Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
# 17 · Upstream-Tooling Verdict — engineering the harness on KiCad + EasyEDA
We inspected the two upstream GitHub orgs that own the tools PCB Flow drives —
[KiCad](https://github.com/orgs/KiCad/repositories) (100 repos) and
[EasyEDA / JLCEDA](https://github.com/orgs/easyeda/repositories) (76 repos) — to
answer one question: **what already exists upstream that we should adopt, align to,
or learn from, instead of hand-rolling.**
**Headline finding.** EasyEDA has, in the last year, shipped an *official* AI-automation
stack that is a superset of the one we reverse-engineered on the Light Dome project:
a typed API package, a WebSocket code-execution bridge, an editor-side gateway
extension, a debug MCP, machine-readable file/netlist format specs, and reference
extensions that mirror our `pcbmunch` and DFM work. KiCad's GitHub is a read-only
mirror + libraries; its automation story is `kicad-cli` (which we already use) plus
the KiCad 9 **IPC API** (`kipy`). The verdict: **stop treating these as black boxes,
bind to the official contracts, and keep our thin Python core as the orchestrator.**
This does not change the thesis (*knowledge is source, geometry is a build artifact*).
It replaces the most fragile, hand-rolled parts of the **build backend** with
maintained upstream contracts.
---
## 0 · TL;DR verdict table
| Upstream asset | What it is | Verdict for PCB Flow | Pri |
|---|---|---|---|
| `easyeda/easyeda-api-skill` → `references/classes/DMT_*.md` + `@jlceda/pro-api-types` | Full `eda.*` API class reference + npm types | **ALIGN-TO** — source of truth for the API surface our generators/probes target | P0 |
| `easyeda/easyeda-api-skill` (Bridge) + `eext-run-api-gateway` | Node WebSocket Bridge with HTTP `/execute` + editor gateway extension (ports 49620-49629, handshake `easyeda-bridge`) | **ADOPT** as primary EasyEDA transport; keep our raw-CDP driver as fallback | P0 |
| `easyeda/easyeda-pro-netlist-format` (`.enet` v2.0.0 + `enet-format-verify.mjs`) | Official JSON netlist: components, designRule, differentialPair, netClass, equalLengthNetGroup | **ADOPT** as canonical netlist interchange + a phase-5 validation gate | P0 |
| `easyeda/easyeda-api-skill/format/**` (+ `easyeda-pro-file-format`) | Machine-readable project/schematic/PCB source-format specs | **LEARN-FROM / parse directly** — read-only analysis without live CDP | P1 |
| `easyeda/eext-jlc-order-dfm-checker` | 18 PCB + 7 SMT JLCPCB DFM checks, thresholds auto-matched to material/layers/copper; rotated-rect pad true-distance, same-net skip | **ADOPT the ruleset** into `pcbflow/geometry.py` + a new `dfm.py` | P1 |
| `easyeda/eext-netlist-explorer` | Netlist views: connection-ref, connector pin-mapping, device topology, BOM, multi-format export | **LEARN-FROM** — it *is* `pcbmunch`'s feature set → adopt its view taxonomy as the roadmap | P1 |
| `easyeda/eext-freerouting-intergration` + `eext-kirouting-integration` (Rust A* via `drandyhaas/KiCadRoutingTools`) | Two proven external autorouters + an EasyEDA↔KiCad format-conversion bridge | **ADOPT as adapters** (keeps our "no custom autorouter" rule) | P1 |
| `KiCad` `kicad-cli` (in `kicad-source-mirror`) | Headless DRC / gerber / netlist export | **KEEP** — already our DRC ground truth (`tools/drc.py`, `automation/kicad/drc.sh`) | — |
| KiCad 9 **IPC API** (`kipy`, dev on GitLab) | Stable out-of-process Python board API, supersedes SWIG `pcbnew` | **LEARN-FROM / forward path** for interactive KiCad manipulation | P1 |
| `KiCad/kicad-library-utils`, `kicad-symbols`, `kicad-footprints`, `kicad-footprint-wizards` | Official libs + KLC checkers + parametric footprint generators | **CONSUME** for library validation + part generation | P2 |
| `easyeda/extension-dev-mcp-tools` | MCP: `import_plugin` / `dev_plugin` / `get_console_logs` (Playwright + Chrome 9222-9231, login cache) | **LEARN-FROM** — fold login-cache + console-capture into our reliability layer | P2 |
| `KiCad/kicad-python` (GitHub) | Old SWIG-era scripting API | **IGNORE** — repo is deprecated (→ `atait/kicad-python`); use `kicad-cli`/`kipy` | — |
---
## 1 · KiCad verdict — we are already on the right interface
- **`kicad-cli` is the correct headless contract and we already use it.** DRC with a
ruleset sidecar (`.kicad_pro`) is our ground truth — that stays. Nothing upstream
beats it for gerber/DRC/netlist export in CI.
- **The SWIG `pcbnew` Python module is legacy.** The reference project drove placement
through `/usr/bin/python3` + `pcbnew`; that still works but is the past. The
GitHub `KiCad/kicad-python` repo is **explicitly deprecated** (moved to
`atait/kicad-python`).
- **Forward path = the KiCad 9 IPC API (`kipy`).** An out-of-process, versioned Python
API (developed on GitLab, published as `kicad-python`/module `kipy`) that talks to a
running KiCad over a socket — no in-process SWIG, no ABI coupling. *We do not
rewrite anything now*, but new KiCad-side interactive automation should target `kipy`
behind a thin adapter, with `kicad-cli` remaining the verification gate. **Mark as
unit-designed / needs validation against the installed KiCad version.**
- **Libraries are free leverage.** `kicad-symbols` / `kicad-footprints` /
`kicad-packages3D` + `kicad-library-utils` (KLC compliance checkers) +
`kicad-footprint-wizards` (parametric generators) let PCB Flow *validate* and
*generate* library parts instead of trusting fuzzy vendor search (the exact failure
mode of KG-T6 / F9 in [`13_LESSONS_LEARNED.md`](13_LESSONS_LEARNED.md)).
**Net:** KiCad needs no re-architecture. Add a `kipy` adapter as an option, wire the
KLC checkers into library validation. `kicad-cli` stays the source of DRC truth.
---
## 2 · EasyEDA verdict — bind to the official automation stack
Today PCB Flow drives EasyEDA two ways (see [`06`](06_EASYEDA_INTEGRATION.md)):
standalone-script paste, and **raw CDP into a logged-in Chrome profile**
(`window._EXTAPI_ROOT_`, port 9222 — with the Google-OAuth-blocked, clone-the-profile,
kill-`Singleton*` workarounds). That was necessary in 2026-H1. It no longer is.
**2.1 Transport — adopt the official Bridge (`/execute`).**
`easyeda-api-skill` ships a Node **Bridge Server** that opens a port in `49620-49629`
and exposes:
```
GET /health → connection status
POST /execute {code} → runs `return await eda.<...>` inside the editor, returns JSON
```
paired with the editor-side **`run-api-gateway`** extension (handshake `easyeda-bridge`,
auto-scan, auto-reconnect, heartbeat). This is *exactly* our `cdp.eval()` envelope
(`{ok,v}`/`{ok,err}`) but maintained upstream, handshake-verified, and it does **not**
require cloning a Chrome profile or defeating OAuth — the user logs into their normal
EasyEDA, ticks "allow external interaction", and the gateway connects out.
→ **Action:** add `automation/easyeda/bridge.py` — a stdlib HTTP client for
`/health` + `/execute` — and make it the *primary* `run(js)->{ok,...}` transport, with
`automation/browser/cdp.py` kept as the fallback for screenshots and when the gateway
isn't installed. One `EdaSession` interface, two backends. Our reliability layer
(`tools/recover.py`, `tools/heal.py`) wraps it unchanged (same envelope).
**2.2 API surface — align to the reference, stop guessing.**
`references/classes/DMT_*.md` (DMT_Pcb, DMT_Schematic, DMT_Board, DMT_Project, …) +
the `@jlceda/pro-api-types` npm package are the authoritative `eda.*` signatures. Our
`section_generator.template.js` and `api_probe.js` should be *checked against* them,
and the "tested-signatures table" in [`06`](06_EASYEDA_INTEGRATION.md) becomes a
*diff against upstream* instead of a hand-maintained list. This kills a whole class of
"wrong-signature hard-hangs the renderer" bugs (see memory + `05` §B).
**2.3 Netlist — adopt `.enet` v2.0.0 as the interchange.**
`.enet` is JSON with `version / components / designRule / differentialPair / netClass /
equalLengthNetGroup`, with a real conformance verifier (`enet-format-verify.mjs`) and
a 496-component reference example. This is the missing standard under our
`net_connection.md` ↔ recon pipeline.
→ **Action:** `pcbflow` recon/dump emits `.enet`; phase-5 verification runs the
official verifier as a gate (fail-closed). `net_connection.md` becomes a human view
*generated from* `.enet`, not a parallel source that can drift.
**2.4 File formats — parse directly for read-only analysis.**
`format/pcb/*.md` (`rule.md`, `pad_via.md`, `primitive.md`, `component.md`),
`format/schematic/*.md`, `format/project/*.md` fully specify the source files. For
*read-only* work (design intelligence, DFM, audits) we can parse the saved project
instead of round-tripping through a live CDP session — faster, offline, CI-able. Live
CDP stays for *writes* and for reading unsaved state.
**2.5 DFM — adopt the JLCPCB ruleset.**
`eext-jlc-order-dfm-checker` encodes **18 PCB + 7 SMT** checks with thresholds
auto-selected by board material / layer count / copper weight, and — critically — it
does **rotated-rect pad true-distance** and **same-net skip (incl. copper cross-connect)**.
That is precisely the geometry our reference project had to discover the hard way.
→ **Action:** encode these thresholds + the pad-distance logic into `pcbflow/geometry.py`
and a new `pcbflow/dfm.py`; expose as `pcbflow dfm` and a `pcbmunch` tool. This is the
authoritative source — do not invent our own numbers.
**2.6 Design intelligence — `eext-netlist-explorer` validates `pcbmunch`.**
Its views (full netlist, connection-reference net, connector pin-mapping SVG, device
topology graph with GND filtering, BOM aggregation, multi-format export) are the exact
surface `pcbmunch` should expose. Treat it as the **feature spec** for pcbmunch:
`get_net` / `blast_radius` / `power_rails` already exist; add `connection_ref`,
`connector_pairs`, `topology`, `bom_health`, and CSV/SVG/JSON export.
**2.7 Routing — two proven external routers, zero custom code.**
Our rule is *no custom autorouter*. Upstream officially integrates two:
**freerouting** (`eext-freerouting-intergration`) and a **Rust-accelerated A\* router**
(`eext-kirouting-integration` → `drandyhaas/KiCadRoutingTools`) via a **Python/FastAPI
bridge that converts EasyEDA↔KiCad**. That conversion bridge is the reusable pattern
(and it doubles as our EasyEDA→KiCad handoff for the DRC gate). → **Action:** add
`automation/routing/` adapters that shell out to freerouting and KiCadRoutingTools;
never write our own maze router (F8, `13_LESSONS_LEARNED.md`).
---
## 3 · What to vendor vs reference (licensing-aware)
The responsible way to "fetch suitable things" is a **curated pointer catalog**, not
a blind copy of 351 upstream files (bloat + attribution risk). See
[`knowledge/upstream/README.md`](../knowledge/upstream/README.md) for the pinned list.
- **Reference (link, don't copy):** the full `references/classes/**` API docs and
`format/**` specs — large, versioned upstream, better fetched on demand.
- **Vendor (small, permissive, high-value):** the `.enet` format spec + its verifier
invocation, and the DFM threshold table — small, stable, and we build tooling on
them. `pro-api-sdk` is **Apache-2.0** (attribution-friendly). Verify each repo's
license before copying any file; record it in the catalog.
- **Depend, don't fork:** `@jlceda/pro-api-types` (npm), freerouting, KiCadRoutingTools —
invoke as external tools / dev-deps.
---
## 4 · What we deliberately ignore
Peripheral to a *schematic→PCB→manufacturing* harness (leave to EasyEDA's marketplace):
simulation (`easyeda-simulation-engine`, `eext-simulation-with-*`), MCAD bridges
(SolidWorks / Fusion360 / FreeCAD), Blender render, art-PCB / coil / graffiti-silk /
QR generators, and the old KiCad `.pretty` footprint repos beyond the ones we consume.
None of these change the harness.
---
## 5 · Net effect on the architecture
The build backend gains **maintained upstream contracts**; the Python core stays the
orchestrator and stays the same size.
```
knowledge (source) ← unchanged: build_sheet / net_connection / rules
│ pcbflow (Python stdlib orchestrator) ← unchanged core, +dfm.py, +bridge client
▼
EDA build backend
├─ EasyEDA ── Bridge /execute (primary) ─┐ ← NEW official transport
│ └ raw CDP (fallback/shots) ─┤
│ binds to @jlceda/pro-api-types + format specs ← NEW: align, don't guess
├─ netlist ── .enet v2.0.0 (+ verifier gate) ← NEW canonical interchange
├─ DFM ────── JLCPCB 18+7 ruleset ← NEW authoritative rules
├─ routing ── freerouting / KiCadRoutingTools adapters ← external, no custom router
└─ KiCad ──── kicad-cli (DRC truth) + kipy adapter (fwd) ← keep + forward path
```
**Prioritized build order:** P0 = Bridge `/execute` client + `.enet` adopt + API-surface
alignment. P1 = `dfm.py` from the JLCPCB checker, pcbmunch views from netlist-explorer,
routing adapters, `kipy` adapter. P2 = library-utils validation, console-capture
reliability, ship an Agent-Skills-compatible `SKILL.md`.
> Everything above the P0/P1 line is **unit-designable now**; the transport, DFM, and
> routing adapters need a **live EasyEDA/KiCad session to validate** — mark them
> "needs real-world validation" until then, per our honesty rule.
7315b96d0This file is pinned to the selected release. Download the original to open it in your design tool.