Problem
RFC-013 (layout constraints) and the existing KiCad .net/BOM emitters give CoHDL a real, working schematic-to-netlist pipeline, but the actual handoff target for a production layout partner is narrower than what CoHDL emits today. The existing "Quilter as a CoHDL Backend Partner — Fit Analysis" note (Business workspace) did the real investigation and reached a load-bearing conclusion: a bare KiCad .net is a fine quick prototype, but Quilter's two hardest-to-reach targets (Cadence Allegro, Siemens Xpedition) are only reachable via IPC-2581, and IPC-2581 is the architecturally better long-term contract regardless — it's a single, vendor-neutral, open-standard file carrying netlist + board outline + footprints + stackup + constraints in one place, decoupling CoHDL from any single router.
Who this is for: the layout-partner integration itself (Quilter, or any other IPC-2581-capable router/tool) — this is the concrete partner-facing work RFC-013's own Decision Record flagged as needed once "a real partner layout-tool integration is scoped." Secondarily, any future backend partner beyond Quilter specifically, since IPC-2581 is vendor-neutral by design — this RFC is not a Quilter-specific integration, it's a standards-based emitter that happens to unblock a Quilter conversation.
Goals
- Emit a partially-specified IPC-2581 document — logical design complete (netlist, specs, designators), physical layout empty (no placement/routing) — the "sweet spot" the fit-analysis note identified as the viable handoff: enough for a router to place and route, nothing CoHDL can't yet honestly provide.
- Carry RFC-013's layout constraints (net classes, differential pairs, length-matching, placement hints) inline in the same file, closing the "separate constraint channel" gap the fit-analysis note named as one of IPC-2581's real advantages over a bare netlist.
- Be honest, in the RFC itself and in the emitted document, about what CoHDL cannot yet provide (footprint geometry, board outline, stackup) rather than emitting a document that claims completeness it doesn't have.
Non-goals
- Not a footprint-geometry system. CoHDL's
partdeclarations reference a footprint by name (e.g."Capacitor_SMD:C_0402_1005Metric", a KiCad library reference) — they do not, and this RFC does not make them, own pad geometry, silkscreen, or 3D models. This RFC's IPC-2581 output references footprints by the same name string CoHDL already has; resolving that name to real geometry is either the receiving tool's job (if it has the same library) or a separate, future RFC (a footprint-resolution/library system) — explicitly out of scope here. - Not a board-outline/stackup language feature. CoHDL has no concept of board shape, layer count, or copper stackup today, and this RFC does not add one. The emitted IPC-2581 document's physical section is honestly empty/minimal (a default rectangular outline placeholder, clearly marked, or omitted where the schema allows) — a real board outline is future work, not silently fabricated.
- Not solving the ECO/re-routing problem the fit-analysis note flagged (Quilter re-routes from scratch on every netlist change, no incremental update) — that's an integration/workflow question for whoever operates the CoHDL↔Quilter loop, not something an emitter format can fix. This RFC's Failure modes section states the limitation plainly rather than pretending the emitter solves it.
- Not replacing the existing KiCad
.net/BOM/layout.jsonemitters. IPC-2581 is a fourth output alongside them, not a replacement — a design still emits.net+ BOM CSV +layout.json(when applicable) exactly as today;cohdl build --emit ipc2581(or similar) is additive.
Design
A new codegen backend, following the existing emit/ module pattern
src/emit/
kicad.rs (existing — .net)
bom.rs (existing — BOM CSV)
layout.rs (existing — layout.json)
json.rs (existing — --json diagnostics)
ipc2581.rs (NEW — this RFC)
cohdl build --emit ipc2581 (or an always-on additional artifact, decided during implementation review) emits <package-name>.xml conforming to the IPC-2581B1.xsd schema (the same schema KiCad's own C++ IPC-2581 I/O targets — the fit-analysis note's cited reference), built from the exact same DesignIr the KiCad/BOM/layout emitters already consume. No new type-checking, no new IR — purely a new projection of data that already exists post-pipeline::check().
What the document carries, mapped from existing CoHDL data:
- Logical netlist — every
netand its member pins, from the same connectivity datakicad.rsalready emits. - Components — every instance, its resolved designator (RFC-005), its bound
part's MPN/manufacturer (RFC-003's structurally-guaranteed-complete MPN), and its footprint name (referenced, not resolved to geometry — see Non-goals). - Specs — every instance's resolved unit-typed spec values (RFC-001), carried as IPC-2581's own component-attribute mechanism, giving a receiving tool machine-readable access to e.g. "this capacitor is rated 16V" without re-deriving it from a part number.
- Layout constraints — RFC-013's
net_classes/diff_pairs/length_matches/placement_hints, mapped into IPC-2581's own constraint/net-class XML elements (its schema has a native place for exactly this — closing the fit-analysis note's "constraint translation is the real work" observation with a direct, real mapping rather than an ad hoc side-channel). - Physical section — deliberately minimal for this RFC's scope: a placeholder board outline (or the schema's minimal-valid-physical-section idiom, whichever the XSD actually requires for a valid document — determined during implementation, not guessed here), explicitly flagged in a document-level comment/metadata field as "logical-complete, physical-minimal — layout not yet performed," so a receiving tool and a human both know exactly what they're getting.
Implementation approach: hand-rolled XML emission, not a general XML library
Consistent with the project's existing style (hand-rolled JSON in json.rs/layout.rs, zero dependencies except the one scoped exception RFC-014 already justified for lsp-types) — IPC-2581 is a large schema, but the subset this RFC actually populates (netlist + components + specs + constraints + minimal physical) is a small, fixed, well-understood slice. Hand-rolling that slice's XML serialization (string formatting with proper escaping, the same discipline json_str() already applies in json.rs) keeps this consistent with existing emitters rather than pulling in a general-purpose XML/serde dependency for a document shape CoHDL controls precisely.
Type-system-first test
N/A — this RFC adds no new checkable construct. It is a new output-format projection of data RFC-001–013's type checker/DRC/RFC-013's layout constraints already validated.
Conceptual impact
Low. No new language concept, no new syntax — part's footprint-name field and RFC-013's constraint data are both already-accepted concepts; this RFC only adds a new way to emit them. The one small addition: a document-level "logical-complete, physical-minimal" marker in the output, which is metadata about the emission, not a language concept.
Coherence matrix row
| Concepts | Grammar | Oracle | Diagnostics | Netlist | Compat | Trust |
|---|---|---|---|---|---|---|
| Low | Low | Low | Low | High | Low | High |
Netlist (High): this is the first RFC to add a genuinely new output format alongside KiCad .net/BOM/layout.json — real new surface area, even though it's a projection of existing data. Fidelity here (does the IPC-2581 document actually carry what CoHDL knows, correctly) is the entire point of the RFC. Trust (High): the explicit "logical-complete, physical-minimal" honesty marker is the single most important design decision in this RFC — it's what prevents this from becoming a document that silently overclaims completeness, directly serving the Constitution's "no silent gaps" hard constraint applied to a new artifact instead of a new check. Oracle/Diagnostics/Concepts/Grammar/Compat (Low): no change to what's checked, no new syntax, no new diagnostics, purely additive output.
Gradeability
Enforced by two mechanically-checkable properties, mirroring the discipline every prior emitter RFC established: (1) schema validity — the emitted XML validates against the real IPC-2581B1.xsd (using KiCad's own schema copy, or the IPC-2581 Consortium's published copy, as the test's ground truth — not a hand-derived subset schema); (2) fidelity equivalence — for every fixture, the IPC-2581 document's netlist/component/spec/constraint content must be derivable from, and consistent with, what the existing KiCad .net/BOM/layout.json emitters already report for the same design — the same "two consumers of the same underlying data must agree" discipline RFC-010's --json equivalence test and RFC-014's LSP equivalence test both already established for their own domains.
AI-generatability
N/A in the usual sense — this RFC doesn't change what an AI author writes in .cohdl source. Indirectly relevant: once this emitter exists, an AI-generated design's part declarations (footprint name, MPN) become directly consumable by a layout partner without any manual re-entry — the same "no silent drops, no manual re-typing across a tool boundary" principle the KiCad/BOM emitters already serve, extended to a partner-facing format.
Alternatives
- Ship the KiCad
.nethandoff as the only integration path, skip IPC-2581 entirely — rejected: this was the fit-analysis note's original sketch, explicitly superseded by its own later analysis once it investigated Quilter's actual multi-vendor contract; keeping only.netwould permanently block the Allegro/Xpedition path and forfeit the vendor-neutrality benefit IPC-2581 specifically buys. - Wrap KiCad's own C++ IPC-2581 I/O (
pcb_io_ipc2581.cpp, cited in the fit-analysis note) instead of writing a native Rust emitter — considered, rejected for this RFC's scope: CoHDL's data doesn't natively live as a KiCad board object (it's aDesignIr, not aBOARD), so wrapping KiCad's I/O would require first lowering to a synthetic KiCad board just to re-serialize — an extra, lossy round-trip for no benefit over emitting IPC-2581 directly from the IR the project already has. Consistent with the existingcohdl-codegen-kicad/cohdl-codegen-lcedapattern of native Rust emitters, not tool-wrapping. - Build full footprint-geometry resolution and board-outline support as part of this same RFC, so the emitted document is fully physically complete — rejected as scope creep: the fit-analysis note itself identified footprint sourcing as "the real gap, not the format," and conflating that much larger, separate engineering problem (a footprint library/resolution system) with the emitter-format question would make this RFC undeliverable in a reasonable scope. This RFC ships the honestly-partial document now; footprint resolution is named as explicit future work (see Migration path).
- A generic, configurable multi-format exporter (KiCad + LCEDA + IPC-2581 unified) — rejected: the existing per-format emitters (
kicad.rs,layout.rs) are already small and independently correct; unifying them behind a configuration layer now would be premature abstraction with no demonstrated need, the same reasoning RFC-013 used to reject a general constraint-plugin system.
Compatibility
Purely additive — a new emitted artifact, new CLI flag/mode, zero change to any existing output (.net, BOM CSV, layout.json) or any existing diagnostic/type-check/DRC behavior.
Tooling & operations
cohdl build's usage string gains the new emit mode;cohdl build --json'sbuildobject gains an"ipc2581"key (path), following the same pattern"layout"already uses — present only when the artifact is emitted.- The emitted document's schema-validity and fidelity-equivalence tests (see Gradeability) belong in a new
tests/ipc2581.rs, following the existing per-RFC conformance-suite convention (tests/layout.rs,tests/json_output.rs). - No new error codes — this RFC introduces no new diagnosable mistake in
.cohdlsource; any IPC-2581-emission-time failure (e.g. apartwhose footprint name is empty, if that's even reachable post-type-check) would reuse or extend an existing E8xx (designators & parts) code, not a new block, since it's still fundamentally a part-completeness question RFC-003 already governs.
Teaching cost
Low for .cohdl authors (no source-level change). Low-to-medium for anyone consuming the output: the "logical-complete, physical-minimal" marker needs one sentence of documentation (mirrored in docs/ipc2581.md, following the existing docs/layout-json.md convention) so a human or partner tool knows what to expect without reading the whole IPC-2581 spec.
Failure modes
- A receiving tool expects a physically-complete IPC-2581 and chokes on the minimal placeholder section — this is a real, named risk (not glossed over): mitigated by making the "logical-complete, physical-minimal" marker prominent and machine-readable (not just a comment), so an automated consumer can detect and handle the case, and by validating against at least one real target (ideally Quilter itself, if/when access is available) before treating this RFC as done.
- The ECO/re-routing mismatch the fit-analysis note flagged — this RFC's emitter does not solve it and does not claim to; every CoHDL regeneration still produces a fresh document with no diff/incremental-update semantics, exactly matching Quilter's own re-route-from-scratch behavior. This is a workflow-level limitation to manage (e.g. "use Quilter once for initial layout, small ECOs elsewhere," per the fit-analysis note's own suggested mitigation), not something this RFC's scope can fix.
- The emitted document's fidelity silently drifts from the KiCad/BOM/layout.json emitters over time (e.g. a future RFC adds a new spec/constraint kind and only updates the other emitters) — mitigated by the mandatory fidelity-equivalence test in Gradeability, which should fail loudly the moment any emitter's output diverges from the others for the same fixture.
Migration path
N/A — purely additive. Explicitly named future work, not part of this RFC's scope: (1) footprint-geometry resolution/a footprint library, (2) board-outline/stackup as a real CoHDL concept, (3) validating the actual Quilter integration end-to-end once access to Quilter's real API or import flow is available.
Decision
Accepted — 2026-07-14. Recorded as DR-021 (see note 7). Language Specification (note 10) gains a short "IPC-2581 output (ipc2581.xml)" tooling-reference section (same category as the Language Server section — tooling, not a language construct). Explicitly scoped as phase one of a multi-phase integration: this RFC ships an honestly-partial, schema-valid document; footprint resolution and board-outline support are named, tracked future work, not silently assumed solved.