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.166: #31 - load the reverse bridge from KiCad's scripting/plugins dir, the hook that still fires on 10.0.5 (verified live: a probe there ran inside kicad.exe with USER_SITE already correct)
5 files changed
+74−7
BRIDGE_VERSION+1−1@@ -1 +1 @@-0.9.165+0.9.166
adom-bridge-kicad-manifest.json+5−5@@ -1,15 +1,15 @@ { "manifest_version": 1, "name": "kicad",- "version": "0.9.165",- "url": "https://wiki.adom.inc/download/adom/kicad-bridge/0.9.165/adom-bridge-kicad-v0.9.165.zip",- "sha256": "2cb2c8ea5e2f51b818b91a90083c14ed4fd51f26aa181137719f8a70dab06da8",- "size": 443871,+ "version": "0.9.166",+ "url": "https://wiki.adom.inc/download/adom/kicad-bridge/0.9.166/adom-bridge-kicad-v0.9.166.zip",+ "sha256": "d83c5a35c1ee5995fa078e4b12f484a27b4fc5a671f719e8ba675ac85a471a47",+ "size": 444512, "verbPrefixes": [ "kicad_" ], "healthEndpoint": "/status",- "released_at": "2026-08-18T12:25:13Z",+ "released_at": "2026-08-18T12:48:46Z", "hero": "https://wiki.adom.inc/blob/app/kicad-bridge/kicad-hero.png", "languages": [ "Python",
adom-bridge-kicad-v0.9.166.zipadded⋯ 1 unchanged line ⋯
bridge.json+1−1@@ -2,7 +2,7 @@ "manifest_version": 1, "name": "kicad", "displayName": "KiCad EDA",- "version": "0.9.165",+ "version": "0.9.166", "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_install.py+67@@ -139,6 +139,55 @@ except Exception: """ +_PLUGIN_DIR_LOADER = """\+\"\"\"adom_bridge_plugin - Adom KiCad bridge loader, KiCad plugin-dir entry.++THE 10.0.5 FIX (issue #31, root-caused 2026-08-18). The bridge used to be loaded+by usercustomize.py, which only runs if the interpreter performs site's+execusercustomize() step. KiCad 10.0.5's GUI stopped doing that, so the reverse+bridge never started and kicad_bridge_status read 0 alive while KiCad sat there+running.++KiCad DOES still import every .py in its scripting/plugins directory at startup -+verified live on 10.0.5: a probe placed here fired inside kicad.exe and reported+site.USER_SITE already pointing at the bridge's deploy directory. So this file is+the reliable entry point, and the payload it loads is unchanged.+\"\"\"+try:+ import os+ import sys++ if not os.environ.get("ADOM_KICAD_BRIDGE_LOADED"):+ os.environ["ADOM_KICAD_BRIDGE_LOADED"] = "1"+ import usercustomize # noqa: F401 - importing it IS the bootstrap+except Exception:+ try:+ import tempfile+ import traceback+ with open(os.path.join(tempfile.gettempdir(),+ "adom-kicad-plugin-loader.error.log"), "a") as fh:+ fh.write(traceback.format_exc() + chr(10))+ except Exception:+ pass+"""+++def _kicad_plugin_dirs(version: str):+ """KiCad's own scripting-plugin directories (it imports every .py here at+ startup). %APPDATA%/kicad/<version>/scripting/plugins on Windows."""+ import os as _os+ from pathlib import Path as _P+ appdata = _os.environ.get("APPDATA")+ if not appdata:+ return []+ out = []+ base = _P(appdata) / "kicad"+ for v in ({version} | {d.name for d in base.glob("*") if d.is_dir()}):+ if v:+ out.append(base / v / "scripting" / "plugins")+ return out++ def _std_user_site(): """The interpreter's DEFAULT user-site for KiCad's Python 3.11 on Windows: %APPDATA%\\Python\\Python311\\site-packages. KiCad 10.0.5 reports this as@@ -346,6 +395,24 @@ def _install_one_version(version: str, version_info: dict) -> dict: # everything deployed to the Documents user-site is invisible. Deploying the # same payload to the interpreter's real user-site makes the loader fire # again; the boot guard keeps it inert in every non-KiCad Python.+ # THE loader that actually fires on 10.0.5: KiCad imports scripting/plugins.+ try:+ pdirs = _kicad_plugin_dirs(str(version or "10.0"))+ wrote = []+ for pdir in pdirs:+ try:+ pdir.mkdir(parents=True, exist_ok=True)+ (pdir / "adom_bridge_plugin.py").write_text(_PLUGIN_DIR_LOADER,+ encoding="utf-8")+ wrote.append(str(pdir))+ except Exception:+ pass+ if wrote:+ report["pluginDirLoaders"] = wrote+ written.append({"name": "adom_bridge_plugin.py", "dest": "; ".join(wrote)})+ except Exception as e:+ report["pluginDirError"] = str(e)+ try: std_site = _std_user_site() if std_site and std_site != user_site: