app
Altium Bridge: AI for Altium Designer
Public Made by Adomby adom
Let an AI (Claude, ChatGPT, Codex or any agent) run Altium Designer for you: create symbols and footprints, place parts (also from Altium 365), wire and annotate schematics, Update PCB, set the stack-up and rules, route, pour copper, add mounting holes and stitching vias, run ERC and DRC, and make Gerbers, BOMs and STEP. Free in Hydrogen; bring your own AI and Altium licence.
← Commit history
0.2.66 source, docs: the README names every verb (generated by tools/readme_verbs.py, release.py refuses a stale list); page title, brief, intro, tags and discovery triggers rewritten for search (AI for Altium Designer)
7 files changed
+411−102
CHANGELOG.md+2@@ -10,6 +10,8 @@ - A pad's mask and paste expansion are written through the pad cache. Writing `Pad.SolderMaskExpansion` directly crashed Altium Develop (an access violation in ScriptingSystem.DLL); the release lint now refuses it, and `MidXSize` stays refused. - Altium's crash-report box ("Access violation ...", TShowException) is catalogued. The bridge closes it like its title-bar X and never presses Send and Close, which would send a report to Altium. (Escape closed it on the laptop; the close path in the bridge has not met a live crash box yet.) - `altium_sch_connect {kind:"noerc"}`: a No ERC marker on a pin's outer end, for a pin left open on purpose (no wire, no net). Measured: two markers on U3, compile reported neither (a marker placed off any pin was reported as "Floating No ERC").+- The README names every verb: `tools/readme_verbs.py` writes the full list from the bridge's own catalog (by area, each with its one-line summary) and keeps every "N verbs" count right; `scripts/release.py` refuses a release whose list is stale. 14 verbs had never been named on the page.+- The page reads for search: title "Altium Bridge: AI for Altium Designer", a plain-words brief and README intro (what the AI does in Altium, free in Hydrogen, bring your own AI and licence), and more tags and discovery triggers ("altium ai", "chatgpt altium", "claude altium", "altium mcp", "altium stitching vias", ...). - Verb battery: `sch_connect` adds a No ERC marker (3 connections must land). - Verb battery: `board_features` on the lane board (2 mm corner holes, a fiducial, 4 stitching vias; all 9 must land). - Verb battery: `create_symbol` makes a dual op-amp from pin objects with hidden power pins and checks all 8 pins and both parts arrive.
README.md+228−90@@ -1,10 +1,24 @@-# Adom Bridge — Altium Bridge+# Altium Bridge: AI for Altium Designer -A **reverse bridge** that lets Adom Bridge (ab) — and the AI driving it — control the user's own-Altium Designer on Windows: open and drive every design surface, author native-`.SchLib`/`.PcbLib` libraries (symbols, footprints, STEP 3D bodies), place parts on schematics and-boards, run compile/ERC and DRC, run OutJobs (Gerber, ODB++, NC drill, BOM, pick-and-place), and-screenshot any window back to the AI.+Let an AI assistant (Claude, ChatGPT, Codex or any agent) run **Altium Designer** for you, inside your own+normal session. Ask in plain words and it:++- creates schematic symbols (multi-part too) and PCB footprints with STEP 3D bodies and Mouser / DigiKey / LCSC numbers+- places parts on a sheet, including parts from your Altium 365 workspace, then wires, annotates and swaps them+- runs Update PCB with the whole change order previewed first, keeping board-only parts+- sets up the board: stack-up (2 to 4 layers, planes), net classes, diff pairs, design rules, outline+- places and routes: moves and rotates parts, finds free space, routes nets, pours copper, adds mounting holes,+ fiducials and stitching vias+- checks the design: compile and ERC, DRC with every violation's location, a 14-check design review+- makes the outputs: Gerbers, NC drill, pick and place, BOMs grouped by MPN (JLCPCB, Mouser, DigiKey files),+ schematic PDF and STEP, checking that the outline and every copper layer reached the Gerbers++174 commands, tested on Altium Designer 26.11 and Altium Designer Develop. It runs in **Hydrogen**, Adom's free+desktop app, through Adom Bridge. You bring your own AI subscription and your own Altium licence.++**How it works:** a reverse bridge lets Adom Bridge (ab), and the AI driving it, control the user's own Altium+Designer on Windows through Altium's own scripting engine (a resident DelphiScript agent), its 1,100 built-in+commands and UI Automation, and screenshot any window back to the AI. **Keyword:** say **altium** to the AI to reach this bridge. It matches the bridge name `altium` and the verb prefix `altium_`.@@ -151,90 +165,214 @@ Modal dialogs freeze the script engine, so every mutating verb scans for dialogs returns them with body screenshots (Altium paints dialog text; it is not exposed as text). A halted engine (DelphiScript runtime errors are modal) recovers with `altium_agent_recover`. -## Verb reference--**Board & schematic introspection (0.1.11):** `list_designators`, `component_data`, `component_pins`, `list_nets`, `net_connections`, `layers`, `copper_layers`, `read_rules`, `set_layer_visibility`, `footprint_primitives`, `schematic_data` — read the live design as data (pads→nets, rules, layers, sheet components with pins), all in tens of milliseconds, no dialogs.---All 174 verbs (prefix `altium_`). Call `altium_describe` for the live catalog.--**Readiness & lifecycle** — `readiness`, `status`, `launch`, `close`, `diagnostics`, `progress`,-`agent_start/_stop/_status/_recover`, `license`, `signin_status`, `connect_workspace`, `uninstall`.-`agent_status` reports the resident loop (`alive`, `responsive`, `residentAnywhere`,-`liveWorkspaces[]`, heartbeat). `license_status` (licence state in plain words plus a frame of-the License Management page), `ensure_licensed` (launch if needed, claim a seat, or name the-human step; `launchWaitSec`, `allowSignInReset`, `allowTrial`) and `setup_trial` (returns the-one next onboarding action) are covered in the `altium-licensing` skill.--`selftest_script_error` (from 0.2.23) proves the script-error safety net on this machine: it makes the-agent raise a real DelphiScript runtime error and answers `netWorks: true` when the bridge photographed-Altium's error box, stopped the halted script itself and left no dialog behind. Any verb that hits a script-error returns `errorCode: agent_script_error` with `errorShot` (a PNG of Altium's message) instead of timing out.--**Lifecycle** — `launch` (hands the user's foreground window back unless `background:false`),-`close` (polite, releases the licence seat; `discardChanges:true` answers the save prompt in full-and escapes a wedged instance), `instances`, `install`, `uninstall`--**Surfaces** — `show_project`, `show_schematic`, `show_2d_board`, `show_3d_board`, `show_library`,-`show_symbol`, `show_footprint`, `show_3d_chip`, `open_document`, `close_document` (`path`; closes-one open document through its handle, never saves), `state`, `demo`, `animate_view` (camera/zoom-choreography run in-bridge: `preset` punch_in | showcase3d | orbit | flip | finale and/or-`steps[]`, `lane` pcb | sch, `pauseMs`), `foreground` (raise Altium for a user who asked to-watch; `reason` of 10+ characters is required; the reply says whether Altium is `visiblyOnTop`).-`show_schematic {filePath}` opens a .SchDoc in the background, zooms to fit and returns the frame.--**Engine** — `eval`, `run_command`, `list_commands`, `run_script`--**Checks & outputs** — `compile` (`run_erc`), `run_drc`, `run_outjob`, `export_gerber`, `export_bom`--**Author libraries** — `create_symbol`, `create_footprint`, `add_body` (STEP or extruded, persisted-and centred on the pads), `set_params`, `build_footprint` (a whole footprint from a-`tools/kicad2altium.py` spec: via pads by duplicate designator, rounded-rect pads, named mechanical-layers), `build_symbol_modes` (one symbol, N display modes) + `symbol_mode` (switch + frame),-`add_models` (N footprint variants on one part — the CHANGE PACKAGE equivalent),-`install_library`, `compile_intlib`, `extract_intlib`, `list_library`, `save`,-`install_library_bundle` + `install_receipt` (the last bundle install's full receipt, for a-client whose call outlived ab's budget), `set_models` (from 0.2.15: replace every footprint-model on a symbol with one PCBLIB model; `set_params` footprint and `add_models` append)--**Chip outline on the symbol (from 0.2.15)** — `add_symbol_art {libraryPath, symbolName, kicadSym,-clear?, mode?}` reads the chip-outline polylines adom-symbol baked into the KiCad symbol, maps-the KiCad body rectangle onto the SchLib component's rectangle and draws them, so the Altium-symbol shows the same chip as the KiCad and Fusion ones. `kicadSym` is a Windows path on the-Altium box (stage it with `send_files`). `clear` (default true) removes the component's-existing lines and polylines first, so a re-run replaces instead of stacking; `mode` is `lines`-(default, eLine segments) or `polyline`. `symbol_prims {libraryPath, symbolName, models?}` is-the read-only check: primitive counts by kind, `bodyRectMil`, `polyBboxMil`, and the footprint-models with `models:true` (off by default; the model walk halts the engine on some builds).--**Heatsink vias (from 0.2.20)** — `plate_vias {libraryPath, footprintName?}` turns every drilled-pad in a PcbLib that loaded on the Top Layer into a plated Multi-Layer pad. Run it once after-installing a library whose thermal-pad vias were written as pads with a hole (adom-lbr before-2.46.1), then `altium_save` the PcbLib. Replies `holes`, `plated`, `fixed`.--**Manipulate libraries** — `clone_symbol` (all display modes carried), `rename_symbol`,-`remove_symbol`, `read_symbol` (pins/params/modes read-back), `copy_footprint` (pads + bodies +-drawing), `rename_footprint`, `remove_footprint`, `xcopy_footprint` (cross-library), `cleanup_libs`, `set_visibility`, `normalize_bodies`, and `import_part` — one call: footprint spec + STEP + symbol + vendor params (Mouser preferred, DigiKey, LCSC)--**Boards & placement** — `place_on_sch`, `place_on_pcb`, `test_board` (fresh PcbDoc, board shape-sized to the part, nets + stub tracks), `board_shape`, `swap_footprint` (change the package on a-placed part; wiring survives), `pcb_report` (ground truth: pads, bodies, nets, tracks with bboxes)--**Whole-design reads & review** — `read_board` (one agent round trip: components, nets, layers,-copper, rules, occupancy, outline; `sections`, `limit`, `raw`), with `board_summary`,-`rules_by_kind` and `layers_in_use` shaped from the same read; `read_schematic` (components of-the current sheet; `sections`, `params`, `limit`); `cross_check {board?, sheet?}` (designators-on the sheet but not the board and the reverse); `review_board {board?, sheet?,-includeSchematic?, checks?}` (14 design-review checks, partial results by design: `skipped`-and `notImplemented` say what did not run)--**Dialogs & desktop** — `check_dialogs`, `dismiss_dialogs`, `dialog_log` (what the standing-dialog reaper dismissed; `limit`, default 25)--**Altium 365** — `a365_configure`, `a365_status`, `a365_query`, `a365_oauth_begin` / `_status` /-`_cancel`, `a365_refresh`, `a365_logout`, `a365_files_upload`, `a365_library_overview`,-`a365_library_schema`. Works with Altium Designer closed; tokens stay in the bridge cache and-never appear in a reply. See the `altium-a365` skill.+## Every verb++<!-- verbs:start (tools/readme_verbs.py writes this list) -->++All 174 verbs, by area (prefix `altium_`). `altium_describe` returns the live catalog with every input, output, hint and example.++### Running Altium: launch, close, health, dialogs++- `altium_readiness`: The one-call gate: is Altium installed, running, licensed, and is the resident agent alive? Answers with Altium closed and never touches the script engine.+- `altium_status`: Is Altium running, licensed, and is the resident agent alive?+- `altium_diagnostics`: Bridge-side facts for a bug report: environment variables, every Altium install found, Altium's windows, the agent status block and the cache directory.+- `altium_window_info`: Altium's top-level windows plus any open dialogs, without screenshots.+- `altium_state`: The whole picture in one call: licence state, windows, dialogs, a screenshot of every main/dialog window, and the agent's logical state (focused document, focused project, open documents).+- `altium_check_dialogs`: List every Altium dialog currently open, classified, each with a screenshot (the only way to READ one: Altium paints its dialog text).+- `altium_dismiss_dialogs`: Press one named button (default OK) on the detected Altium dialogs through UIA - no cursor, no focus steal.+- `altium_launch`: Start Altium (the newest numbered install, or the one install names) and wait for its main window, then hand the user's own window back.+- `altium_close`: Polite close (releases the licence seat).+- `altium_instances`: Every running Altium (Designer + Designer Develop can run together).+- `altium_dialog_log`: What the standing dialog reaper (and the bridge's own recoveries) pressed, newest last: nuisance boxes, script-error boxes, discarded save prompts, silent engine halts cleared.+- `altium_uninstall`: Remove the bridge's own cache directory (agent workspaces, rendered agent scripts, the Altium 365 token file).+- `altium_describe`: This list - the bridge's verbs and schemas for ab's Verbs tab.+- `altium_panel`: Activate a docked panel TAB (SCH Library, PCB Library, Components, Projects, Properties) in the BACKGROUND - the 'ganged-up view' needs the right panels in front, and no Altium server process switches a tab.+- `altium_list_installed_libraries`: Every library in Altium's Installed Libraries list (read-only).+- `altium_uninstall_library`: Remove libraries from Altium's Installed Libraries: the inverse of install_library / install_library_bundle.++### Scripting: DelphiScript, Altium commands, documents++- `altium_agent_start`: Bootstrap the resident DelphiScript agent inside Altium (renders the script, runs it through the -R lane, waits for the heartbeat).+- `altium_agent_stop`: Stop the selected instance's resident agent loop (drops a stop file and waits up to 12 s for the heartbeat to go stale).+- `altium_agent_status`: Is the agent loop alive and responsive, in which workspace, and is any loop resident anywhere? Read-only; never starts the agent.+- `altium_agent_recover`: Un-halt the script engine: clear the PCB transaction, press OK on open Altium dialogs, send EditScript:Stop, reap the busy notice and delete stale request files.+- `altium_eval`: Run a DelphiScript snippet inside Altium (optional Var block, then Begin ...+- `altium_run_command`: Run an Altium process (Server:Command) through the agent, on the CURRENT document or on filePath opened first.+- `altium_run_script`: One shot: run a procedure of YOUR OWN .PrjScr through Altium's -R command line.+- `altium_list_commands`: Search Altium's process-launcher catalog (about 1,100 Server:Command entries parsed from the install's System/*.rcs files) by text and/or server.+- `altium_open_document`: Open a document or project by path through the agent and show it without focusing it.+- `altium_open_project`: Open a project (.PrjPcb / .PrjScr / .PrjMbd / .PrjHar / .LibPkg) by path.+- `altium_close_document`: Close ONE open document by path through its document handle.+- `altium_activate_document`: Make a document current - the quiet lane (one in-process agent call, no cursor, no OS foreground).+- `altium_progress`: The bridge's timing book: phases in flight right now (percent/ETA blocks ab paints on the taskbar), measured phase history and per-verb run statistics.++### Reading and setting up the design++- `altium_read_board`: ONE round trip: components, nets, layers, copper, rules, occupancy, outline.+- `altium_board_summary`: One-screen summary of the current board, shaped from one read_board round trip: component counts by side, nets, copper layers actually in use, rule counts.+- `altium_rules_by_kind`: The current board's ENABLED design rules grouped by rule kind (Clearance, Width, RoutingVias, ...), each group sorted by priority.+- `altium_layers_in_use`: Which layers of the current board actually carry primitives: copper layers with copper (densest first) and every layer with anything on it.+- `altium_read_schematic`: Components on the CURRENT schematic sheet (designator, library reference, comment, position, parameters) in one agent round trip.+- `altium_cross_check`: Compare one schematic sheet's designators with a board's.+- `altium_review_board`: Design-review checks (14) over one board read; schematic checks with includeSchematic.+- `altium_list_designators`: Every component designator on the current board.+- `altium_component_data`: Placement data for one board component, or for all of them: footprint pattern, comment, layer/side, position, rotation, size, pad count and the nets on its pads.+- `altium_component_pins`: Every pad of one board component with its net, position, layer, size and hole.+- `altium_list_nets`: Every net on the current board with its pad count.+- `altium_net_connections`: Every pad on the board with its net and owner (Designator.Pad), plus a bounding span and the airline length (minimum spanning tree over its pads, airlineMm) per net.+- `altium_layers`: The current board's layer set with ids, names, kind and whether each is displayed.+- `altium_copper_layers`: Every copper layer Altium can address on the current board (top, mid 1-30, planes 1-16, bottom) with names and visibility.+- `altium_read_rules`: Every design rule on the current board, flat, disabled ones included: name, kind ordinal, enabled, priority, both scope expressions, comment, and Altium's descriptor with the rule's VALUES (e.g. 'Clearance Constraint (Gap=6mil) (All),(All)').+- `altium_set_layer_visibility`: Show or hide one layer of the current board (by layer id) and refresh the view and the layer tabs.+- `altium_footprint_primitives`: Geometry dump of one PLACED component: its tracks, arcs, pads (with solder and paste mask expansion in um) and texts in mils with layer ids; other primitive kinds are counted.+- `altium_schematic_data`: Components on a schematic sheet (filePath, else the CURRENT sheet) with their pins (number, name, electrical type), position and orientation.+- `altium_layer_stack`: The CURRENT board's stack-up: copper layers in order with copper thickness and the dielectric under each (height, constant, material), and the total thickness.+- `altium_net_classes`: Net classes on the current board: list them with their nets, or make one (replacing a class of that name) with an optional width and clearance rule scoped to it, or remove one with its rules.+- `altium_diff_pairs`: Differential pairs on the current board: list them, define one from two nets (replacing a pair of that name), or remove one.+- `altium_board_outline`: Draw the board shape as tracks and arcs on a mechanical layer: the outline a fab house reads from the Gerbers.+- `altium_set_track_width`: Set the width of the EXISTING tracks and arcs on nets or a net class (rules only steer new routing).+- `altium_find_space`: Free spots on the board for a part near another (clear of every other part on that side, of that side's tracks and vias, and inside the outline), nearest first; or check:true lists parts that already overlap or leave the outline.+- `altium_selection`: What the user has selected in the current board (components with position mm, rotation, side, footprint, size) or sheet (components with location mils and orientation).+- `altium_check_orientation`: Advisory: 2-pad parts whose rotation could be better.+- `altium_replicate_layout`: Copy one channel's placement to matching channels: each target keeps its anchor part where it is and every other part takes the source's offset and rotation from the anchor (turned by the anchors' rotation difference).+- `altium_outjob_info`: An OutJob's containers (output media), the outputs in each, and their key settings (units, decimals, plotted layer count), read from the .OutJob file: Altium need not be running.+- `altium_find_symbol`: Find symbols (or footprints with kind:'footprint') by part of their name across libraries: the given ones, or every installed .SchLib/.PcbLib.+- `altium_part_parameters`: The parameter names a project's parts carry (with how many parts carry each), or with name, that parameter's value on every part.++### Placing and routing a live board++- `altium_routing_state`: The WHOLE current board as data, in mm: tracks, arcs, vias, pads (with owner and net), components (ref, x, y, rotation, side), polygon pours, the outline, the unrouted (ratsnest) count, and a revision hash.+- `altium_route_net`: Route one net as tracks, segment by segment; a waypoint on another layer drops a via there.+- `altium_move_parts`: Move and rotate placed components; each part is read back to 0.001 mm and the exact rotation.+- `altium_place_vias`: Place vias (through, top to bottom).+- `altium_board_features`: Add the furniture every real board needs in one undo step: mounting holes (at points or the four corners), fiducials, and a stitching-via grid on a net that keeps clear of every other net's copper, every pad and the board edge.+- `altium_remove_items`: Delete specific free tracks and vias, given exactly as altium_routing_state returned them.+- `altium_ripup_nets`: Delete every free track, arc and via on each named net.+- `altium_apply_pours`: Add solid polygon pours from outlines and pour them, each with its own connect style (solid joints or thermal spokes), plus pour keepouts (polygon cutouts); answers each pour's real poured copper area.+- `altium_pour_state`: Every polygon pour with the copper it actually poured: filled area per pour and per layer, and the pours that poured nothing.+- `altium_remove_pours`: Delete polygon pours by net (and layer), or all of them, and the pour keepouts (cutouts) apply_pours made.+- `altium_repour`: Repour every polygon on the board (Altium's Repour All) and answer the copper after.+- `altium_routing_drc`: Design-rule violations on the current board WITH locations, plus the unrouted (ratsnest) count, as one clean/not-clean answer.+- `altium_build_board`: Build a NEW board from a parts list and a netlist: outline (rounded corners allowed), every footprint from one PcbLib placed by its own origin, pad nets assigned, saved; then read back pin by pin.+- `altium_set_outline`: Reshape the current board's outline (a rectangle with rounded corners, or a polygon).+- `altium_set_design_rules`: Write a fab's design rules into the current board: clearance, track width, routing via style, hole size, annular ring, hole-to-hole and board-edge clearance (mm).+- `altium_zoom_to`: Frame the PCB view on a rectangle, a part (or several) or a whole net, with a margin.+- `altium_add_rule`: Add one SCOPED design rule (a net's clearance or width, a net class's, any Altium query) that set_design_rules' board-wide values cannot express.+- `altium_build_schematic`: Draw a design's schematic from its netlist with the project library's symbols, inside a new project (.PrjPcb with the board and libraries), compile it, and check its netlist pin by pin.+- `altium_export_manufacturing`: A project's manufacturing set in one call: Gerbers, NC drill, pick and place (CSV, mm) and the BOM, from an OutJob the bridge writes beside the project (composed from this Altium's own OutJob templates, every output on one medium that opens nothing).+- `altium_select_net`: Select one net as a whole on the current board (tracks, arcs, vias, pads, pours) and nothing else, optionally framing it; no net clears the selection.+- `altium_silk_state`: The silkscreen as it stands: every part's body box, its designator and comment (text, location, size, rotation, shown, Altium's measured box), and the free overlay texts and lines on both faces.+- `altium_apply_silkscreen`: Land a silkscreen plan in one undo step: designators and comments moved, sized and turned (or hidden), free overlay texts and lines added (bottom texts mirrored), earlier ones removed; answers silk_state after.++### Showing it: views, frames, 3D++- `altium_show_project`: Open a project (.PrjPcb) through the agent and return a proof frame of Altium's main window.+- `altium_show_schematic`: Open a .SchDoc, zoom to fit, and return a proof frame.+- `altium_show_2d_board`: Open a .PcbDoc, switch to 2D, zoom to fit, and return a proof frame.+- `altium_show_3d_board`: Open a .PcbDoc, switch to 3D, zoom to fit, and return a proof frame.+- `altium_show_library`: Open a .SchLib or .PcbLib (kind taken from the extension), select its first component, return a proof frame and the component names.+- `altium_show_symbol`: Open a SchLib member in the Symbol editor and capture a background proof.+- `altium_show_footprint`: Open a PcbLib member in the footprint editor in 2D, zoom to fit, and capture a proof frame.+- `altium_show_3d_chip`: Open a PcbLib member in the footprint editor in 3D, zoom to fit, and capture a proof frame of the part's 3D body.+- `altium_list_library`: Names of every component in a .SchLib or every footprint in a .PcbLib (kind taken from the extension).+- `altium_demo`: The tour.+- `altium_animate_view`: Camera/zoom choreography on the current document - native Altium camera commands, animated by Altium itself.+- `altium_foreground`: Bring Altium in front of the user - the sanctioned exception to the never-foreground rule.++### Checks, outputs, BOM, schematic editing and project++- `altium_compile`: Compile a project and return Altium's Messages panel (ERC + connectivity) with counts by class.+- `altium_run_erc`: Electrical rules check.+- `altium_run_drc`: Run the design rule check on a board and read the violation markers back.+- `altium_run_outjob`: Run one output medium of an .OutJob (gerbers, drill, BOM, PDFs...) and list what it wrote under 'Project Outputs for <project>'.+- `altium_export_gerber`: Gerber/drill export: altium_run_outjob with the fabrication OutJob and the 'Folder Structure' medium as defaults.+- `altium_export_bom`: Bill of materials export: altium_run_outjob with the assembly OutJob and the 'Folder Structure' medium as defaults.+- `altium_export_step`: Headless STEP export of a board.+- `altium_bom`: The project's bill of materials read straight from Altium: every schematic sheet the .PrjPcb lists (placed parts and their parameters) merged with the board (footprint, position, side), a variant applied, grouped one line per manufacturer part number, checked for what an order needs, and written as bom.csv, bom-jlcpcb.csv + cpl-jlcpcb.csv, bom-mouser.csv and bom-digikey.csv (+ bom.json).+- `altium_variants`: Assembly variants of a project (which parts are fitted on which build): list them, make or change one with not-fitted parts (or put parts back), or remove one.+- `altium_workspace_search`: Search the Altium 365 workspace's components (the shared cloud library Altium is signed in to) through Altium's own Components panel: name, description and footprint per result.+- `altium_workspace_place`: Put a part from the Altium 365 workspace on a sheet: search, pick a result, place it (Altium's own placement, so the part keeps its workspace link, parameters and footprint), move it to x,y and name it.+- `altium_sheet_params`: Write parameters onto PLACED parts on the schematic sheets (the BOM write-back): MPN, Manufacturer, Mouser/DigiKey/LCSC numbers, anything.+- `altium_sch_place_part`: Place a component from a .SchLib onto an EXISTING sheet at a position, with its library parameters (MPN, Manufacturer, distributor numbers) and its footprint link.+- `altium_sch_swap_part`: Replace a placed part with another library part (a different value, package or symbol) at the same place, designator and rotation, keeping its connections: where a new pin ends elsewhere, a wire joins it to where the old pin ended.+- `altium_sch_connect`: Connect pins of placed parts: a wire stub from each pin's outer end plus a net label (kind label), a power port (kind power: GND-like nets get a ground symbol) or the stub alone (kind wire); or mark a pin left open on purpose with a No ERC marker (kind noerc, no net).+- `altium_sch_edit`: Change placed parts on a sheet: move (to x,y mil), moveBy (dx,dy), rotate (degrees), rename (designator), re-comment (comment), delete.+- `altium_annotate`: Number every '?' designator (R?, C?, U?) across the project's sheets: the lowest free number per prefix, top-left first on each sheet.+- `altium_doc_params`: Read or set a sheet's document parameters: the title block (Title, DocumentNumber, Revision, DrawnBy, Author, CompanyName, ...).+- `altium_update_pcb`: Design > Update PCB Document from the schematic (the engineering change order): parts added, removed or renamed, nets and footprints updated on the board.+- `altium_export_pdf`: Every sheet of a project as one PDF (and the board's composite print with board:true), from an OutJob in a throwaway project; the user's project is not touched.+- `altium_sch_zoom`: Find parts on a sheet: select them (everything else deselected), frame the view on them and return a proof frame.+- `altium_autoroute`: Altium's own autorouter (Situs) on the current board: picks a strategy, keeps existing routing locked by default, routes, and answers the unconnected count and DRC errors before and after.+- `altium_save`: Save the focused document, or open filePath first and save that (WorkspaceManager:SaveObject on the focused document).+- `altium_test_board`: Place one footprint, or a ';' list, from the open PcbLib on ONE board: a NEW board (wMm x hMm outline) when pcbPath is new or omitted, APPENDED to the existing board when pcbPath already exists (issue 11).+- `altium_board_shape`: Redefine the CURRENT board's outline as a wMm x hMm rectangle at (x0Mm, y0Mm) by rewriting the board outline's segments.+- `altium_pcb_report`: Numbers instead of pixels: for a PcbLib, every footprint's pads, pad bounding box, primitive census and 3D bodies; for a board, outline, components with nets and bodies, census and tracks.+- `altium_import_kicad`: Import a KiCad file with Altium's own KiCad importer, driven through the AdomBridge .NET extension.+- `altium_install_extension`: Install, update or remove the AdomBridge .NET extension (the PowerShell installer shipped beside the bridge).+- `altium_extension_ping`: Does the AdomBridge .NET extension answer? Sends AdomBridge:Ping through the -R lane and waits up to 30 s for its result file.++### Libraries: symbols, footprints, 3D bodies, parts++- `altium_create_footprint`: Create one footprint from a pad list in a PcbLib (the library is created and saved if the path does not exist) and return a proof frame.+- `altium_create_symbol`: Create one rectangular symbol from a pin list in a SchLib (the library is created and saved if the path does not exist) and return a proof frame.+- `altium_build_footprint`: Build a complete footprint (pads, silkscreen, courtyard, arcs) in a PcbLib from a kicad2altium spec file on this machine, and return a proof frame.+- `altium_build_symbol_modes`: Build ONE SchLib component with N display modes (Normal + Alternate 1..N-1) from a symbol_modes spec file on this machine, and return a proof frame.+- `altium_add_body`: Put a 3D body on a footprint of a PcbLib: a STEP model, or an extruded box when no step is given.+- `altium_add_models`: Attach one or more PCBLIB footprint models, parameters, comment and description to a SchLib component (Altium's several-footprints-per-symbol mechanism).+- `altium_normalize_bodies`: Move every 3D body of a PcbLib's footprints (or one footprint) onto its pad cluster.+- `altium_plate_vias`: Make every drilled pad in a PcbLib a plated MULTI-LAYER pad (all footprints, or footprintName).+- `altium_set_params`: Set parameters on a SchLib component, optionally its comment, and optionally link a footprint by name.+- `altium_set_visibility`: Show or hide one named parameter on a SchLib component.+- `altium_read_symbol`: Read a SchLib component back: description, display-mode count, the pins of mode 0 (designator, name, electrical type), every parameter with its hidden flag, and its model links (footprints, 3D, sim).+- `altium_clone_symbol`: Copy a symbol inside the current SchLib under a new name, all display modes included.+- `altium_rename_symbol`: Rename a component (LibReference) in the current SchLib.+- `altium_rename_footprint`: Rename a footprint in the current PcbLib.+- `altium_remove_symbol`: Delete one component from the current SchLib.+- `altium_remove_footprint`: Delete one footprint from the current PcbLib.+- `altium_copy_footprint`: Duplicate a footprint inside the current PcbLib under a new name (every primitive replicated).+- `altium_xcopy_footprint`: Copy a footprint ACROSS libraries: from fromLib into toLib (opened and made current), optionally under a new name.+- `altium_swap_footprint`: Replace the FIRST component on the current board with a footprint from a PcbLib at the same position, re-assigning nets by pad designator.+- `altium_symbol_mode`: Show one display mode (0 = Normal, 1..+- `altium_cleanup_libs`: Remove the factory-default stray every fresh library carries: Component_1 from the current SchLib and an empty (no pads) PCBComponent_1 from the current PcbLib.+- `altium_install_library`: Register a library file in Altium's Installed Libraries (IntegratedLibraryManager.InstallLibrary) so its parts appear in the Components panel.+- `altium_install_library_bundle`+- `altium_install_receipt`: The last bundle install's full receipt (proof frame included), for a client whose install call outlived ab's budget.+- `altium_compile_intlib`: Compile a .LibPkg into an integrated library (.IntLib).+- `altium_extract_intlib`: Extract the editable .SchLib/.PcbLib sources from a compiled .IntLib (Altium writes them next to the IntLib and opens them).+- `altium_place_on_sch`: Place one symbol, or a ';' list of symbols, from the open SchLib on ONE new sheet (sheet sized FROM the measured parts: 500 mil gaps, 600 mil margins, A4 minimum; parts inside the frame as U1..Un with the part number as Comment); fills the title block from title/number/revision/drawnBy and places description as a text frame; saves to schPath when given.+- `altium_place_on_pcb`: Place ONE footprint from a PcbLib on a new board and return a proof frame.+- `altium_import_part`: One call imports a whole part: footprint spec + STEP + symbol modes + models + params + save.+- `altium_add_symbol_art`: Draw the chip-outline artwork (the chip-thumbnailer polylines adom-symbol baked into the KiCad symbol) into a SchLib component, fitted to its body rectangle, so the Altium symbol shows the same chip as KiCad and Fusion.+- `altium_symbol_prims`: Read a SchLib component's drawing: primitive counts by kind, body rectangle, polyline bounding box, display mode and the footprint models.+- `altium_set_models`: Replace every footprint model on a SchLib component with ONE PCBLIB model (set_params footprint and add_models APPEND, which is how a symbol ends up with two).+- `altium_selftest_script_error`: Regression test for the script-error safety net (from 0.2.23): makes the agent raise a REAL DelphiScript runtime error on purpose and checks that the bridge photographs Altium's Error box, stops the halted script itself and leaves no dialog behind.+- `altium_install`: Install Altium Designer on this machine, STAGED, with the rules in the verb (from 0.2.29).++### Licence and account++- `altium_license`: Drive the License Management page (UIA first - no cursor, no foreground).+- `altium_license_status`: Plain-language answer to 'what Altium licence am I on?': the state from the window title plus a capture of the License Management page.+- `altium_ensure_licensed`: One call to get a usable Altium: launch if needed, then claim a seat (Use License via UIA).+- `altium_setup_trial`: Onboarding state machine: from nothing to a working trial.+- `altium_signin`: Report-only alias of altium_signin_status: it does NOT sign anyone in.+- `altium_signin_status`: Account and Altium 365 workspace connection as Altium's own UI reports it: licence state from the title, and whether the workspace menu reads 'Not Connected'.+- `altium_connect_workspace`: Open Altium's workspace picker (the 'Not Connected' menu) and return a screenshot with a coordMap.++### Altium 365 cloud++- `altium_a365_configure`: Store the Altium 365 workspace domain and, optionally, a Bearer token created by hand in the workspace web UI (Admin - Developer).+- `altium_a365_oauth_begin`: Start the Altium 365 OAuth (PKCE + ActionWait) sign-in: the bridge starts listening FIRST, then returns the authorize URL for the user's browser.+- `altium_a365_oauth_status`: State of the OAuth flow started by altium_a365_oauth_begin: idle | waiting | authorized | cancelled | error.+- `altium_a365_oauth_cancel`: Cancel a waiting OAuth flow.+- `altium_a365_refresh`: Exchange the stored refresh token for a new access token (and store a rotated refresh token if one comes back).+- `altium_a365_logout`: Revoke the refresh grant at Altium and remove every cached OAuth token.+- `altium_a365_status`: Is the Altium 365 lane configured, is there a token, and is it LIVE (probed with a one-row GraphQL query)?+- `altium_a365_query`: Run one GraphQL query or mutation against the workspace's GraphQL gateway (https://<workspace>/svc/napi/gateway/graphql/) with the stored token.+- `altium_a365_files_upload`: Upload one local file to the workspace's Files Service and get a temporary opaque file id to pass to a library mutation.+- `altium_a365_library_overview`: One fixed read-only query: the workspace library's name, description, update time, component ids/names and footprint/symbol totals.+- `altium_a365_library_schema`: Read-only schema map: the GraphQL queries and mutations whose names mention lib, component, symbol, footprint, part or datasheet, with mutation argument types.++<!-- verbs:end --> ## The dock bar card
dev-skills/altium-bridge-dev/SKILL.md+5@@ -30,6 +30,11 @@ Everything you need to change the bridge without re-learning what this session p `src/server.py` and `src/handlers/` are the retired Python reference — behaviour questions can still be answered there, but code changes go in `bridge-rs/src/` (verbs.rs KNOWN is the dispatch of record; scripts/release.py lints bridge.json against it and refuses drift).+- **The README names every verb**: `python3 tools/readme_verbs.py` writes the list (KNOWN's groups, each verb's+ first summary sentence from its verb_doc) and the "N verbs / N commands" counts. release.py refuses a stale one.+ After adding a verb: give it a verb_doc summary whose first sentence says what it does in plain words, run the+ tool, and add it to the "What it can do" table and, if it is a new kind of job, the intro list and+ page.json/package.json `discovery_triggers` (the page is found by those words). - **Deploy loop**: edit `bridge-rs/src/` → `cargo test && cargo build --release --target x86_64-pc-windows-gnu` → `send_files` the exe into `C:\Users\john\AppData\Local\Adom Bridge\bridges-cache\altium\` → `bridge_kill` (respawns the
package.json+35−5@@ -2,7 +2,7 @@ "slug": "altium-bridge", "version": "0.2.66", "type": "app",- "description": "Skills for your container so your AI knows how to drive the Altium Designer bridge (altium_* verbs). The bridge runtime itself is the release zip; Adom Bridge loads that.",+ "description": "Let an AI (Claude, ChatGPT, Codex or any agent) run Altium Designer for you: create symbols and footprints, place parts (also from Altium 365), wire and annotate schematics, Update PCB, set the stack-up and rules, route, pour copper, add mounting holes and stitching vias, run ERC and DRC, and make Gerbers, BOMs and STEP. Free in Hydrogen; bring your own AI and Altium licence.", "tags": [ "altium", "altium-designer",@@ -11,7 +11,14 @@ "eda", "bridge", "adom-bridge",- "desktop-app"+ "desktop-app",+ "ai",+ "ai-agent",+ "automation",+ "pcb-design",+ "gerber",+ "bom",+ "altium-365" ], "dependencies": { "adom/adom-bridge": "^2.0.3"@@ -100,9 +107,31 @@ "import kicad symbol into altium", "kicad to altium", "convert kicad library to altium",- "altium intlib import"+ "altium intlib import",+ "ai for altium",+ "altium ai",+ "ai altium designer",+ "let an ai run altium",+ "chatgpt altium",+ "claude altium",+ "altium copilot",+ "altium mcp",+ "ai pcb design in altium",+ "altium update pcb",+ "annotate my altium schematic",+ "altium stack-up",+ "altium net class",+ "altium diff pair",+ "altium mounting holes",+ "altium fiducials",+ "altium stitching vias",+ "altium 365 workspace part",+ "altium jlcpcb bom",+ "altium step export",+ "altium multi-part symbol",+ "altium no erc" ],- "discovery_pitch": "Drive the user's real Altium Designer from an AI: open any design surface, author native libraries with 3D bodies, run DRC and OutJobs, and screenshot everything back.",+ "discovery_pitch": "An AI that runs Altium Designer in the user's own session: libraries, schematics, Update PCB, stack-up, routing, DRC, Gerbers and BOMs.", "sample_prompts": [ { "label": "Show my board in 3D",@@ -120,5 +149,6 @@ "label": "Export Gerbers", "prompt": "generate gerbers and a BOM from my altium project" }- ]+ ],+ "title": "Altium Bridge: AI for Altium Designer" }
page.json+36−7@@ -2,8 +2,8 @@ "schema_version": 1, "slug": "altium-bridge", "type": "app",- "title": "Altium - the Altium Bridge",- "brief": "Adom Bridge for Altium Designer: a resident DelphiScript agent gives the AI eval, the 1,100-command process launcher, all 8 EDA surfaces with screenshots, compile/ERC, DRC, OutJob outputs, native SchLib/PcbLib authoring with STEP 3D bodies, and dialog handling by PID.",+ "title": "Altium Bridge: AI for Altium Designer",+ "brief": "Let an AI (Claude, ChatGPT, Codex or any agent) run Altium Designer for you: create symbols and footprints, place parts (also from Altium 365), wire and annotate schematics, Update PCB, set the stack-up and rules, route, pour copper, add mounting holes and stitching vias, run ERC and DRC, and make Gerbers, BOMs and STEP. Free in Hydrogen; bring your own AI and Altium licence.", "version": "0.2.66", "hero": { "type": "image",@@ -21,7 +21,14 @@ "eda", "bridge", "adom-bridge",- "desktop-app"+ "desktop-app",+ "ai",+ "ai-agent",+ "automation",+ "pcb-design",+ "gerber",+ "bom",+ "altium-365" ], "license": "MIT", "visibility": {@@ -92,9 +99,31 @@ "import kicad symbol into altium", "kicad to altium", "convert kicad library to altium",- "altium intlib import"+ "altium intlib import",+ "ai for altium",+ "altium ai",+ "ai altium designer",+ "let an ai run altium",+ "chatgpt altium",+ "claude altium",+ "altium copilot",+ "altium mcp",+ "ai pcb design in altium",+ "altium update pcb",+ "annotate my altium schematic",+ "altium stack-up",+ "altium net class",+ "altium diff pair",+ "altium mounting holes",+ "altium fiducials",+ "altium stitching vias",+ "altium 365 workspace part",+ "altium jlcpcb bom",+ "altium step export",+ "altium multi-part symbol",+ "altium no erc" ],- "discovery_pitch": "Drive the user's real Altium Designer from an AI: open any design surface, author native libraries with 3D bodies, run DRC and OutJobs, and screenshot everything back.",+ "discovery_pitch": "An AI that runs Altium Designer in the user's own session: libraries, schematics, Update PCB, stack-up, routing, DRC, Gerbers and BOMs.", "metadata": {}, "created_at": "2026-08-30T13:43:48.604Z", "updated_at": "2026-08-30T13:43:48.604Z",@@ -106,7 +135,7 @@ }, "skills": [], "org": "adom",- "description": "Skills for your container so your AI knows how to drive the Altium Designer bridge (altium_* verbs). The bridge runtime itself is the release zip; Adom Bridge loads that.",+ "description": "Let an AI (Claude, ChatGPT, Codex or any agent) run Altium Designer for you: create symbols and footprints, place parts (also from Altium 365), wire and annotate schematics, Update PCB, set the stack-up and rules, route, pour copper, add mounting holes and stitching vias, run ERC and DRC, and make Gerbers, BOMs and STEP. Free in Hydrogen; bring your own AI and Altium licence.", "dependencies": { "adom/adom-bridge": "^2.0.3" },@@ -147,4 +176,4 @@ "tools/symbol_modes.py", "uninstall.sh" ]-}+}
scripts/release.py+11@@ -177,6 +177,14 @@ ENGINE_HALTING = [ ] +def lint_readme():+ """Refuse a release whose README does not name every verb (tools/readme_verbs.py writes the list)."""+ r = subprocess.run([sys.executable, str(ROOT / "tools" / "readme_verbs.py"), "--check"], capture_output=True, text=True)+ if r.returncode != 0:+ raise SystemExit((r.stderr or r.stdout).strip())+ print("readme verb list ok")++ def lint_agent_script(): """Refuse an agent template that uses an identifier known to halt the engine.""" src = (SRC / "agent" / "AdomAgent.pas.tmpl").read_text(encoding="utf-8", errors="replace")@@ -399,6 +407,7 @@ def stage_only(log_line, source): lint_versions(ver) lint_agent_script() n = lint_verbs()+ lint_readme() print(f"verb lint ok: {n} verbs") build_exe() assert_source_is_head(source, "before signing")@@ -418,6 +427,7 @@ def ship_insiders(log_line, source): lint_versions(ver) lint_agent_script() n = lint_verbs()+ lint_readme() print(f"verb lint ok: {n} verbs declared and dispatchable") build_exe() assert_source_is_head(source, "before signing")@@ -584,6 +594,7 @@ def main(): lint_versions(ver) lint_agent_script() n = lint_verbs()+ lint_readme() print(f"verb lint ok: {n} verbs") build_exe() print("built the exe (unsigned). --stage or --publish signs, packages and uploads.")
tools/readme_verbs.pyadded+94@@ -0,0 +1,94 @@+#!/usr/bin/env python3+"""Write the README's full verb list from the bridge's own catalog, so the page names every verb.++The groups and their order come from KNOWN in bridge-rs/src/verbs.rs (its comment headings), each verb's line from+the first sentence of its verb_doc summary. The list lives between the two markers below in README.md.++ python3 tools/readme_verbs.py rewrite README.md+ python3 tools/readme_verbs.py --check exit 1 if README.md is stale (scripts/release.py runs this)+"""+import re+import sys+from pathlib import Path++ROOT = Path(__file__).resolve().parent.parent+VERBS = ROOT / "bridge-rs" / "src" / "verbs.rs"+README = ROOT / "README.md"+START, END = "<!-- verbs:start (tools/readme_verbs.py writes this list) -->", "<!-- verbs:end -->"++# KNOWN's comment headings, as a reader would say them+HEADINGS = {+ "health / lifecycle": "Running Altium: launch, close, health, dialogs",+ "outputs / project": "Checks, outputs, BOM, schematic editing and project",+ "library authoring": "Libraries: symbols, footprints, 3D bodies, parts",+ "licence / account": "Licence and account",+ "Altium 365": "Altium 365 cloud",+ "agent / REPL": "Scripting: DelphiScript, Altium commands, documents",+ "board / schematic reads": "Reading and setting up the design",+ "the live-board lane AI Flow drives": "Placing and routing a live board",+ "surfaces": "Showing it: views, frames, 3D",+}+++def catalog(src: str):+ known = src[src.index("pub const KNOWN"):]+ known = known[:known.index("];")]+ groups, current = [], None+ for line in known.splitlines():+ m = re.match(r"\s*//\s*(.+?)\s*$", line)+ if m:+ current = (m.group(1), [])+ groups.append(current)+ continue+ if current is not None:+ current[1].extend(re.findall(r'"([a-z0-9_]+)"', line))+ docs = {}+ for m in re.finditer(r'verb_doc\(\s*"([a-z0-9_]+)",\s*"((?:[^"\\]|\\.)*)"', src):+ docs[m.group(1)] = m.group(2).replace('\\"', '"').replace("\\'", "'")+ return groups, docs+++def first_sentence(s: str) -> str:+ s = s.strip()+ m = re.search(r"(?<!e\.g)(?<!i\.e)\.\s", s)+ if m:+ s = s[:m.start() + 1]+ return s+++def render(src: str) -> str:+ groups, docs = catalog(src)+ total = sum(len(v) for _, v in groups)+ out = [START, "", f"All {total} verbs, by area (prefix `altium_`). `altium_describe` returns the live catalog with "+ "every input, output, hint and example.", ""]+ for head, verbs in groups:+ out.append(f"### {HEADINGS.get(head, head[:1].upper() + head[1:])}")+ out.append("")+ for v in verbs:+ d = first_sentence(docs.get(v, ""))+ out.append(f"- `altium_{v}`" + (f": {d}" if d else ""))+ out.append("")+ out.append(END)+ return "\n".join(out)+++def main():+ src = VERBS.read_text(encoding="utf-8")+ readme = README.read_text(encoding="utf-8")+ if START not in readme or END not in readme:+ sys.exit(f"README.md has no verb-list markers ({START} ... {END})")+ new = readme[:readme.index(START)] + render(src) + readme[readme.index(END) + len(END):]+ # the counts the prose quotes ("174 verbs", "174 commands", "174 `altium_*` verbs") follow the catalog too+ total = sum(len(v) for _, v in catalog(src)[0])+ new = re.sub(r"(?<![\d,])\d{3}(?= (?:verbs|commands|`altium_\*` verbs)\b)", str(total), new)+ if "--check" in sys.argv:+ if new != readme:+ sys.exit("README.md's verb list is stale: run python3 tools/readme_verbs.py")+ print("readme verb list ok")+ return+ README.write_text(new, encoding="utf-8")+ print("README.md verb list written")+++if __name__ == "__main__":+ main()