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
install_library: footprint installs carry a bundle's 3D models (0.9.251)
Cloud Library bundles ship 3dmodels/ beside the .pretty with relative model
refs, which KiCad resolves against the PROJECT dir, so installed footprints
lost their 3D. Footprint installs now take modelsPath or auto-detect the
3dmodels/ sibling: models copy into 3dmodels/<lib>.3dshapes and the COPIED
footprints' matching refs rewrite to the installed absolute paths (matching
the absolute fp-lib-table URI convention). Source .pretty never modified;
stock-var refs untouched.
5 files changed
+75−10
BRIDGE_VERSION+1−1@@ -1 +1 @@-0.9.250+0.9.251
adom-bridge-kicad-manifest.json+5−5@@ -1,15 +1,15 @@ { "manifest_version": 1, "name": "kicad",- "version": "0.9.250",- "url": "https://wiki.adom.inc/download/adom/kicad-bridge/0.9.250/adom-bridge-kicad-v0.9.250.zip",- "sha256": "7abccebea835d2bd79517c361d48adbfee8ee615f99c4315590071eea5ec6dce",- "size": 1012007,+ "version": "0.9.251",+ "url": "https://wiki.adom.inc/download/adom/kicad-bridge/0.9.251/adom-bridge-kicad-v0.9.251.zip",+ "sha256": "f84e87f08c6e8881d93e50053f0416608cdb5292c5a58c89968d499e9f8ab805",+ "size": 449044, "verbPrefixes": [ "kicad_" ], "healthEndpoint": "/status",- "released_at": "2026-08-24T11:09:20Z",+ "released_at": "2026-08-26T20:34:19Z", "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.250",+ "version": "0.9.251", "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.",
handlers/install_library.py+65@@ -110,6 +110,39 @@ def _install_footprint(kicad_info: dict, args: dict) -> dict: if source.suffix == ".kicad_mod": _add_model_to_footprint(pretty_dir / source.name, model_installed_path) + # Library-bundle 3D models (Adom wiki Cloud Library bundles): a directory+ # of model files (modelsPath arg), or auto-detected as a `3dmodels/`+ # sibling of the source .pretty (the bundle layout). The bundle's+ # footprints reference models by RELATIVE `3dmodels/<file>` paths, which+ # KiCad resolves against the PROJECT dir, not the library — so after+ # copying the models into the user's 3dmodels/<lib>.3dshapes dir, rewrite+ # the COPIED footprints' matching refs to the absolute installed path+ # (forward slashes). Absolute matches this installer's existing+ # convention: the fp-lib-table URI it writes is absolute already. The+ # SOURCE .pretty is never modified.+ models_installed = 0+ refs_rewritten = 0+ models_src = args.get("modelsPath", "")+ if not models_src and source.is_dir() and source.suffix == ".pretty":+ sibling = source.parent / "3dmodels"+ if sibling.is_dir():+ models_src = str(sibling)+ if models_src:+ models_src_dir = Path(models_src)+ if models_src_dir.is_dir():+ models_dir = Path(user_dir) / "3dmodels" / f"{lib_name}.3dshapes"+ models_dir.mkdir(parents=True, exist_ok=True)+ installed_by_name = {}+ for mf in sorted(models_src_dir.iterdir()):+ if not mf.is_file():+ continue+ dest_model = models_dir / mf.name+ shutil.copy2(str(mf), str(dest_model))+ installed_by_name[mf.name] = str(dest_model).replace("\\", "/")+ models_installed += 1+ if installed_by_name:+ refs_rewritten = _rewrite_model_refs(pretty_dir, installed_by_name)+ # Register in fp-lib-table table_path = Path(config_dir) / "fp-lib-table" table = LibTable.parse_file(str(table_path))@@ -150,10 +183,42 @@ def _install_footprint(kicad_info: dict, args: dict) -> dict: if model_installed_path: result["data"]["model3dPath"] = model_installed_path result["output"] += f". 3D model installed to {model_installed_path}"+ if models_installed:+ result["data"]["modelsInstalled"] = models_installed+ result["data"]["modelRefsRewritten"] = refs_rewritten+ result["output"] += (+ f". {models_installed} 3D model(s) installed to 3dmodels/{lib_name}.3dshapes; "+ f"{refs_rewritten} footprint model ref(s) rewritten to the installed paths"+ ) return result +def _rewrite_model_refs(pretty_dir: Path, installed_by_name: dict) -> int:+ """Rewrite (model "...") refs in every .kicad_mod under pretty_dir whose+ BASENAME matches an installed model file, pointing them at the absolute+ installed path. Refs to models we did not install are left untouched+ (they may be stock ${KICAD*_3DMODEL_DIR} refs that already resolve)."""+ rewritten = 0++ def _sub(match):+ nonlocal rewritten+ ref = match.group(2)+ base = ref.replace("\\", "/").rsplit("/", 1)[-1]+ dest = installed_by_name.get(base)+ if not dest:+ return match.group(0)+ rewritten += 1+ return f'{match.group(1)}"{dest}"'++ for mod in sorted(pretty_dir.glob("*.kicad_mod")):+ text = mod.read_text(encoding="utf-8")+ new_text = re.sub(r'(\(model\s+)"([^"]+)"', _sub, text)+ if new_text != text:+ mod.write_text(new_text, encoding="utf-8")+ return rewritten++ def _add_model_to_footprint(footprint_path: Path, model_path: str): """Add a (model ...) reference to a .kicad_mod file.""" text = footprint_path.read_text(encoding="utf-8")
server.py+3−3@@ -353,10 +353,10 @@ _VERB_CATALOG = { "window_info": {"summary": "Report geometry/state for open KiCad windows (auto-expires benign OpenGL dialogs).", "long": False, "hint": "Read-only; returns each KiCad window's position/size/state. Use before click/send_key to target the right window.", "related": ["kicad_open_editors", "kicad_click", "kicad_send_key"], "pitfalls": ["coordinates are screen-absolute — re-read after a window moves/resizes"]},- "install_library": {"summary": "Register a symbol/footprint library in the user's sym-/fp-lib-table.", "long": False,- "hint": "Adds a library to the selected KiCad version's lib table so its parts are usable.",+ "install_library": {"summary": "Register a symbol/footprint library in the user's sym-/fp-lib-table (footprint installs also carry a bundle's 3D models).", "long": False,+ "hint": "Adds a library to the selected KiCad version's lib table so its parts are usable. Footprint installs take modelsPath (a directory of STEP/WRL files) or auto-detect a 3dmodels/ sibling of the source .pretty (the Adom wiki library-bundle layout): models copy into 3dmodels/<lib>.3dshapes and the COPIED footprints' matching (model ...) refs are rewritten to the installed absolute paths, so 3D previews resolve.", "related": ["kicad_install_symbol", "kicad_install_footprint", "kicad_list_versions"],- "pitfalls": ["each KiCad version has its OWN lib tables — install under every version the user needs", "restart/reload KiCad to see a newly-added library"]},+ "pitfalls": ["each KiCad version has its OWN lib tables — install under every version the user needs", "restart/reload KiCad to see a newly-added library", "model-ref rewriting touches only the INSTALLED copy, never the source, and only refs whose basename matches an installed model (stock ${KICAD*_3DMODEL_DIR} refs stay)"]}, "install_symbol": {"summary": "Install a .kicad_sym into the user's sym-lib-table.", "long": False, "hint": "Absolute path to a .kicad_sym; registers it in the sym-lib-table.", "related": ["kicad_open_symbol_editor", "kicad_install_library", "kicad_install_footprint"],