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 2 file(s)
2 files changed
+107
dev-skills/kicad-bridge-dev.md+9@@ -44,3 +44,12 @@ A reverse bridge AD spawns on the user's laptop (`spawn.kind: python`, `entrypoi ## Testing on a fresh AD / VM `refresh_bridges {name:kicad}` pulls the new cache; the RUNNING instance keeps its old code until it dies — `bridge_kill {name:kicad}` forces a fresh spawn that loads the new version and re-detects. The first verb after a kill returns a `bridge_starting` envelope — retry. Confirm the running version via `bridge_log_read` ("starting v0.9.xx").+++## Where the full, current version lives++This file is the source-only stub. The COMPLETE developer skill, including the+publish ritual, the verification discipline, and the plugin-payload upgrade+rules, is `skills/kicad-bridge-dev/SKILL.md` in this repo. Read that one before+changing bridge code; it is the file that gets installed into a developer's+~/.claude/skills and it is kept current with each release.
skills/kicad-bridge-dev/SKILL.md+98@@ -385,3 +385,101 @@ plugin-free path exists." It was a red herring — the Win32 menu API sees the m perfectly. When a UIA walk comes back empty, try GetMenu before concluding the control is unreachable. (Also: PowerShell P/Invoke through shell_execute is quoting-hell; write the ctypes walk in a bridge handler and test via the verb.)++## 🚢 The publish ritual (every release, in this order)++Nothing reaches a user until all four steps run. Skipping the last one is the most+common way a "fixed" bug is still broken on the box that reported it.++```bash+# 1. bump BOTH, they must agree+echo -n "0.9.NNN" > BRIDGE_VERSION+# and "version" in bridge.json++# 2. build the runtime zip from the SHIPPING file list (never `zip -r .`)+# resources/ is always included; skills/, demo/, docs/, dashboard/, *.md+# except SKILL.md, and images are not part of the runtime++# 3. sha256 + size into adom-bridge-kicad-manifest.json, then+adom-wiki repo push adom/kicad-bridge --files BRIDGE_VERSION bridge.json \+ adom-bridge-kicad-manifest.json <changed sources>+adom-wiki release create adom/kicad-bridge 0.9.NNN+adom-wiki release upload adom/kicad-bridge 0.9.NNN <zip>++# 4. INSTALL IT. refresh_bridges does NOT pull a new release.+adom-bridge --target <BOX> bridge_install \+ '{"manifestUrl":"https://wiki.adom.inc/api/v1/pages/kicad-bridge/files/adom-bridge-kicad-manifest.json",+ "force":true,"reason":"..."}'+```++Then confirm what is actually RUNNING, not what you published:+`kicad_status` returns `bridgeVersion`. A box silently one version behind has+wasted more of this project's time than any single bug.++The CONTAINER package (skills + the dashboard launcher) is a separate layer:+`adom-wiki pkg publish --org adom` after bumping `package.json`. Publishing the+package does NOT push the page repo, and pushing the page repo does NOT publish+the package. Two layers, two commands, every time.++## 🧭 Verification discipline (learned the hard way, 2026-08-19/20)++Every one of these came from shipping something that looked verified and was not.++**Your container is not a user's container.** `kicad-dashboard` "existed" for+months as a 104-byte hand-written wrapper pointing at a dev clone, so `skip_if:+command -v kicad-dashboard` reported SKIP on the maintainer's box and RUN on+every user's - the dock died with exit 127 for everyone else. Test packaging from+a genuinely clean state: delete the installed tree AND the launcher, then install+from the wiki. `adom-wiki pkg install` no-ops when the registry already lists the+current version, so deleting files alone does not re-run `install.sh`.++**"It works on my box" is close to no evidence.** Three separate bugs were+invisible here because the maintainer's environment differed: a dev-clone+wrapper, a 245-byte stub footprint standing in for a user's 2 KB file, and a+KiCad that restarts many times a day where the user's had been up for hours.+Before claiming a part loads, compare BYTES (size + sha256), not names.++**Never test against a machine somebody is using.** KiCad is single-instance. A+human clicking in it while a sweep runs produces failures indistinguishable from+races - one whole day went into chasing a "cold open bug" that was the maintainer+using KiCad in another window. Automated verification belongs on an idle box; the+user's daily machine is for SHOWING them the result.++**A verb must never report what it did not verify for THAT request.** This class+has shipped four times here in one week:+ - a show verb reported success and the caller screenshotted the project window+ - a title check used a SUBSTRING, so "RP2040" matched "AdomRP2040:ADOM_MECHANICAL_PIN"+ - a focus-steal path returned success for having typed, with the previous part on screen+ - a progress registry keyed on phase alone served one caller another caller's steps+A hard failure is recoverable; a false success is not, because nothing downstream+has any reason to look again. When adding a verb, ask what would make its success+claim FALSE, and check that thing specifically.++**A diagnosis about a thing must first establish the thing exists.** The bridge+reported "your editor's library index is stale" when no editor was open at all,+and a plugin probe reported "KiCad refuses to load it" when the probe's own+adapter had returned None. Keep probe failures (`probeError`) strictly separate+from host-app verdicts.++**A window existing is not a window having painted.** Title verification returns+true well before KiCad draws anything, so evidence captured at that moment can be+structurally perfect and visually empty. `evidence.canvasRendered` samples the+real `wxGLCanvas` child rect; the capture polls for paint before returning.++## 🔌 Plugin payload upgrades reach a RUNNING KiCad only on restart++The payload is imported into the KiCad process and held by the RPC server thread+for its life. Updating the bridge on disk does NOT change what a running pcbnew+executes, and KiCad's own **Tools > External Plugins > Refresh Plugins** (menu id+20593) does not swap it either - measured, 2026-08-20: the payload is not an+action plugin, and Python returns the cached `sys.modules` entry on re-import.++The only symptom is `unknown method: <new_rpc>`, which reads like a missing+feature rather than a stale process. Call `kicad_bridge_call {method:+"payload_marker"}` to see the payload version actually in memory; if it trails+the installed bridge, that KiCad needs restarting and no amount of updating will+help.++Corollary worth remembering: **an upgrade path has to ship before it is needed.**+Anything added to the payload today is unreachable on every KiCad already+running an older one, which is an argument for adding it now, not later.