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
Publish 1.0.132
7 files changed
+92−2
SKILL.md+2@@ -102,6 +102,8 @@ If you pass a version that's not installed, the bridge returns a hint listing th | `kicad_adom_library_status` | `adom_library_status` | Report whether the Adom shared library is registered | — | | `kicad_adom_library_heal` | `adom_library_heal` | Reconcile the Adom library: `mode` merge (default) / repoint / prune; `dryRun` previews. From 0.9.279 `prune` drops symbols KiCad refuses | `mode`, `dryRun` | | `kicad_rescan_libraries` | `rescan_libraries` | Make parts installed while an editor was open visible: refreshes the editor library tree in place (seconds, no restart). Pass `footprints:["Adom:NAME"]` to have each loaded in the Footprint Editor as proof (`verified`). `force:true` is the KiCad process restart, last resort | optional `footprints`, `force` |+| `kicad_ipc_api` | `ipc_api` | Read or flip KiCad's IPC API server switch that live routing needs (`{}` reports, `{"enable":true}` writes kicad_common.json, backup kept). KiCad reads it at start: close KiCad, enable, relaunch | optional `enable` |+| `kicad_list_footprints` | `list_footprints` | Footprints per library, read from the fp-lib-table with URIs expanded like KiCad does (stock Resistor_SMD and friends included, from 0.9.343) | optional `library` | ## The `show_*` family — START HERE for "show me X"
package.json+1−1@@ -1,6 +1,6 @@ { "slug": "kicad-bridge",- "version": "1.0.131",+ "version": "1.0.132", "type": "app", "description": "Skills for your container so your AI knows how to drive the KiCad bridge. The bridge runtime itself is the release zip; Adom Bridge loads that.", "tags": [
page.json+1−1@@ -4,7 +4,7 @@ "slug": "kicad-bridge", "title": "KiCad - the KiCad Bridge", "brief": "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.",- "version": "1.0.131",+ "version": "1.0.132", "tags": [ "kicad", "pcb",
skills/kicad-bridge-dev/SKILL.md+34@@ -978,3 +978,37 @@ plus the rejection checks (wrong net, stale revision, crossing route, dry run) a / Ctrl+Y on the PCB Editor window. Evidence goes to `demo/routing/evidence/<box>-<date>.json`. Container tests: `PYTHONPATH=<linux pip target of requirements-routing.txt> python3 -m unittest discover -s tests` (the vendored `routing_deps` are Windows wheels; the container needs its own target).+++## Release-day lessons, 2026-09-07 (0.9.340 to 0.9.347, measured on arav-rog and winvm)++- **Never click a dialog button with a plain SendMessage (#83).** KiCad's first-run wizard opens its+ "Are you sure?" Confirmation modally inside the Cancel handler, so a synchronous BM_CLICK never+ returns and the sweep that would answer the follow-up is the thing blocked. `SendMessageTimeoutW`+ (SMTO_ABORTIFHUNG, 1.5 s) delivers the click and returns; both sweep loops stop after 25 s.+- **With two pcbnew processes, ask the one that owns the window (#81).** `_resolve_plugin("pcbnew")`+ picks the newest instance; a stray untitled PCB Editor has no Footprint Editor frame, so the+ Library Tree toggle went nowhere and every background load typed into a hidden tree. Resolve by+ the pid of the hwnd you are driving (`GetWindowThreadProcessId`), fall back to newest.+- **Stock library variables resolve to the INSTALLED KiCad (#80).** `${KICAD10_SYMBOL_DIR}` and+ friends are `<base_dir>/share/kicad/{symbols,footprints,3dmodels}`, never Documents; Configure+ Paths overrides in kicad_common.json `environment.vars` win. Per-user installs live under+ `%LOCALAPPDATA%/Programs/KiCad`, so never hardcode Program Files.+- **A positive detection cache must re-check the exe (#82).** Uninstalling KiCad while the bridge+ runs kept readiness at detected:true; readiness and list_versions now stat the cached kicad.exe+ and re-detect when it is gone.+- **kicad_close semantics (#84).** A dirty editor answers WM_CLOSE with "Save Changes?"; the old+ code waited 5 s and force-killed. Now: report `unsaved_changes` with the dialog text and leave+ it; `discardChanges:true` presses Discard (the Win32 BM_CLICK on the dialog's button works, UIA+ reports the control not_invokable); `force:true` is the only kill.+- **Footprints installed while the editor is open do NOT need a KiCad restart (#51, corrects #47).**+ View > Refresh reloads the tree; the load succeeds on the second pass on the same process+ (18 s cold, 6 s warm). `kicad_rescan_libraries {footprints:[...]}` proves it by loading each part.+ The in-process `probe_footprint` cannot enumerate on KiCad 10 (module-level API has no+ FootprintEnumerate), so it is not an oracle there.+- **The post-verb sweep also expires a Save prompt the close verb left up.** It falls through to+ Escape + WM_CLOSE, which is Cancel: the editor stays open, nothing lost. Do not rely on a dialog+ staying up after a verb returns.+- **A headless VM hands new windows the foreground by itself.** With no console user, every+ background launch measures at z=0; that is the environment, not a focus steal (see the test+ skill's victim rule).
skills/kicad-bridge-publish/SKILL.md+23@@ -219,3 +219,26 @@ with that page's skills package (adom/wiki#170). The zip stays here. box tell the other threads, or expect your staged build to vanish. - After a build, push the non-runtime source too (tests/, demo/, tools/, RELEASE_NOTES.md): the release tool pushes only what the zip ships.+++## Repo pushes and caches, 2026-09-07 (#79, #86)++- **Twenty releases shipped handlers that never reached master.** The release tool pushed sources+ in chunks of 40 with `check=False`, and the chunk carrying `certs/cacert.pem` always failed:+ the wiki's secret scanner rejects every `.pem`, and one rejected file fails the whole chunk.+ "certs" sorts right before "handlers", so demo.py, kicad_ui.py, kicad_windows.py,+ install_footprint.py and open_footprint_editor.py rode that chunk. Now `push_exclude` in+ tools/release_files.json keeps the CA bundle out of pushes, every push reply is checked, and a+ failed chunk refuses the release. After a release, diff a fresh `adom-wiki repo download` of+ master against the zip's file list; they must match.+- **Stage backups OUTSIDE bridges-cache.** ab discovery adopts any subfolder that holds a+ bridge.json as a bridge (adom-bridge#161, fixed in ab 2.1.71: such folders now list as `ignored`+ with the reason): a `kicad-release-backup-*` copy next to the real cache showed up in bridge_list+ as the kicad bridge with the wrong version. Back up to `%LOCALAPPDATA%/Adom Bridge/bridge-backups/`,+ which is also ab's documented rule now.+- **Staging chain that works:** `bridge_dev_mode on` (note: does not stop an explicit+ bridge_install, adom-bridge#159), `bridge_kill {confirm:true}` (a dashboard poll can respawn+ the old process; check bridgeVersion after resume and kill again if stale), PowerShell+ Copy-Item backup + Expand-Archive -Force, write `.bridge-version`, `bridge_resume`, then test,+ then `build_release.py <ver> --publish --reuse-zip`, then unpin and `bridge_install` from the+ tier manifest so the box follows the tier again.
skills/kicad-bridge-test/SKILL.md+21@@ -114,3 +114,24 @@ Manual driving unchanged: run the one command, read `report.md`. upgrade changed CLI flags; `kicad_diagnostics` first. - **Coverage gap listed** — someone (you) added a verb without a test. Add a matrix entry or a justified skip; that is the contract.+++## Runner changes, 2026-09-07 (#78, #81, #85)++- **Coverage is complete against the live catalog:** every verb has a matrix entry or a stated+ skip (install_library_bundle, pcm_install/uninstall, rescan_libraries, set_design_rules,+ set_settings, and the routing verbs, which tests/ and demo/routing/run_demo.py cover).+- **The Windows user comes from the box** (kicad_diagnostics paths, then status); the runner+ refuses to guess `john`.+- **Phase 4.5** runs make_part_project and export_part after the phase-4 installs create+ ADOM_VERBTEST (#85: export used to sort before install and fail falsely).+- **A foreground steal needs a victim.** The runner records the foreground title before each GUI+ verb; KiCad on top afterwards counts only when a non-KiCad user window was displaced. Otherwise+ it lands in `foreground_notes` (a headless VM with no console user gives Windows every new window+ the foreground by itself).+- **bridge_call pings pcbnew.** KiCad 9/10 eeschema has no Python scripting, so the plugin can only+ live in the PCB side; `plugin_not_running` for eeschema is correct, not a failure.+- **trace_net traces the first real net** kicad_extract_netlist reports for the fixture;+ list_symbols Device and list_footprints Resistor_SMD are permanent stock-library regression checks.+- **Full replies are kept** under results[verb].response; response_head is only the summary.+- The rp2040 fixture (tour-pack-rp2040/template/*) ships in the repo; it had never been pushed.
skills/kicad-interaction/SKILL.md+10@@ -163,3 +163,13 @@ if ! curl -sf http://127.0.0.1:8766/health >/dev/null 2>&1; then fi adom-desktop ping ```+++## Closing KiCad with unsaved work (0.9.347)++`kicad_close {}` never kills an editor that is asking to save. It returns `success:false`,+`errorCode:"unsaved_changes"` and the dialog text, and leaves the editor open (the post-verb sweep+cancels the prompt, so the user's work stays where it is). Ask the user, then either save in KiCad+(Ctrl+S through desktop_press_key) and close again, or `kicad_close {"discardChanges":true}` to+press Discard for them. `force:true` kills the process and discards silently; use it only for a+disposable fixture or when the user said so.