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
Update 4 file(s)
4 files changed
+42−10
BRIDGE_VERSION+1−1@@ -1 +1 @@-0.9.214+0.9.215
adom-bridge-kicad-manifest.json+5−5@@ -1,15 +1,15 @@ { "manifest_version": 1, "name": "kicad",- "version": "0.9.214",- "url": "https://wiki.adom.inc/download/adom/kicad-bridge/0.9.214/adom-bridge-kicad-v0.9.214.zip",- "sha256": "4531cb0b703a69aeeafa6ed54662557b05a6a487578d04afca63a1cfa7b571d7",- "size": 482513,+ "version": "0.9.215",+ "url": "https://wiki.adom.inc/download/adom/kicad-bridge/0.9.215/adom-bridge-kicad-v0.9.215.zip",+ "sha256": "3930ebde7c53b56f5c1e011f1d68a5495315dca33df7b7b5270e27e145378381",+ "size": 483003, "verbPrefixes": [ "kicad_" ], "healthEndpoint": "/status",- "released_at": "2026-08-20T16:05:00Z",+ "released_at": "2026-08-20T16:20:00Z", "hero": "https://wiki.adom.inc/blob/app/kicad-bridge/kicad-hero.png", "languages": [ "Python",
bridge.json+1−1@@ -2,7 +2,7 @@ "manifest_version": 1, "name": "kicad", "displayName": "KiCad EDA",- "version": "0.9.214",+ "version": "0.9.215", "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.",
plugin_payload/adom_bridge.py+35−3@@ -2809,6 +2809,15 @@ def _ui_wm_command(frame_index: int, menu_id: int) -> dict: +class _ProbeUnavailable(Exception):+ """The PROBE could not run. Distinct from KiCad rejecting a footprint, and+ the distinction matters: the first version of this probe reported+ "KICAD REFUSES TO LOAD IT: AttributeError: 'NoneType' object has no+ attribute 'FootprintLoad'" - which was MY adapter failing, dressed up as+ KiCad's parser talking. Blaming the host app for a bug in the probe is+ exactly the false-diagnosis class this bridge keeps having to fix."""++ class _ModuleFpTable: """Adapter over KiCad 10's module-level footprint functions. @@ -2827,10 +2836,16 @@ class _ModuleFpTable: return list(self._m.GetFootprintLibraries()) def FootprintEnumerate(self, library, _best_efforts=False):- return list(self._m.FootprintEnumerate(library))+ fn = getattr(self._m, "FootprintEnumerate", None)+ if fn is None:+ raise _ProbeUnavailable("pcbnew has no FootprintEnumerate on this build")+ return list(fn(library)) def FootprintLoad(self, library, footprint):- return self._m.FootprintLoad(library, footprint)+ fn = getattr(self._m, "FootprintLoad", None)+ if fn is None:+ raise _ProbeUnavailable("pcbnew has no FootprintLoad on this build")+ return fn(library, footprint) def _ui_probe_footprint(library: str, footprint: str) -> dict: """Ask KICAD ITSELF whether it can see and load this footprint.@@ -2906,7 +2921,12 @@ def _ui_probe_footprint(library: str, footprint: str) -> dict: listed = [] out["kicadListCount"] = len(listed) out["inKicadList"] = footprint in listed- if listed and not out["inKicadList"]:+ if not listed:+ out["verdict"] = ("PROBE COULD NOT ENUMERATE: KiCad returned an empty list for a "+ "library it says is registered, so the probe has no opinion on "+ "this footprint. See enumerateError. Not evidence of a bad file.")+ return out+ if not out["inKicadList"]: near = [n for n in listed if footprint.lower() in n.lower() or n.lower() in footprint.lower()][:5] out["kicadNearby"] = near@@ -2930,6 +2950,18 @@ def _ui_probe_footprint(library: str, footprint: str) -> dict: pass out["verdict"] = ("LOADS FINE: KiCad can enumerate AND parse this footprint, so any " "failure to show it is in the editor navigation, not the library.")+ except _ProbeUnavailable as e:+ out["loads"] = None+ out["probeError"] = str(e)+ out["verdict"] = (f"PROBE UNAVAILABLE: {e}. This says NOTHING about the footprint - "+ "it is the probe that could not run.")+ except AttributeError as e:+ # An AttributeError here is almost always the probe's own plumbing+ # (a None where an object was expected), not KiCad rejecting a file.+ out["loads"] = None+ out["probeError"] = f"{type(e).__name__}: {e}"+ out["verdict"] = (f"PROBE ERROR (not a KiCad verdict): {type(e).__name__}: {e}. "+ "Treat this as the probe failing, not the footprint.") except Exception as e: out["loads"] = False out["loadError"] = f"{type(e).__name__}: {e}"