From 8ae0eb239a3837579564afd23bd85795a153885d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Saillant?= Date: Tue, 7 Apr 2026 15:39:30 +0200 Subject: [PATCH] feat: public example of life-project gates system Public demo of Factory 4 Life project management: - Gate definitions S0 (spec), S1 (build), S2 (integration), S3 (production ready) - Hardware project template with PlatformIO, KiCad CI, and Makefile for fab packages - JSON schema for .kill-life.yaml manifest - CLI scripts: create-project, validate-gates, dashboard with color-coded status output - Example project: led-controller (S0+S1 passed, S2 in progress) --- .gitignore | 5 + README.md | 67 ++++++++ gates/s0_spec_ready.md | 43 +++++ gates/s1_build_ok.md | 49 ++++++ gates/s2_integration.md | 45 ++++++ gates/s3_production_ready.md | 54 +++++++ projects/example-led-controller.yaml | 16 ++ schemas/kill-life.schema.json | 81 ++++++++++ scripts/create-project.sh | 95 +++++++++++ scripts/dashboard.sh | 51 ++++++ scripts/validate-gates.sh | 147 ++++++++++++++++++ .../.github/workflows/kill-life-ci.yml | 58 +++++++ templates/hardware-project/.kill-life.yaml | 21 +++ templates/hardware-project/Makefile | 32 ++++ templates/hardware-project/README.md | 38 +++++ .../hardware-project/docs/specs/.gitkeep | 0 .../hardware-project/firmware/platformio.ini | 8 + .../hardware-project/firmware/src/main.cpp | 10 ++ 18 files changed, 820 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 gates/s0_spec_ready.md create mode 100644 gates/s1_build_ok.md create mode 100644 gates/s2_integration.md create mode 100644 gates/s3_production_ready.md create mode 100644 projects/example-led-controller.yaml create mode 100644 schemas/kill-life.schema.json create mode 100755 scripts/create-project.sh create mode 100755 scripts/dashboard.sh create mode 100755 scripts/validate-gates.sh create mode 100644 templates/hardware-project/.github/workflows/kill-life-ci.yml create mode 100644 templates/hardware-project/.kill-life.yaml create mode 100644 templates/hardware-project/Makefile create mode 100644 templates/hardware-project/README.md create mode 100644 templates/hardware-project/docs/specs/.gitkeep create mode 100644 templates/hardware-project/firmware/platformio.ini create mode 100644 templates/hardware-project/firmware/src/main.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..df0be26 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.DS_Store +*.swp +*.swo +tmp/ +.omc/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..25ea1ec --- /dev/null +++ b/README.md @@ -0,0 +1,67 @@ +# life-project-example + +Example repo for Factory 4 Life project management: gates S0-S3, templates, cross-repo orchestration. + +> This is a **public demo** of the project management system. See the gate definitions, templates, and scripts below. + +## Concept + +Chaque projet hardware/firmware/software suit un pipeline de **gates** (S0 -> S3) inspiré du stage-gate process. Ce repo centralise : + +- **Gates** : definitions, criteres, checklists (`gates/`) +- **Schemas** : validation YAML des manifests `.kill-life.yaml` (`schemas/`) +- **Templates** : squelettes de repos prets a l'emploi (`templates/`) +- **Scripts** : outils CLI pour creer, valider et suivre les projets (`scripts/`) +- **Projects** : registre des projets actifs (`projects/`) + +## Pipeline de gates + +| Gate | Nom | Objectif | +|------|-----|----------| +| **S0** | Spec Ready | Specs testables, architecture definie, plan de validation | +| **S1** | Build OK | Firmware compile, ERC/DRC green, tests unitaires passent | +| **S2** | Integration | Tests integration, BOM valide, prototype fonctionnel | +| **S3** | Production Ready | Fab package complet, compliance, documentation livree | + +## Structure d'un projet + +Chaque repo projet contient un `.kill-life.yaml` a la racine : + +```yaml +kill_life: + version: 1 + project: "mon-projet" + client: "client-name" + gates: + s0: { status: passed, date: "2026-03-15" } + s1: { status: in_progress } + s2: { status: pending } + s3: { status: pending } + hardware: + pcb_dir: hardware/pcb + bom_dir: hardware/bom + firmware: + framework: platformio + src_dir: firmware/src +``` + +## Utilisation + +```bash +# Creer un nouveau projet depuis le template +./scripts/create-project.sh mon-projet electron-rare + +# Valider les gates d'un projet +./scripts/validate-gates.sh electron-rare/mon-projet + +# Dashboard de tous les projets +./scripts/dashboard.sh +``` + +## Repos exemple + +- [electron-rare/hypnoled](https://github.com/electron-rare/hypnoled) — HypnoLED animations LED ESP32 + +## License + +MIT diff --git a/gates/s0_spec_ready.md b/gates/s0_spec_ready.md new file mode 100644 index 0000000..535c405 --- /dev/null +++ b/gates/s0_spec_ready.md @@ -0,0 +1,43 @@ +# Gate S0 — Spec Ready + +## Objectif + +Valider que les specifications sont completes, testables, et que l'architecture est definie. + +## Criteres obligatoires + +- [ ] `docs/specs/01_spec.md` existe avec des criteres d'acceptation testables +- [ ] `docs/specs/02_arch.md` definit les interfaces et contrats +- [ ] `docs/specs/03_plan.md` liste les commandes de validation et l'evidence attendue +- [ ] `constraints.yaml` present et valide (si applicable) +- [ ] `.kill-life.yaml` present a la racine avec `version: 1` + +## Criteres optionnels + +- [ ] Diagramme d'architecture (Excalidraw, Draw.io, ou Mermaid) +- [ ] Estimation de BOM preliminaire +- [ ] Identification des risques techniques + +## Artifacts produits + +| Artifact | Chemin | Format | +|----------|--------|--------| +| Spec | `docs/specs/01_spec.md` | Markdown | +| Architecture | `docs/specs/02_arch.md` | Markdown | +| Plan de validation | `docs/specs/03_plan.md` | Markdown | +| Contraintes | `constraints.yaml` | YAML | + +## Validation automatique + +```bash +# Verifie la presence des fichiers requis +./scripts/validate-gates.sh / --gate s0 +``` + +## Passage de gate + +Le passage de S0 est formalise par : +1. Une PR avec label `gate:s0` +2. Review par au moins 1 personne +3. Tous les checks CI passent +4. Mise a jour du `.kill-life.yaml` : `s0.status: passed` diff --git a/gates/s1_build_ok.md b/gates/s1_build_ok.md new file mode 100644 index 0000000..e3bcb31 --- /dev/null +++ b/gates/s1_build_ok.md @@ -0,0 +1,49 @@ +# Gate S1 — Build OK + +## Objectif + +Valider que le projet compile, que les checks hardware passent, et que les tests unitaires sont en place. + +## Criteres par type + +### Firmware (si `firmware/` existe) + +- [ ] `pio run` compile sans erreur (au moins 1 environment) +- [ ] `pio test -e native` passe (ou justification documentee) +- [ ] Pas de warnings critiques (-Werror ou equivalent) + +### Hardware (si `hardware/` existe) + +- [ ] ERC (Electrical Rules Check) green — artifact JSON +- [ ] DRC (Design Rules Check) green — artifact JSON +- [ ] Netlist exportable +- [ ] BOM genere (`hardware/bom/`) + +### Software (si pas firmware/hardware) + +- [ ] Build reussi (`npm run build` / `cargo build` / etc.) +- [ ] Tests unitaires passent +- [ ] Linter/formatter OK + +## Criteres communs + +- [ ] CI GitHub Actions configure et green +- [ ] README.md a jour avec instructions de build +- [ ] Gate S0 passee + +## Validation automatique + +```bash +./scripts/validate-gates.sh / --gate s1 +``` + +Le workflow `.github/workflows/kill-life-ci.yml` execute automatiquement : +- ERC/DRC via `kicad-cli` (container `ghcr.io/inti-cmnb/kicad8_auto`) +- Build firmware via PlatformIO +- Validation BOM + +## Passage de gate + +1. CI green sur `main` +2. PR avec label `gate:s1` +3. Mise a jour `.kill-life.yaml` : `s1.status: passed` diff --git a/gates/s2_integration.md b/gates/s2_integration.md new file mode 100644 index 0000000..34c1462 --- /dev/null +++ b/gates/s2_integration.md @@ -0,0 +1,45 @@ +# Gate S2 — Integration + +## Objectif + +Valider que les composants (firmware + hardware + software) fonctionnent ensemble sur un prototype. + +## Criteres obligatoires + +- [ ] Gate S1 passee +- [ ] Prototype physique assemble et fonctionnel +- [ ] Tests d'integration documentes et passes +- [ ] Communication inter-composants validee (I2C, SPI, UART, WiFi...) +- [ ] Consommation electrique mesuree et dans les specs + +### Hardware + +- [ ] PCB fabrique et assemble (au moins 1 exemplaire) +- [ ] Tous les composants soudes et testes +- [ ] Photos/videos du prototype dans `docs/prototype/` + +### Firmware + +- [ ] Flash reussi sur le hardware reel +- [ ] Tests fonctionnels sur cible (pas seulement native) +- [ ] OTA fonctionnel (si applicable) + +### Software + +- [ ] Integration API/backend testee end-to-end +- [ ] Deployment staging fonctionnel + +## Artifacts produits + +| Artifact | Chemin | Format | +|----------|--------|--------| +| Rapport d'integration | `docs/integration_report.md` | Markdown | +| Photos prototype | `docs/prototype/` | Images | +| Mesures electriques | `docs/measurements/` | CSV/Markdown | +| Test results | `tests/integration/` | Code + logs | + +## Passage de gate + +1. PR avec label `gate:s2` +2. Review incluant validation physique (photos/videos) +3. Mise a jour `.kill-life.yaml` : `s2.status: passed` diff --git a/gates/s3_production_ready.md b/gates/s3_production_ready.md new file mode 100644 index 0000000..5bb64a0 --- /dev/null +++ b/gates/s3_production_ready.md @@ -0,0 +1,54 @@ +# Gate S3 — Production Ready + +## Objectif + +Valider que le projet est pret pour la fabrication en serie / le deploiement en production. + +## Criteres obligatoires + +- [ ] Gate S2 passee +- [ ] Fab package complet et valide + +### Fab Package (hardware) + +- [ ] Gerbers exportes et verifies +- [ ] Drill files generes +- [ ] BOM finale avec references fournisseurs et prix +- [ ] Pick & place file (si SMD) +- [ ] `acceptance_gates` dans `.kill-life.yaml` : `erc_ok`, `drc_ok`, `bom_review_ok`, `artifacts_complete` + +### Firmware release + +- [ ] Version taguee (semver) +- [ ] Binary release sur GitHub Releases +- [ ] Changelog a jour +- [ ] OTA path teste depuis version N-1 (si applicable) + +### Documentation + +- [ ] Guide utilisateur (`docs/user_guide.md`) +- [ ] Procedure de fabrication (`docs/manufacturing.md`) +- [ ] Nomenclature complete et a jour +- [ ] Licences verifiees (SPDX) + +### Compliance + +- [ ] Conformite CE / FCC documentee (si applicable) +- [ ] Tests EMC references (si applicable) +- [ ] WEEE / RoHS compliance (si applicable) + +## Artifacts produits + +| Artifact | Chemin | Format | +|----------|--------|--------| +| Fab package | `releases//` | Gerbers, drill, BOM, netlist | +| Firmware binary | GitHub Release | `.bin` / `.uf2` | +| User guide | `docs/user_guide.md` | Markdown | +| Manufacturing guide | `docs/manufacturing.md` | Markdown | + +## Passage de gate + +1. PR avec label `gate:s3` +2. Review par au moins 2 personnes +3. Tag de release cree +4. Mise a jour `.kill-life.yaml` : `s3.status: passed` diff --git a/projects/example-led-controller.yaml b/projects/example-led-controller.yaml new file mode 100644 index 0000000..3896901 --- /dev/null +++ b/projects/example-led-controller.yaml @@ -0,0 +1,16 @@ +kill_life: + version: 1 + project: "example-led-controller" + repo: "electron-rare/life-project-example" + client: "demo" + gates: + s0: { status: passed, date: "2026-03-01" } + s1: { status: passed, date: "2026-03-15" } + s2: { status: in_progress } + s3: { status: pending } + hardware: + pcb_dir: hardware/pcb + bom_dir: hardware/bom + firmware: + framework: platformio + src_dir: firmware/src diff --git a/schemas/kill-life.schema.json b/schemas/kill-life.schema.json new file mode 100644 index 0000000..c34766e --- /dev/null +++ b/schemas/kill-life.schema.json @@ -0,0 +1,81 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "kill-life.yaml", + "description": "Manifest de projet Factory 4 Life", + "type": "object", + "required": ["kill_life"], + "properties": { + "kill_life": { + "type": "object", + "required": ["version", "project"], + "properties": { + "version": { "type": "integer", "const": 1 }, + "project": { "type": "string", "minLength": 1 }, + "client": { "type": "string" }, + "mascarade_url": { "type": "string", "format": "uri" }, + "agents": { + "type": "array", + "items": { "type": "string" } + }, + "mcp_servers": { + "type": "array", + "items": { "type": "string" } + }, + "gates": { + "type": "object", + "properties": { + "s0": { "$ref": "#/$defs/gate_status" }, + "s1": { "$ref": "#/$defs/gate_status" }, + "s2": { "$ref": "#/$defs/gate_status" }, + "s3": { "$ref": "#/$defs/gate_status" } + } + }, + "acceptance_gates": { + "type": "object", + "properties": { + "erc_ok": { "type": "boolean" }, + "drc_ok": { "type": "boolean" }, + "bom_review_ok": { "type": "boolean" }, + "artifacts_complete": { "type": "boolean" } + } + }, + "hardware": { + "type": "object", + "properties": { + "pcb_dir": { "type": "string" }, + "simulation_dir": { "type": "string" }, + "bom_dir": { "type": "string" } + } + }, + "firmware": { + "type": "object", + "properties": { + "framework": { "type": "string", "enum": ["platformio", "esp-idf", "arduino", "zephyr"] }, + "src_dir": { "type": "string" } + } + }, + "software": { + "type": "object", + "properties": { + "framework": { "type": "string" }, + "src_dir": { "type": "string" } + } + } + } + } + }, + "$defs": { + "gate_status": { + "type": "object", + "required": ["status"], + "properties": { + "status": { + "type": "string", + "enum": ["pending", "in_progress", "passed", "blocked", "skipped"] + }, + "date": { "type": "string", "format": "date" }, + "notes": { "type": "string" } + } + } + } +} diff --git a/scripts/create-project.sh b/scripts/create-project.sh new file mode 100755 index 0000000..5c85ef0 --- /dev/null +++ b/scripts/create-project.sh @@ -0,0 +1,95 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Create a new Factory 4 Life project from template +# Usage: ./scripts/create-project.sh [--client ] + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(dirname "$SCRIPT_DIR")" +TEMPLATE_DIR="${REPO_ROOT}/templates/hardware-project" + +usage() { + cat <<'EOF' +Usage: create-project.sh [options] + +Options: + --client Client name for the project + --public Create as public repo (default: private) + --no-clone Don't clone locally after creation + -h, --help Show this help + +Example: + ./scripts/create-project.sh my-led-project electron-rare --client acme +EOF +} + +PROJECT="" +ORG="" +CLIENT="" +VISIBILITY="--private" +CLONE=true + +while [[ $# -gt 0 ]]; do + case "$1" in + --client) CLIENT="$2"; shift 2 ;; + --public) VISIBILITY="--public"; shift ;; + --no-clone) CLONE=false; shift ;; + -h|--help) usage; exit 0 ;; + *) + if [[ -z "$PROJECT" ]]; then PROJECT="$1" + elif [[ -z "$ORG" ]]; then ORG="$1" + else usage >&2; exit 2 + fi + shift ;; + esac +done + +[[ -n "$PROJECT" ]] || { echo "Error: project name required" >&2; usage >&2; exit 1; } +[[ -n "$ORG" ]] || { echo "Error: github org required" >&2; usage >&2; exit 1; } + +echo "Creating project: ${ORG}/${PROJECT}" + +# Create GitHub repo +gh repo create "${ORG}/${PROJECT}" ${VISIBILITY} \ + --description "Factory 4 Life project — ${PROJECT}" \ + --clone + +cd "${PROJECT}" + +# Copy template +cp -r "${TEMPLATE_DIR}/"* . +cp -r "${TEMPLATE_DIR}/".[!.]* . 2>/dev/null || true + +# Generate .kill-life.yaml +cat > .kill-life.yaml < [--gate s0|s1|s2|s3] [--local ] + +usage() { + cat <<'EOF' +Usage: validate-gates.sh [options] + +Options: + --gate Validate specific gate (default: all) + --local Use local directory instead of cloning + --json Output as JSON + -h, --help Show this help + +Example: + ./scripts/validate-gates.sh electron-rare/hypnoled --gate s1 + ./scripts/validate-gates.sh electron-rare/hypnoled --local ~/hypnoled +EOF +} + +REPO="" +GATE="" +LOCAL_PATH="" +JSON_OUTPUT=false + +while [[ $# -gt 0 ]]; do + case "$1" in + --gate) GATE="$2"; shift 2 ;; + --local) LOCAL_PATH="$2"; shift 2 ;; + --json) JSON_OUTPUT=true; shift ;; + -h|--help) usage; exit 0 ;; + *) REPO="$1"; shift ;; + esac +done + +[[ -n "$REPO" ]] || { echo "Error: repo required" >&2; usage >&2; exit 1; } + +# Get project directory +if [[ -n "$LOCAL_PATH" ]]; then + PROJECT_DIR="$LOCAL_PATH" +else + TMPDIR=$(mktemp -d) + trap "rm -rf $TMPDIR" EXIT + gh repo clone "$REPO" "$TMPDIR/repo" -- --depth 1 2>/dev/null + PROJECT_DIR="$TMPDIR/repo" +fi + +PASS=0 +FAIL=0 +WARN=0 + +check() { + local gate="$1" desc="$2" result="$3" + if [[ "$result" == "pass" ]]; then + echo " [PASS] $desc" + ((PASS++)) + elif [[ "$result" == "warn" ]]; then + echo " [WARN] $desc" + ((WARN++)) + else + echo " [FAIL] $desc" + ((FAIL++)) + fi +} + +validate_s0() { + echo "=== Gate S0: Spec Ready ===" + check s0 ".kill-life.yaml exists" \ + "$([[ -f "$PROJECT_DIR/.kill-life.yaml" ]] && echo pass || echo fail)" + check s0 "docs/specs/01_spec.md exists" \ + "$([[ -f "$PROJECT_DIR/docs/specs/01_spec.md" ]] && echo pass || echo fail)" + check s0 "docs/specs/02_arch.md exists" \ + "$([[ -f "$PROJECT_DIR/docs/specs/02_arch.md" ]] && echo pass || echo fail)" + check s0 "docs/specs/03_plan.md exists" \ + "$([[ -f "$PROJECT_DIR/docs/specs/03_plan.md" ]] && echo pass || echo fail)" + check s0 "README.md exists" \ + "$([[ -f "$PROJECT_DIR/README.md" ]] && echo pass || echo fail)" +} + +validate_s1() { + echo "=== Gate S1: Build OK ===" + + # Firmware checks + if [[ -f "$PROJECT_DIR/firmware/platformio.ini" ]]; then + check s1 "platformio.ini exists" pass + check s1 "firmware/src/ has source files" \ + "$(find "$PROJECT_DIR/firmware/src" -name '*.cpp' -o -name '*.c' -o -name '*.h' 2>/dev/null | head -1 | grep -q . && echo pass || echo fail)" + fi + + # Hardware checks + if [[ -d "$PROJECT_DIR/hardware/pcb" ]]; then + check s1 "KiCad schematic exists" \ + "$(find "$PROJECT_DIR/hardware/pcb" -name '*.kicad_sch' 2>/dev/null | head -1 | grep -q . && echo pass || echo fail)" + check s1 "KiCad PCB exists" \ + "$(find "$PROJECT_DIR/hardware/pcb" -name '*.kicad_pcb' 2>/dev/null | head -1 | grep -q . && echo pass || echo fail)" + check s1 "BOM exists" \ + "$([[ -d "$PROJECT_DIR/hardware/bom" ]] && find "$PROJECT_DIR/hardware/bom" -name '*.csv' 2>/dev/null | head -1 | grep -q . && echo pass || echo warn)" + fi + + # CI check + check s1 "GitHub Actions CI configured" \ + "$(find "$PROJECT_DIR/.github/workflows" -name '*.yml' -o -name '*.yaml' 2>/dev/null | head -1 | grep -q . && echo pass || echo fail)" +} + +validate_s2() { + echo "=== Gate S2: Integration ===" + check s2 "Integration report exists" \ + "$([[ -f "$PROJECT_DIR/docs/integration_report.md" ]] && echo pass || echo fail)" + check s2 "Prototype documentation exists" \ + "$([[ -d "$PROJECT_DIR/docs/prototype" ]] && echo pass || echo warn)" + check s2 "Integration tests exist" \ + "$(find "$PROJECT_DIR/tests/integration" -type f 2>/dev/null | head -1 | grep -q . && echo pass || echo warn)" +} + +validate_s3() { + echo "=== Gate S3: Production Ready ===" + check s3 "User guide exists" \ + "$([[ -f "$PROJECT_DIR/docs/user_guide.md" ]] && echo pass || echo fail)" + check s3 "Manufacturing guide exists" \ + "$([[ -f "$PROJECT_DIR/docs/manufacturing.md" ]] && echo pass || echo warn)" + check s3 "Release directory exists" \ + "$([[ -d "$PROJECT_DIR/releases" ]] && echo pass || echo fail)" + + if [[ -d "$PROJECT_DIR/hardware/pcb" ]]; then + check s3 "Gerbers generated" \ + "$(find "$PROJECT_DIR/releases" -name '*.gbr' -o -name '*.gtl' 2>/dev/null | head -1 | grep -q . && echo pass || echo fail)" + fi +} + +# Run validations +echo "Validating: $REPO" +echo "" + +case "$GATE" in + s0) validate_s0 ;; + s1) validate_s0; validate_s1 ;; + s2) validate_s0; validate_s1; validate_s2 ;; + s3) validate_s0; validate_s1; validate_s2; validate_s3 ;; + "") validate_s0; validate_s1; validate_s2; validate_s3 ;; + *) echo "Unknown gate: $GATE" >&2; exit 1 ;; +esac + +echo "" +echo "Results: ${PASS} passed, ${FAIL} failed, ${WARN} warnings" +[[ "$FAIL" -eq 0 ]] && exit 0 || exit 1 diff --git a/templates/hardware-project/.github/workflows/kill-life-ci.yml b/templates/hardware-project/.github/workflows/kill-life-ci.yml new file mode 100644 index 0000000..fcfb787 --- /dev/null +++ b/templates/hardware-project/.github/workflows/kill-life-ci.yml @@ -0,0 +1,58 @@ +name: Kill_LIFE CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + erc-drc: + name: KiCad ERC/DRC + runs-on: ubuntu-latest + if: hashFiles('hardware/pcb/*.kicad_sch') != '' + container: + image: ghcr.io/inti-cmnb/kicad8_auto:latest + steps: + - uses: actions/checkout@v4 + + - name: Run ERC + run: | + for sch in $(find hardware/pcb -name '*.kicad_sch' -not -path '*/libs/*'); do + echo "--- ERC: $sch ---" + kicad-cli sch erc --exit-code-violations "$sch" || exit 1 + done + + - name: Run DRC + run: | + for pcb in $(find hardware/pcb -name '*.kicad_pcb'); do + echo "--- DRC: $pcb ---" + kicad-cli pcb drc --exit-code-violations "$pcb" || exit 1 + done + + bom-check: + name: BOM Validation + runs-on: ubuntu-latest + if: hashFiles('hardware/bom/*.csv') != '' + steps: + - uses: actions/checkout@v4 + - name: Validate BOM + run: | + if [ -f hardware/bom/bom.csv ]; then + echo "BOM found: $(wc -l < hardware/bom/bom.csv) lines" + else + echo "WARNING: No BOM at hardware/bom/bom.csv" + fi + + firmware-build: + name: Firmware Build + runs-on: ubuntu-latest + if: hashFiles('firmware/platformio.ini') != '' + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + - run: pip install platformio + - name: Build firmware + run: cd firmware && pio run diff --git a/templates/hardware-project/.kill-life.yaml b/templates/hardware-project/.kill-life.yaml new file mode 100644 index 0000000..670150e --- /dev/null +++ b/templates/hardware-project/.kill-life.yaml @@ -0,0 +1,21 @@ +kill_life: + version: 1 + project: "TEMPLATE" + client: "tbd" + gates: + s0: { status: in_progress } + s1: { status: pending } + s2: { status: pending } + s3: { status: pending } + agents: + - forge + - firmware-agent + - qa-agent + mcp_servers: + - kicad + hardware: + pcb_dir: hardware/pcb + bom_dir: hardware/bom + firmware: + framework: platformio + src_dir: firmware/src diff --git a/templates/hardware-project/Makefile b/templates/hardware-project/Makefile new file mode 100644 index 0000000..04fde3e --- /dev/null +++ b/templates/hardware-project/Makefile @@ -0,0 +1,32 @@ +PROJECT_DIR := hardware/pcb +TS ?= $(shell date +%Y%m%d-%H%M%S) +REL := releases/$(TS) + +.PHONY: kicad-check kicad-fab firmware-build + +kicad-check: + @command -v kicad-cli >/dev/null || (echo "kicad-cli manquant" && exit 1) + @for sch in $$(find $(PROJECT_DIR) -name '*.kicad_sch' -not -path '*/libs/*'); do \ + echo "--- ERC: $$sch ---"; \ + kicad-cli sch erc "$$sch"; \ + done + @for pcb in $$(find $(PROJECT_DIR) -name '*.kicad_pcb'); do \ + echo "--- DRC: $$pcb ---"; \ + kicad-cli pcb drc "$$pcb"; \ + done + +kicad-fab: + @command -v kicad-cli >/dev/null || (echo "kicad-cli manquant" && exit 1) + mkdir -p "$(REL)/gerbers" "$(REL)/drill" "$(REL)/bom" "$(REL)/netlist" + @for pcb in $$(find $(PROJECT_DIR) -name '*.kicad_pcb'); do \ + kicad-cli pcb export gerbers "$$pcb" --output "$(REL)/gerbers"; \ + kicad-cli pcb export drill "$$pcb" --output "$(REL)/drill"; \ + done + @for sch in $$(find $(PROJECT_DIR) -name '*.kicad_sch' -maxdepth 1); do \ + kicad-cli sch export bom "$$sch" --output "$(REL)/bom/bom.csv"; \ + kicad-cli sch export netlist "$$sch" --output "$(REL)/netlist/project.net"; \ + done + @echo "Artefacts dans $(REL)" + +firmware-build: + cd firmware && pio run diff --git a/templates/hardware-project/README.md b/templates/hardware-project/README.md new file mode 100644 index 0000000..2fbc656 --- /dev/null +++ b/templates/hardware-project/README.md @@ -0,0 +1,38 @@ +# PROJECT_NAME + +> Factory 4 Life project — description here + +## Structure + +``` +.kill-life.yaml # Project manifest & gate status +firmware/ # ESP32 firmware (PlatformIO) +hardware/ + pcb/ # KiCad schematics & PCB + bom/ # Bill of Materials +docs/ + specs/ # Specifications (S0 gate) +releases/ # Fab packages & binaries +``` + +## Gates + +| Gate | Status | +|------|--------| +| S0 — Spec Ready | in_progress | +| S1 — Build OK | pending | +| S2 — Integration | pending | +| S3 — Production Ready | pending | + +## Build + +```bash +# Firmware +cd firmware && pio run + +# Hardware checks +make kicad-check + +# Fab package +make kicad-fab +``` diff --git a/templates/hardware-project/docs/specs/.gitkeep b/templates/hardware-project/docs/specs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/templates/hardware-project/firmware/platformio.ini b/templates/hardware-project/firmware/platformio.ini new file mode 100644 index 0000000..b5ae12b --- /dev/null +++ b/templates/hardware-project/firmware/platformio.ini @@ -0,0 +1,8 @@ +[env:esp32] +platform = espressif32 +board = esp32dev +framework = arduino +monitor_speed = 115200 + +[env:native] +platform = native diff --git a/templates/hardware-project/firmware/src/main.cpp b/templates/hardware-project/firmware/src/main.cpp new file mode 100644 index 0000000..3ea92c9 --- /dev/null +++ b/templates/hardware-project/firmware/src/main.cpp @@ -0,0 +1,10 @@ +#include + +void setup() { + Serial.begin(115200); + Serial.println("Factory 4 Life — Project init"); +} + +void loop() { + // TODO: implement +}