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.93: kicad_show_* family (Fusion fusion_show_* parity) — one clean verb per surface: symbol/footprint/3d_chip/schematic/2d_board/3d_board/library
7 files changed
+160−9
BRIDGE_VERSION+1−1@@ -1 +1 @@-0.9.92+0.9.93
adom-bridge-kicad-manifest.json+5−5@@ -1,15 +1,15 @@ { "manifest_version": 1, "name": "kicad",- "version": "0.9.92",- "url": "https://wiki.adom.inc/download/adom/kicad-bridge/0.9.92/adom-bridge-kicad-v0.9.92.zip",- "sha256": "8e5b2159ed87fad4a7e0b1be7a6d912bda21c61d9c87251e1e4a5bdfdff5383e",- "size": 385143,+ "version": "0.9.93",+ "url": "https://wiki.adom.inc/download/adom/kicad-bridge/0.9.93/adom-bridge-kicad-v0.9.93.zip",+ "sha256": "aa2783fe9d50896d4ee466cb4cd4f25bbff25cffa9eacff1bf4133edb71cd5b5",+ "size": 387661, "verbPrefixes": [ "kicad_" ], "healthEndpoint": "/status",- "released_at": "2026-08-14T18:49:19Z",+ "released_at": "2026-08-14T18:53:13Z", "hero": "https://wiki.adom.inc/blob/app/kicad-bridge/kicad-hero.png", "languages": [ "Python",
adom-bridge-kicad-v0.9.93.zipadded⋯ 1 unchanged line ⋯
bridge.json+9−2@@ -2,7 +2,7 @@ "manifest_version": 1, "name": "kicad", "displayName": "KiCad EDA",- "version": "0.9.92",+ "version": "0.9.93", "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-bridge", "author": "Adom Inc.",@@ -65,7 +65,14 @@ "kicad_demo", "kicad_launch", "kicad_uninstall",- "kicad_state"+ "kicad_state",+ "kicad_show_symbol",+ "kicad_show_footprint",+ "kicad_show_3d_chip",+ "kicad_show_schematic",+ "kicad_show_2d_board",+ "kicad_show_3d_board",+ "kicad_show_library" ], "statusVerb": "kicad_status", "timeouts": {
handlers/show.pyadded+104@@ -0,0 +1,104 @@+"""show.py — kicad_show_* verbs: one clean, self-documenting verb per KiCad+surface, so a caller (ab, a web demo, an AI) NEVER hand-assembles a workflow.++Mirrors the Fusion bridge's fusion_show_* family (#24 follow-up, John 2026-08-14):+the bridge is the expert on which window shows what, so it owns a named verb for+each surface instead of making callers guess file types / editor combos.++The six surfaces a hardware person thinks in, plus library browse:++ kicad_show_symbol -> Symbol Editor at a symbol (or a library) [design/lib]+ kicad_show_footprint -> Footprint Editor at a footprint (or a library)+ kicad_show_3d_chip -> 3D Viewer of the FOOTPRINT (single part in 3D)+ kicad_show_schematic -> Schematic Editor on a .kicad_sch+ kicad_show_2d_board -> PCB Editor (2D) on a .kicad_pcb+ kicad_show_3d_board -> 3D Viewer of the BOARD (whole assembly in 3D)+ kicad_show_library -> Symbol OR Footprint Editor filtered to a library++Every one is a thin, arg-normalizing wrapper over the existing open_* handlers —+same background-first behavior, same verified loads — but with an obvious name+and an obvious argument. All accept the KiCad analogue of Fusion's deviceset:+symbolName/footprintName (+ optional libraryName), or filePath for the docs.+"""+from handlers.open_files import handle_open_board, handle_open_schematic+from handlers.open_symbol_editor import handle_open_symbol_editor+from handlers.open_footprint_editor import handle_open_footprint_editor, handle_open_3d_viewer+++def handle_show_symbol(kicad_info: dict, args: dict) -> dict:+ """Show a schematic SYMBOL in the Symbol Editor. Args: symbolName (+ libraryName),+ or libraryName alone to browse a library."""+ r = handle_open_symbol_editor(kicad_info, args or {})+ r.setdefault("surface", "symbol")+ return r+++def handle_show_footprint(kicad_info: dict, args: dict) -> dict:+ """Show a FOOTPRINT in the Footprint Editor. Args: footprintName (+ library),+ or library alone to browse."""+ r = handle_open_footprint_editor(kicad_info, args or {})+ r.setdefault("surface", "footprint")+ return r+++def handle_show_3d_chip(kicad_info: dict, args: dict) -> dict:+ """Show a single part in 3D — the FOOTPRINT's 3D view (Fusion's Create3DPackage+ analogue). Loads the footprint first if footprintName is given, then its 3D viewer."""+ a = dict(args or {})+ if a.get("footprintName") or a.get("footprint") or a.get("library"):+ loaded = handle_open_footprint_editor(kicad_info, a)+ if not loaded.get("success") and not loaded.get("editorOpened"):+ loaded["surface"] = "3d_chip"+ return loaded+ r = handle_open_3d_viewer(kicad_info, {**a, "editor": "fp"})+ r.setdefault("surface", "3d_chip")+ return r+++def handle_show_schematic(kicad_info: dict, args: dict) -> dict:+ """Show a SCHEMATIC (2D) in the Schematic Editor. Args: filePath (.kicad_sch)."""+ r = handle_open_schematic(kicad_info, args or {})+ if isinstance(r, dict):+ r.setdefault("surface", "schematic")+ return r+++def handle_show_2d_board(kicad_info: dict, args: dict) -> dict:+ """Show the 2D BOARD LAYOUT in the PCB Editor. Args: filePath (.kicad_pcb)."""+ r = handle_open_board(kicad_info, args or {})+ if isinstance(r, dict):+ r.setdefault("surface", "2d_board")+ return r+++def handle_show_3d_board(kicad_info: dict, args: dict) -> dict:+ """Show the whole board in 3D — the BOARD's 3D viewer. Opens the board first if+ filePath is given, then the PCB 3D viewer."""+ a = dict(args or {})+ if a.get("filePath"):+ opened = handle_open_board(kicad_info, {"filePath": a["filePath"],+ "reason": a.get("reason", "show 3D board")})+ if isinstance(opened, dict) and not opened.get("success"):+ opened["surface"] = "3d_board"+ return opened+ r = handle_open_3d_viewer(kicad_info, {**a, "editor": "pcb"})+ r.setdefault("surface", "3d_board")+ return r+++def handle_show_library(kicad_info: dict, args: dict) -> dict:+ """Browse a LIBRARY (symbol or footprint). Args: libraryName (+ kind:'symbol'|'footprint',+ default 'symbol'). No part is loaded — the tree is filtered to the library."""+ a = dict(args or {})+ lib = a.get("libraryName") or a.get("library")+ if not lib:+ return {"success": False, "error": "libraryName is required",+ "_hint": "kicad_show_library {\"libraryName\":\"Device\"} — add kind:\"footprint\" for the footprint side."}+ kind = (a.get("kind") or "symbol").lower()+ if kind in ("footprint", "fp"):+ r = handle_open_footprint_editor(kicad_info, {"library": lib, "timeout": a.get("timeout")})+ else:+ r = handle_open_symbol_editor(kicad_info, {"libraryName": lib, "timeout": a.get("timeout")})+ if isinstance(r, dict):+ r.setdefault("surface", "library")+ return r
server.py+30@@ -30,6 +30,8 @@ from capabilities import build_capability_report from handlers.open_files import handle_open_board, handle_open_schematic from handlers.open_symbol_editor import handle_open_symbol_editor from handlers.open_footprint_editor import handle_open_footprint_editor, handle_open_3d_viewer+from handlers.show import (handle_show_symbol, handle_show_footprint, handle_show_3d_chip,+ handle_show_schematic, handle_show_2d_board, handle_show_3d_board, handle_show_library) from handlers.software_opengl import handle_enable_software_opengl from handlers.diagnostics import handle_diagnostics from handlers.close_windows import (@@ -219,6 +221,27 @@ _VERB_CATALOG = { "hint": "Absolute filePath to a board; opens the 3D viewer. Follow with screenshot_all to capture it.", "related": ["kicad_open_board", "kicad_screenshot_all", "kicad_close_3d_viewer"], "pitfalls": ["3D models only render if the footprints reference installed 3D model files", "the viewer takes a few seconds to render — wait before screenshotting"]},+ "show_symbol": {"summary": "Show a schematic symbol in the Symbol Editor (design/library surface).", "long": True,+ "hint": "kicad_show_symbol {\"symbolName\":\"R\",\"libraryName\":\"Device\"} — verified background load. libraryName alone browses the library.",+ "related": ["kicad_show_footprint", "kicad_show_3d_chip", "kicad_show_library"], "pitfalls": ["the symbol must be in an installed sym-lib-table library"]},+ "show_footprint": {"summary": "Show a footprint in the Footprint Editor.", "long": True,+ "hint": "kicad_show_footprint {\"footprintName\":\"R_0603_1608Metric\",\"library\":\"Resistor_SMD\"}. library alone browses.",+ "related": ["kicad_show_symbol", "kicad_show_3d_chip"], "pitfalls": ["cold Footprint Editor spawns a fresh pcbnew + loads all fp libs — allow ~20-30s"]},+ "show_3d_chip": {"summary": "Show a single part in 3D (the footprint's 3D view).", "long": True,+ "hint": "kicad_show_3d_chip {\"footprintName\":...,\"library\":...} loads the footprint then its 3D viewer. No args = 3D of whatever footprint is loaded.",+ "related": ["kicad_show_footprint", "kicad_show_3d_board"], "pitfalls": ["software-OpenGL boxes render slowly; the window can self-raise late (guarded)"]},+ "show_schematic": {"summary": "Show a schematic (2D) in the Schematic Editor.", "long": True,+ "hint": "kicad_show_schematic {\"filePath\":\"...kicad_sch\"}. Prefer kicad_lint_schematic first for unfamiliar files.",+ "related": ["kicad_show_2d_board", "kicad_show_3d_board"], "pitfalls": ["absolute Windows path; no %VAR% expansion"]},+ "show_2d_board": {"summary": "Show the 2D board layout in the PCB Editor.", "long": True,+ "hint": "kicad_show_2d_board {\"filePath\":\"...kicad_pcb\"}. Prefer kicad_lint_board / kicad_run_drc first.",+ "related": ["kicad_show_3d_board", "kicad_show_schematic"], "pitfalls": ["absolute Windows path; no %VAR% expansion"]},+ "show_3d_board": {"summary": "Show the whole board in 3D (the board's 3D viewer).", "long": True,+ "hint": "kicad_show_3d_board {\"filePath\":\"...kicad_pcb\"} opens the board then its 3D viewer. No filePath = 3D of the open board.",+ "related": ["kicad_show_2d_board", "kicad_show_3d_chip"], "pitfalls": ["3D render self-raise is late on slow boxes — the focus guardian handles it"]},+ "show_library": {"summary": "Browse a symbol or footprint library (no part loaded).", "long": False,+ "hint": "kicad_show_library {\"libraryName\":\"Device\"} (add kind:\"footprint\" for the fp side). Filters the tree to the library.",+ "related": ["kicad_show_symbol", "kicad_show_footprint"], "pitfalls": ["the library must be registered in the sym-/fp-lib-table"]}, "close_symbol_editor": {"summary": "Close the Symbol Editor window.", "long": False, "hint": "Closes the Symbol Editor if open; no-op otherwise.", "related": ["kicad_open_symbol_editor", "kicad_close"], "pitfalls": ["unsaved edits may prompt — save first if you made changes"]},@@ -455,6 +478,13 @@ COMMAND_HANDLERS = { "open_symbol_editor": handle_open_symbol_editor, "open_footprint_editor": handle_open_footprint_editor, "open_3d_viewer": handle_open_3d_viewer,+ "show_symbol": handle_show_symbol,+ "show_footprint": handle_show_footprint,+ "show_3d_chip": handle_show_3d_chip,+ "show_schematic": handle_show_schematic,+ "show_2d_board": handle_show_2d_board,+ "show_3d_board": handle_show_3d_board,+ "show_library": handle_show_library, "close_symbol_editor": handle_close_symbol_editor, "close_footprint_editor": handle_close_footprint_editor, "close_3d_viewer": handle_close_3d_viewer,
skills/kicad-bridge-test/run_verb_tests.py+11−1@@ -130,6 +130,15 @@ def matrix(w: dict) -> dict: note="e2e load of a stock footprint (needs the 0.9.84 lib self-heal)"), "open_3d_viewer": dict(phase=3, args={"reason": "daily verb test"}, timeout=200), "open_editors": dict(phase=3, args={}, check="editors_listed"),+ # ---- phase 3b: show_* surface verbs (Fusion-parity clean names)+ "show_symbol": dict(phase=3, args={"symbolName": "R", "libraryName": "Device"}, check="ok", timeout=160),+ "show_footprint": dict(phase=3, args={"footprintName": "R_0603_1608Metric", "library": "Resistor_SMD"}, timeout=180),+ "show_3d_chip": dict(phase=3, args={}, timeout=200, note="3D of the loaded footprint"),+ "show_schematic": dict(phase=3, args={"filePath": S, "reason": "verb test"}, timeout=160),+ "show_2d_board": dict(phase=3, args={"filePath": B, "reason": "verb test"}, timeout=160),+ "show_3d_board": dict(phase=3, args={"reason": "verb test"}, timeout=200),+ "show_library": dict(phase=3, args={"libraryName": "Device"}, timeout=160),+ "state": dict(phase=3, args={"maxWidth": 640}, check="state_shots", timeout=160, note="#22: every KiCad window as inline base64 + logical state"), "window_info": dict(phase=3, args={}),@@ -355,7 +364,8 @@ def main(): print(f" kicad_{verb:24} {'PASS' if passed else 'FAIL'}") PHASE3_ORDER = ["launch", "open_board", "open_schematic", "open_symbol_editor",- "state",+ "show_schematic", "show_2d_board", "show_symbol", "show_footprint",+ "show_3d_chip", "show_3d_board", "show_library", "state", "open_footprint_editor", "open_3d_viewer", "open_editors", "window_info", "screenshot_all", "dismiss_dialogs", "send_key", "click", "bridge_call"]