app
KiCad - the KiCad Bridge
Public Made by Adomby adom
Reference implementation of the KiCad bridge: multi-instance Python server, forward path via kicad-cli, reverse path via in-process plugin. Most complex of the three bundled bridges.
← Commit history
v0.9.61: kicad_export_molecule — one-shot molecule export pack (STEP + silk renders + sch/pro discovery + container next-steps); capabilities note KiCad-11 schematic IPC
7 files changed
+148−11
BRIDGE_VERSION+1−1@@ -1 +1 @@-0.9.10+0.9.61
adom-bridge-kicad-manifest.json+6−6@@ -1,19 +1,19 @@ { "manifest_version": 1, "name": "kicad",- "version": "0.9.60",- "url": "https://wiki.adom.inc/download/adom/adom-desktop-kicad-bridge/0.9.60/adom-bridge-kicad-v0.9.60.zip",- "sha256": "675f2dd7c44d4ca3fe2f1735fe54166079d0e1b09a3a1f9fee95c11840c48c65",- "size": 646046,+ "version": "0.9.61",+ "url": "https://wiki.adom.inc/download/adom/adom-desktop-kicad-bridge/0.9.61/adom-bridge-kicad-v0.9.61.zip",+ "sha256": "11387c89dd960e16797c42a1db4972f0547f24ffd656da225b71be8e5e103c7b",+ "size": 500594, "verbPrefixes": [ "kicad_" ], "healthEndpoint": "/status",- "released_at": "2026-07-04T14:44:55Z",+ "released_at": "2026-07-15T13:12:16Z", "hero": "https://wiki.adom.inc/blob/app/adom-desktop-kicad-bridge/kicad-hero.png", "languages": [ "Python", "PowerShell" ], "updateManifestUrl": "https://wiki.adom.inc/blob/app/adom-desktop-kicad-bridge/adom-bridge-kicad-manifest.json"-}+}
adom-bridge-kicad-v0.9.61.zipadded⋯ 1 unchanged line ⋯
bridge.json+1−1@@ -2,7 +2,7 @@ "manifest_version": 1, "name": "kicad", "displayName": "KiCad EDA",- "version": "0.9.60",+ "version": "0.9.61", "description": "Reverse bridge for KiCad \u2014 board/schematic introspection, lint via kicad-cli, plugin install, multi-instance probe, in-process DRC.", "homepage": "https://wiki.adom.inc/adom/adom-desktop", "author": "Adom Inc.",
capabilities.py+7−3@@ -25,9 +25,13 @@ public KiCad IPC-API roadmap): The schematic/symbol editor has NO IPC handler yet, so opening a *symbol* on the canvas stays assisted (Win32) automation. * KiCad 11 (when it ships) → SWIG bindings removed; IPC is the only- Python path and is expected to broaden to the schematic/symbol editor.- When it does, symbol delivery flips from "assisted" to "ipc" with no- caller change — they just read `automation.symbol`.+ Python path and broadens to the schematic editor. Confirmed against+ kipy (kicad-python): `KiCad.get_schematic()` is tagged "Added in …+ (KiCad 11)" — the schematic object is NOT in KiCad 10.x, so on 10.x+ symbol/schematic work stays assisted (Win32) automation. When 11 lands,+ symbol delivery flips from "assisted" to "ipc" with no caller change —+ they just read `automation.symbol`. (Verified 2026-07: get_board() is+ the only document object exposed by kipy on 10.0.x.) The IPC API also requires the user to ENABLE the API server (Preferences > Plugins > "Enable KiCad API server"); we detect that from
handlers/export_molecule.pyadded+126@@ -0,0 +1,126 @@+"""kicad_export_molecule — one-shot "molecule export pack" for a KiCad board.++The Adom molecule pipeline (container side) is:+ STEP → step2glb (color-preserving GLB) → adom-molecule create+ --glb ... --pcb ... --sch ... --pro ... → Hydrogen molecule+ (+ optionally a wiki.adom.inc component page)++adom-molecule REQUIRES four files for a KiCad source: .glb, .kicad_pcb,+.kicad_sch and .kicad_pro. The GLB comes from the STEP via step2glb *in the+container*; everything else lives here on the Windows host next to the board.++This verb does the entire desktop-side half in one call:+ 1. export the board's STEP (geometry + component models),+ 2. render silkscreen top/bottom PNGs when `kicad-cli pcb render` exists+ (KiCad 9+; optional extras for the molecule page),+ 3. locate the sibling .kicad_sch / .kicad_pro by the board's stem,+ 4. return a single manifest of host paths + the exact container commands+ to finish the pipeline.++The caller then pull_file's the manifest paths and runs the printed commands.+No container tools are shelled from here — the bridge stays desktop-only.+"""++import os+import subprocess+from pathlib import Path++from .export import _run_pcb_export+++def handle_export_molecule(kicad_info: dict, args: dict) -> dict:+ if not kicad_info.get("installed"):+ return {+ "success": False,+ "error": "KiCad not installed",+ "_hint": "Install KiCad first (kicad_upgrade), then retry.",+ }++ file_path = args.get("filePath", "")+ if not file_path:+ return {"success": False, "error": "No filePath specified (the .kicad_pcb)"}+ pcb_path = Path(file_path)+ if not pcb_path.exists():+ return {+ "success": False,+ "error": f"PCB file not found: {file_path}",+ "_hint": "Path must exist on the Windows host. send_files it first if it lives in Docker.",+ }++ out_dir = args.get("outputDir") or str(pcb_path.parent / "molecule_output")+ os.makedirs(out_dir, exist_ok=True)++ result: dict = {"success": True, "data": {}}+ missing: list = []++ # 1) STEP (reuse the standard export; honors its own error paths)+ step_res = _run_pcb_export(+ kicad_info,+ {"filePath": str(pcb_path), "outputDir": out_dir},+ "step",+ "STEP",+ )+ if not step_res.get("success"):+ return {+ "success": False,+ "error": f"STEP export failed: {step_res.get('error')}",+ "_hint": "The STEP is mandatory for the molecule GLB — fix this first.",+ }+ step_path = step_res["data"]["output_path"]+ result["data"]["step"] = step_path++ # 2) Silkscreen renders (optional; needs `kicad-cli pcb render`, KiCad 9+)+ cli_exe = kicad_info.get("kicad_cli_exe")+ silk = {}+ for side in ("top", "bottom"):+ png = os.path.join(out_dir, f"{pcb_path.stem}-silk-{side}.png")+ try:+ r = subprocess.run(+ [cli_exe, "pcb", "render", "--side", side,+ "--background", "transparent", "--output", png, str(pcb_path)],+ capture_output=True, text=True, timeout=180,+ )+ if r.returncode == 0 and Path(png).exists():+ silk[side] = png+ else:+ missing.append(f"silk-{side} (kicad-cli pcb render rc={r.returncode})")+ except Exception as e: # old KiCad without `pcb render`, timeout, …+ missing.append(f"silk-{side} ({e})")+ result["data"]["silkscreen"] = silk++ # 3) Sibling project files by stem — adom-molecule needs sch + pro+ sch = pcb_path.with_suffix(".kicad_sch")+ pro = pcb_path.with_suffix(".kicad_pro")+ result["data"]["pcb"] = str(pcb_path)+ result["data"]["sch"] = str(sch) if sch.exists() else None+ result["data"]["pro"] = str(pro) if pro.exists() else None+ for label, p in (("sch", sch), ("pro", pro)):+ if not p.exists():+ missing.append(f"{label} ({p.name} not next to the board — adom-molecule requires it)")++ # 4) The exact container-side finish+ name = args.get("name") or pcb_path.stem+ result["data"]["nextSteps"] = [+ f"pull_file the paths in data (step/pcb/sch/pro/silkscreen) to the container",+ f"step2glb convert <step> --out /tmp/{pcb_path.stem}.glb",+ (+ f"adom-molecule create --source kicad --name \"{name}\" --owner <owner> "+ f"--description \"<desc>\" --glb /tmp/{pcb_path.stem}.glb "+ f"--pcb <pcb> --sch <sch> --pro <pro>"+ + (" --silk-top <silk-top> --silk-bottom <silk-bottom>" if silk else "")+ ),+ ]+ if missing:+ result["data"]["missing"] = missing+ result["output"] = (+ f"Molecule export pack in {out_dir}: STEP"+ + (f" + silk({','.join(silk)})" if silk else "")+ + (f"; MISSING: {'; '.join(missing)}" if missing else " — complete")+ )+ result["_hint"] = (+ "Desktop half of the molecule pipeline is done. pull_file everything in "+ "data, then run data.nextSteps in the container (step2glb → adom-molecule "+ "create). adom-molecule REQUIRES glb+pcb+sch+pro; silk PNGs are optional "+ "polish for the molecule page."+ )+ return result
server.py+7@@ -56,6 +56,9 @@ from handlers.export import ( handle_export_gerber, handle_export_pdf, handle_export_svg, handle_export_step, handle_export_bom_csv, )+# v0.9.61+: one-shot desktop half of the Adom molecule pipeline (STEP + silk+# renders + sibling sch/pro discovery + container next-steps manifest).+from handlers.export_molecule import handle_export_molecule # v0.9.10+: check/upgrade KiCad via the OFFICIAL downloads.kicad.org installer # (NOT winget, which lags the real release). check_for_updates is read-only; # upgrade silent-installs the official signed NSIS build.@@ -320,6 +323,9 @@ _VERB_CATALOG = { "export_step": {"summary": "Export a STEP 3D model from a board.", "long": False, "hint": "Absolute board path + output; exports a STEP assembly via kicad-cli.", "related": ["kicad_open_3d_viewer", "kicad_export_gerber"], "pitfalls": ["only components with 3D models attached appear in the STEP"]},+ "export_molecule": {"summary": "One-shot molecule export pack: STEP + silk renders + sch/pro discovery for the Adom molecule pipeline.", "long": True,+ "hint": "Absolute board path; exports STEP (+ silkscreen top/bottom PNGs when kicad-cli pcb render exists), finds the sibling .kicad_sch/.kicad_pro, and returns data.nextSteps — the exact container commands (step2glb → adom-molecule create) to finish.",+ "related": ["kicad_export_step", "kicad_export_svg"], "pitfalls": ["adom-molecule requires glb+pcb+sch+pro — check data.missing before running the container half", "silk renders need KiCad 9+ (kicad-cli pcb render); older KiCads skip them gracefully"]}, "export_bom_csv": {"summary": "Export a BOM CSV from a schematic.", "long": False, "hint": "Absolute schematic path + output; writes a BOM CSV via kicad-cli.", "related": ["kicad_open_schematic", "kicad_export_gerber"], "pitfalls": ["needs kicad-cli (KiCad >= 7)"]},@@ -473,6 +479,7 @@ COMMAND_HANDLERS = { "export_pdf": handle_export_pdf, "export_svg": handle_export_svg, "export_step": handle_export_step,+ "export_molecule": handle_export_molecule, "export_bom_csv": handle_export_bom_csv, # v0.9.10+: KiCad version check + upgrade via the official downloads.kicad.org # installer (read-only check; silent /S install). Exposed as kicad_check_for_updates