Project template — one repo per product, rules baked in¶
Status: proposal — awaiting decision, 2026-09-14 (task 150). Plan started 2026-09-13.
The decision asked of Engineering: adopt the safe-everywhere design-rule set as the KiCad
template default (0.20/0.20 track/space, 0.30 drill, 0.15 annular ring, 0.30 copper-to-edge,
0.15 silk, 0.10 mask dam, 1 oz, no impedance assumed) so any board can go to any of six fabs
unchanged, keep the six existing net classes, and add a second JLCPCB-only .kicad_dru for boards
that need finer geometry. Numbers and sources are in "Fab capabilities" below; two items still need
an engineer's eye (JLCPCB's 0.25 mm figure, and the USB 90 Ω width/gap from JLCPCB's impedance
calculator). Approve, amend the table, or reject on the home page. Angel's ask: a template KiCad repo carrying our rules (net
classes, trace widths, clearances), an SOP for starting a new PCB, and an answer to the
harder question — a product is not just a board. It has an enclosure, firmware, an app,
labels, artwork. How is that captured?
What the Real Cow teaches¶
The Real Cow exists across five repos: Cow_Robot_Board, Cow_Remote, Cow_LCD,
The_Real_Cow_Flasher, The_Real_Cow_Configurator. Each is sensible alone. Together they
have no front door: nothing says what the product is, which board revision ships with which
firmware, or where the enclosure lives. Answering "what did we ship?" means knowing the
history.
What it got right, and the template should keep: Cow_Robot_Board already holds
hardware/, firmware/, FreeCad/ and Solidworks/ side by side. The shop's instinct was
already one-repo-per-thing-you-build. The drift was the remote, the LCD and the two apps
becoming their own islands.
The decision: one repo per product¶
At two people, the coordination cost of five repos beats the coupling cost of one — badly. A product gets one repo, with a fixed shape:
product.yml the manifest — what this is, and where every piece lives
hardware/<board>/ one KiCad project per board, from the template
firmware/<target>/ one per MCU
app/ configurator, mobile, whatever the customer touches
mechanical/ enclosure, CAD source and exported STEP/STL
artwork/ labels, silkscreen art, packaging, the printed insert
test/ fixtures, test plans, and the Universal Tester plan (TOML)
docs/ the datasheet, the manual, compliance evidence
.github/workflows/ the checks
Where a piece genuinely must live elsewhere — a public configurator, a fork of somebody
else's flasher — it stays where it is and product.yml points at it. The manifest is what
makes a product findable even when it is not all in one place. That is the whole trick, and
it is why the manifest matters more than the folder layout.
product.yml¶
The one file that makes a scattered product coherent, and the thing the engineering portal reads (engineering-portal):
product: The Real Cow
ipn: EE-P-0007 # the ERP part number — the ERP owns the number (SOP-001)
status: shipping # concept | prototype | shipping | retired
revision: C # the PRODUCT revision, not the board's
boards:
- name: Robot Cow
path: hardware/robot-cow
revision: 4.0.1
ipn: EE-A-0031
firmware:
- target: STM32G0
path: firmware/robot-cow
builds_for: [Robot Cow 4.0.1]
mechanical: mechanical/enclosure-v3
artwork: artwork/
external:
- what: Configurator (public, browser)
repo: EmbeddedEra/The_Real_Cow_Configurator
compliance: docs/compliance/ # FCC IDs, UN38.3, RoHS — see embeddedera-business
Why a manifest rather than a README: a person reads a README; the portal, the audit and the ERP sync read a manifest. It is checkable — "every board has an IPN", "status shipping implies compliance evidence exists" become audit rules the same way SOP checks are.
The KiCad template, with the rules in it¶
hardware/<board>/ starts as a copy of the template already in the KiCad repo
(template/EmbeddedEra_Project), extended so a new board is correct by default rather
than correct if you remember:
- Net classes — Default, Power, HV, USB (90 Ω differential), RF (50 Ω), and a documented trace width, clearance and via size for each.
- A
.kicad_drucustom rules file for the things net classes cannot say: annular ring minimums, edge clearance, courtyard overlap, silkscreen over pad. - A stackup that matches what we order — JLCPCB 2- and 4-layer are already separate templates; keep that and name the fab in the template's name, because the rules are the fab's, not ours.
- Sheet template and title block already filled with the shop's details.
- The ERC/DRC severities we mean, saved in the project, so the checks in CI and the checks in the editor agree.
Where the numbers come from: whatever JLCPCB's capability page says for the process we actually buy, not folklore. Writing this down is part of the work, and it is the part that needs an engineer rather than me.
SOPs¶
- SOP-021 New PCB Design — start from the template, name and number it (SOP-001), the net classes and when to deviate, when a review happens, what "done" means (ERC and DRC clean, BOM resolves to real IPNs, fab files generated by CI not by hand).
- SOP-022 Product Records — what a product repo must contain,
product.yml, how a revision is cut, and what evidence a shipping product must carry.
Both cross-reference SOP-008 KiCad Library and SOP-001 Part Numbering instead of restating them.
Order¶
- Write the rules down (net classes, widths, clearances) — needs the fab's capabilities.
- Extend the KiCad project template with those rules and the DRU file.
- Create
EmbeddedEra/Project_Templatewith the folder shape,product.yml, and the checks workflow already wired. - SOP-021, then SOP-022. (018 Content Publishing, 019 Cloudflare Changes and 020 Credentials were written on 2026-09-14 — numbers are sequential and never reused.)
- Backfill
product.ymlfor the Real Cow across its five repos — the test of whether the manifest idea actually works is whether it can describe the messy real case. - The portal reads the manifests (engineering-portal).
Related: KiCad, engineering-portal, task-board, universal-tester-product.
Fab capabilities (research, 2026-09-14)¶
Scouted from the fabs' own capability pages by a research agent; every number carries its URL
below. Cells marked unverified were not on an official page. Not yet checked by an engineer —
that check is task 150. Two known weak spots to verify first: the agent labelled JLCPCB's 0.25 mm
figure "annular ring" but it is more likely the minimum via pad diameter (0.15 drill + 0.05 ring
each side), and it did not find JLCPCB's impedance calculator (it exists at
jlcpcb.com/pcb-impedance-calculator; the stackup codes such as JLC04161H-7628 are shown there,
not on the capabilities page).
| Fab | Track/Space 2L | Track/Space 4L | Min drill | Annular ring | Hole-to-Cu | Hole-to-hole | Cu-to-edge | Silk width | Mask dam | Thickness | Copper | ENIG | Impedance |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| JLCPCB | 0.10/0.10 | 0.09/0.09 | 0.15 | 0.25 (see note) | ~0.2 | unverified | ≥0.2 | ≥0.15 | 0.10 | 0.4–2.0 | 1–4.5 oz out, 0.5–2 in | yes | ±10 %, 4+ layers |
| PCBWay | 0.10/0.10 | 0.10/0.10 | 0.15 | 0.15 | ~0.1 | unverified | 0.25 | 0.15 | 0.05 | 0.2–3.2 | 1–8 oz out, 1–4 in | yes | ±10 % |
| NextPCB | 0.08/0.08 | 0.08/0.08 | 0.15 | ≥0.1 | ~0.1 | unverified | ≥0.2 | ≥0.12 | ≥0.04 | 0.6–3.2 | 1–2 oz out, 0.5–2 in | unverified | ±10 % |
| Seeed Fusion | 0.15/0.15 | 0.15/0.15 | 0.3 | unverified | unverified | unverified | unverified | unverified | 0.1 | 0.8–2.0 | 1 oz out | yes (+$10) | unverified |
| Elecrow | 0.20/0.20 | 0.20/0.20 | 0.3 | 0.15 | 0.3 | 0.45 | unverified | 0.15 | unverified | unverified | 1 oz all | unverified | no |
| ALLPCB | 0.10/0.10 | 0.10/0.10 | 0.2 | ≥0.153 | unverified | unverified | ≥0.3 | ≥0.15 | unverified | 0.4–3.2 | 1–2 oz out, 0.5–2 in | yes | yes, details unverified |
| Safe everywhere | 0.20/0.20 | 0.20/0.20 | 0.30 | 0.15 | 0.30 | 0.45 | 0.30 | 0.15 | 0.10 | 0.8–2.0 | 1 oz | yes | do not assume |
All mm. "Safe everywhere" is the tightest rule set that passes every fab listed; it is also, not
by accident, almost exactly what the KiCad template already uses (0.20 track, 0.20 clearance,
0.60/0.30 via, 0.5 edge). The design-rule decision is therefore: ship the safe set as the
template default (a board can go to any of six fabs unchanged) and keep a JLCPCB .kicad_dru
for the boards that need the headroom (USB-C, fine-pitch BGA).
Assembly: JLCPCB in-house library + consigned, 0201 yes, BGA 0.35 mm, 2–3 days; PCBWay 0201 risky, BGA 0.25 mm with X-ray, 8–48 h; NextPCB BGA 0.5 mm; Seeed 0402 minimum, 4–6 days; Elecrow 0201 claimed. Price bands were not found on official pages (unverified).
Sources: JLCPCB https://jlcpcb.com/capabilities/pcb-capabilities and https://jlcpcb.com/capabilities/pcb-assembly-capabilities · PCBWay https://www.pcbway.com/capabilities.html, https://m.pcbway.com/assembly-capabilities.html · NextPCB https://www.nextpcb.com/pcb-capabilities · Seeed https://wiki.seeedstudio.com/Service_for_Fusion_PCB/ · Elecrow https://www.elecrow.com/blog/a-complete-guide-from-kicad-design-to-pcb-prototyping-order.html · ALLPCB https://www.allpcb.com/standard_pcb_manufacturing_capability.html
Rule files to fork (no fab publishes an official .kicad_dru): Cimos/KiCad-CustomDesignRules
(JLCPCB + PCBWay, KiCad 8), labtroll/KiCad-DesignRules (JLCPCB, KiCad 7),
Huaqiu-Electronics/NextPCB-Manufacturing-Rules (NextPCB).
Build plan for task 151 (2026-09-14)¶
What already exists, checked before planning (Hard Rule 1):
- The KiCad template already carries six net classes (
kicad-lib/template/EmbeddedEra_Project: Default 0.20, Signal_Robust 0.25, Power_500mA 0.40, Power_1A 0.60, Power_2A 1.00, USB2 0.20 pair) plus naming conventions, README and AGENTS.md — the Universal Tester 003 repo'sEMBEDDEDERA_TEMPLATE_UPDATE_PLAN.mddid that work and marks it complete. Task 150 is therefore smaller than it reads: not "invent the classes" but "confirm the fab minimums and write them into a.kicad_dru". UT003'sPCB_NET_CONSTRAINTS_PLAN.mdalready used JLCPCB-derived values (0.1375 mm clearance, 0.20 mm min track, 0.60/0.30 via) and is the best starting point. - Universal_Tester_003 is already the target shape (
hardware/kicad,hardware/enclosure,firmware/,host/,docs/, README with a layout table). The template should look like UT003 tidied up, not like something new; Cow_Robot_Board (hardware/<rev>/,firmware/,FreeCad/,Solidworks/) is the second reference. EmbeddedEra-products/templates/product-template+new_product.pyis a different idea (the modular-ECU merge workspace withfusion/modulessubmodules). Leave it alone; it is not a per-product repo template and its copy-and-rename script is replaced by GitHub's own template feature below.- CI:
kicad-lib/.github/workflows/kicad-checks.yml(KiCad 10.0.5 container +kicad-cli, written 2026-09-13, not yet pushed — task 100) is the check to reuse verbatim. Community alternatives were checked: KiBot (739★, community default, but KiCad 10 support limited as of v1.9.1) and actions-for-kicad/kicad-actions (25★, KiCad 10 ok). Neither is needed:kicad-clialready exports gerbers, drill, BOM and position files, so fab outputs are a second job in the same workflow, no extra tool. Revisit KiBot only if we want the PDF/3D render set. - Manifest: Open Know-How (OKH v1, iop-alliance, active) is the published standard for
describing open hardware, but it models one design, not "board X rev 4.0.1 ships with firmware Y".
Decision: keep
product.yml, but use OKH's field names wherever they overlap (title,version,license,repo,documentation-home,bom) so an OKH export is a mapping, not a rewrite. CycloneDX HBOM is for supply-chain SBOMs, not this. - Design-rule files: labtroll/KiCad-DesignRules (362★, JLCPCB, KiCad 7 syntax) and
tinfever/KiCAD-Custom-DRC-Rules-for-JLCPCB-with-Unit-Tests (4-layer, with test boards) are the
references to fork;
.kicad_druis native in KiCad 10 with a graphical editor, so the file ports.
Steps¶
- Task 150 — design rules (engineer, ~1 h, blocks the rest). Open JLCPCB's capability page
for the 2-layer 1 oz and 4-layer processes we buy and fill one table: min track/space, min
annular ring, min drill, min hole-to-copper, edge clearance, silkscreen minimums, USB 90 Ω
width/gap for each stackup (JLC's impedance calculator, JLC04161H-7628 for 4-layer). Decide
whether the six existing classes stay. Output: the table in this note. Claude then writes
EmbeddedEra_JLCPCB_2L.kicad_druand_4L.kicad_drufrom labtroll/tinfever as the base, sets the board minimums in the two template.kicad_profiles, and runskicad-checkon the template to prove it is DRC-clean out of the box. - Create
EmbeddedEra/Project_Template(Claude, no engineer needed). Private repo, marked a GitHub template repository (gh repo edit --template), so a product starts withgh repo create EmbeddedEra/<Product> --template EmbeddedEra/Project_Template --privateand the copy-rename script goes away. Contents: product.ymlwith every field present and a# required/# optionalcomment, plusdocs/product-yml.mddocumenting each field.hardware/board-1/= a copy of the KiCad template (post step 1);firmware/,app/,mechanical/,artwork/,test/,docs/each with a one-paragraph README saying what goes there and what must not (no generated fab files, no backups, no.DS_Store)..gitignoreand.gitattributesmerged from UT003 and kicad-lib (KiCad backups,-cache,fp-info-cache,*.bak, STEP exports as LFS)..github/workflows/kicad-checks.ymlcopied from kicad-lib, with the library tables step changed to cloneEmbeddedEra/KiCadat a pinned tag (a product repo has no libraries of its own); a second jobfab-outputsthat on a taghw/<board>/<rev>runskicad-cli pcb export gerbers|drill|posandsch export bom, zips them, attaches them to the GitHub release..github/workflows/manifest-check.yml: a 40-line Python check thatproduct.ymlparses, everyboards[].pathexists and contains a.kicad_pro, every board has anipn, andstatus: shippingimpliesdocs/compliance/is non-empty. This is what makes the manifest auditable (SOP-022 later cites this check).AGENTS.mdfrom the KiCad template, extended with the repo shape.- README with the layout table (UT003 style) and the "start a product" steps.
- Prove it on a fresh clone: create a throwaway repo from the template, push, watch both workflows go green, delete the throwaway. Then push task 100's workflow to kicad-lib the same day so the two repos run the same checks.
- SOP-021 New PCB Design, SOP-022 Product Records (task 152) — written against the real
template, not before it. SOP-021 is mostly "use the template; deviate from a net class only
with a comment in the schematic"; SOP-022 is the
product.ymlcontract and the revision cut (taghw/<board>/<rev>= fab outputs frozen). - Real Cow backfill (task 153): one
product.ymlinCow_Robot_Boardpointing at the other four repos throughexternal:. If the manifest cannot describe it, the schema is wrong and gets fixed before SOP-022 is published. Second test: Universal_Tester_003, which should need only the manifest and a workflow. - Add a
tilefor the engineering portal reading manifests later (engineering-portal).
What needs Angel¶
- Step 1 only: the fab numbers and a yes/no on the six classes. Everything after is Claude's, each step verified on a real clone before being called done.
Log¶
- 2026-09-13: written, after looking at how the Real Cow is spread across five repos.
- 2026-09-14: build plan for task 151 written after checking existing work (KiCad template already has the net classes; UT003 is the reference shape; GitHub template repos replace the copy script; OKH field names, not OKH itself; kicad-cli, not KiBot, for CI).
- 2026-09-14: fab capability table added from a research pass over six Asian fabs; the safe-everywhere set matches the template's current numbers. Engineer check pending (task 150).