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.
Releases 350
Standalone per-platform binaries to download and run, no tools needed. The newest is pinned on top.
Stable link for websites and docs: /download/adom/kicad-bridge/latest
All releases showing 281-300 of 350
The 10.0.5 demo-beat mystery, root cause at last (verified with in-process menu introspection): the PM menu ids are UNCHANGED (20011/20013 confirmed live via the plugin's get_menu_ids), and the in-process wm_command 20011 opens the Symbol Editor fine even on a project-loaded PM. What broke the chain: tier 1a posts eeschema's menu id 20390, the post lands 'successfully' but opens nothing (stale id), and the tier treated a successful POST as terminal, never trying tier 1b (the working PM route) before falling to the external PostMessage tier, which a project-loaded 10.0.5 PM ignores. Tier 1 now treats the WINDOW APPEARING as the only success signal and always falls through to the PM in-process post (with plugin bind-wait) when no window shows.
KiCad 10.0.5 root cause closed: external cross-process WM_COMMAND to the Project Manager no longer opens editors, and the PM menu is no longer a native Win32 menu, so the in-process plugin post is the only working route from a running PM. That plugin takes a few seconds to bind after PM spawn, and tier 1 gave up after a single probe, which is exactly the race the background demo job hit (its beats run back-to-back). Tier 1 now retries the plugin post for up to 15s. Staged and manual calls always passed because human pacing gave the plugin time to bind.
Hotfix for 0.9.125: find_menu_command returns (cmd_id, label) and the new PM tiers passed the whole tuple into PostMessageW, a ctypes ArgumentError that killed the demo job at beat 1. Proper unpacking in both editors' PM tiers.
KiCad 10.0.5 renumbered the Project Manager menu command ids the bridge had hardcoded (20011 Symbol Editor, 20013 Footprint Editor) - the WM_COMMAND tier fired into nothing and the demo's first three beats died in background mode. Both PM tiers now resolve the command id from the window's REAL menu bar via the win32 menu walk (the 0.9.99 doctrine), with the old ids as last-resort fallback. Numeric menu ids are never to be trusted across KiCad versions.
Cold-start hardening: the project-manager WM_COMMAND route waited only 6s for the Symbol Editor to appear, and a cold KiCad 10.0.5 can take 15s+ when the demo job runs beats back-to-back. The wait is now 30s with a one-time command repost at the 10s mark. This was the root of the demo's beats 1-3 failing in background mode on 10.0.5 (staged mode passed because human-paced calls gave KiCad time).
Failed kicad_demo beats now carry failReason {handlerSuccess, error, output} in result.steps and log the raw step result to stderr. The prior summary discarded the underlying error, which made background-mode beat failures undiagnosable from the outside.
Background demo beats now run the modal-dialog sweep before their retry. Staged demo calls always got the dispatcher's post-verb dialog sweep, but the background job's internal steps did not, and KiCad 10.0.5 introduced a dialog at editor-open that stalled the first three beats (they only recovered in past runs because the caller's progress polls happened to sweep). The blocking dialog is also logged to stderr when hit.
stepShot fix: 0.9.120 keyed the per-step capture off the beat's title field, which is the display label ('1/6 - Schematic symbol'), not a window title, so no frame ever matched a window and zero stepShots streamed. The capture now uses the beat's window field. Caught by the live verification run before the web-control page ever saw a frame.
kicad_demo background jobs now stream per-step screenshot EVIDENCE to the caller: at each beat's completion the bridge captures that beat's own window (it alone knows the moment and the surface) and the next progress poll carries stepShot {step, title, image} (base64 PNG, 640px cap), one per completed step. This implements the web-control contract from #25: the page pins each frame as the step's evidence and stops taking its own racy guess-snaps. The final result.state.shots gallery is unchanged (DURING evidence + AFTER evidence compose).
The major.minor detection string ('10.0') cannot distinguish point releases, and that blindness lived in three places found during the fleet upgrade to KiCad 10.0.5: (1) install ranking, a freshly installed per-user 10.0.5 lost to an old Program Files 10.0.1 because both read '10.0', the bridge now probes kicad-cli version per install (cached) and ranks by full X.Y.Z; (2) check_for_updates compared '10.0' to '10.0.5' and reported an upgrade forever; (3) kicad_upgrade's post-install verification could never see its own success. Also: the update-nudge's cached installed version is invalidated after a successful upgrade.
Fix for the 0.9.116 update nudge: readiness and bridge_status return through early dispatcher paths and never reached the injection point, so the kicadUpdate field never appeared. The attachment now lives at the HTTP funnel every response passes through.
Proactive KiCad update nudge: the bridge now checks the latest stable KiCad at most once per 24h (async, never delaying a verb) and, when the installed version is behind, attaches kicadUpdate {installed, latest, _hint} to the everyday status verbs (status, readiness, state, bridge_status, window_info). The hint tells the AI to OFFER the user the update, close KiCad, then run kicad_upgrade (official installer, silent, per-user, no UAC), never mid-design-work. Point releases are compared properly now: the installed version comes from kicad-cli version (X.Y.Z), not the major.minor detection string.
Focus sentinel classifier fix: recent keyboard/mouse input anywhere wrongly counted as user intent, so a KiCad self-raise WHILE the user typed in another app (the most disruptive case, caught live on ConfRoomROG over RustDesk) was left in the foreground. A foreground transition now only counts as user-initiated when a mouse click landed with the cursor on that window, or an alt-tab was in progress. Everything else bounces.
Focus sentinel refinement: the bridge's own SANCTIONED foreground paths (foreground:true via bring_to_user, and the allowForeground last resorts which always announce with a toast first) now set expect_foreground(), so the always-on sentinel never bounces a foreground the user explicitly asked for. Sentinel log gains a sanctioned-foreground (allowed) event type.
Always-on focus sentinel: the per-verb guardians prevent foreground steals while a verb runs, but they expire, and KiCad windows self-raise LATE (a 3D render or footprint-library load finishing minutes after the verb). John caught such flashes live. The sentinel watches foreground transitions for the bridge process lifetime: a KiCad window reaching the foreground with NO user input in the preceding 1.2s is a self-raise and gets minimize-bounced back (never touching any user window); one preceded by user input is the human's own click and is left alone. Every transition is logged to kicad_state.focusEvents and stderr (bridge-logs), so background-contract compliance is now provable from the log instead of sampled by callers.
kicad_make_part_project now generates SINGLE-COMPONENT demo projects: just the part on the sheet (stub wires off its pins) and just its footprint centered in tight edge cuts with two copper stubs. The synthetic 330R companion is gone (extra components on a one-part demo board confuse the user). The reference designator now comes from the part's own Reference property, so a diode is D1 and a capacitor is C1. Result gains a 'reference' field.
faulthandler.enable(all_threads=True) at server boot (issue #27): a native ctypes/GDI fault now dumps every thread's Python stack to stderr, and ab 2.0.44+ captures bridge stderr into ~/.adom/bridge-logs/kicad.log, so the next hard crash leaves a usable trace instead of a silent dead port.
Screenshots no longer require PIL: ab 2.0.44+'s managed Python runtime is stdlib-only, and on a fresh box every capture fell back to .bmp, which kicad_state rejects - so a brand-new install had zero working captures. handlers/png_stdlib.py now encodes the GDI BGRA buffer straight to PNG (zlib + struct, nearest-neighbor downscale to 1568px, ~0.3s/frame) whenever PIL is absent. Found running kicad_demo on ConfRoomROG's first-ever bridge boot.
New verb kicad_export_part {partName}: writes one-off single-entry library files for an installed part (a .kicad_sym containing ONLY that symbol, a .pretty containing ONLY that footprint, and the bare 3D model), the reverse of install, proving per-asset round-trip. kicad_make_part_project now generates part-dominant boards (tight edge cuts sized from the footprint) so the part's 3D model is clearly visible in the 3D board view instead of being a speck. kicad_uninstall also removes adom-part-exports and adom-part-staging.