skill
EDA Bridge Standard: one way for an AI to drive every PCB tool
Public Made by Adomby adom
The standard every Adom EDA bridge follows so one AI can drive Altium, KiCad, Fusion 360 and any future PCB tool the same way: shared verb names in tiers, the board model JSON, reply and refusal conventions, and a coverage table of each bridge against the Altium reference.
← Commit history
standard 0.4.1: coverage counts only what works: equivalents take [verb, match, note?] with match exact | partial | unsupported (listed, not counted; fusion-lane #10); conventions: sheet is the sheet number on a tool without sheet files, save may default false where a save costs (a cloud version); regenerated with fusion 1.12.2 (21 schematic verbs) and altium 0.2.76: Altium 211, KiCad 143, Fusion 107 of 236
8 files changed
+180−76
README.md+10−5@@ -57,12 +57,12 @@ verb by verb: [docs/coverage.md](docs/coverage.md). <!-- coverage:start (tools/generate.py writes this) --> | Tier | Verbs | Altium | KiCad | Fusion 360 | |---|---|---|---|---|-| **core** | 93 | 80 | 72 | 29 |-| **native** | 46 | 36 | 35 | 18 |-| **checks** | 37 | 32 | 11 | 4 |+| **core** | 93 | 86 | 72 | 48 |+| **native** | 46 | 36 | 35 | 20 |+| **checks** | 37 | 33 | 11 | 4 | | **app** | 60 | 56 | 25 | 35 | | **platform** | 19 | 19 | 0 | 0 |-| standard (all but platform) | 236 | 204 | 143 | 86 |+| standard (all but platform) | 236 | 211 | 143 | 107 | <!-- coverage:end --> The **checks** tier is where the other bridges are furthest behind, and it is the cheapest to close: those verbs are@@ -107,7 +107,10 @@ adom-wiki repo push adom/eda-bridge-standard -m "kicad 1.0.63 reference" --files `generate.py` reads each bridge's newest file in `reference/` by version number. `tools/tiers.json` puts each Altium verb in a tier; `tools/equivalents/<bridge>.json` records verbs a bridge has under another name (Altium included, for proposed verbs it already does). An equivalent counts only when every verb it names is in that bridge's newest `reference/` file-(`generate.py` warns and leaves it out otherwise), so push the bridge's catalog before crediting its new verbs.+(`generate.py` warns and leaves it out otherwise), so push the bridge's catalog before crediting its new verbs. An+entry is `[verb, match]` or `[verb, match, note]`: `exact`, `partial` (the note says what is missing) or `unsupported`+(the verb refuses the whole job: listed, not counted). An entry wins over a verb of the same name, so a bridge can mark+its own standard-named verb partial or unsupported. ## Proposing a verb @@ -152,6 +155,8 @@ Decisions so far (proposals from the KiCad and Fusion bridges, 2026-10-27; issue ## Status +Version 0.4.1: coverage counts only what works: a bridge marks a verb `partial` (with a note) or `unsupported` in its+equivalents file ([conventions](docs/conventions.md)); `sheet` on a tool without sheet files is the sheet number. Version 0.4.0: the checks engine, `adom-eda-checks`, is on this page in `engine/` with its first five checks; fab limits come in from adom/pcb-design-rules, never built in. Version 0.3.1: an internal plane is named `In<n>.Cu` by its place in the copper stack, with `kind: "plane"` ([board model](docs/board-model.md#settled-questions)); the stack-up companion gives each copper layer's board model name in `layer`. Version 0.3.0: 33 more verbs from other bridges, all agreed by the Altium bridge's thread: 26 from the KiCad bridge (the board exports ODB++, IPC-2581, IPC-356, GenCAD and DXF, `render_board_3d`, `remove_parts`, `edit_parts`, `align_parts`, `copy_routing`, projects, library footprints, `estimate_cost`, `check_clearance`, `place_decoupling`, `plan_fanout`) and 7 from the Fusion bridge (`bodies`, `render_board_layers`, `plan_route`, `generate_body`, `library_views`, `close_all_documents`, `document_info`). A bridge's own equivalents now win over a name match, so a verb that shares a standard name but does another job is not credited for it. Version 0.2.1: this page has one keeper (standard-lane) and bridge threads push only their own files (*Keeping it in sync*), one file per owner (`tools/equivalents/<bridge>.json`, `tools/proposed/<thread>.json`); the decisions on the KiCad and Fusion proposals are written down above; a lesson from the Fusion bridge on DRC severity is in
docs/conventions.md+9@@ -10,6 +10,10 @@ the same way, and lets the shared checks run on any of them. alias, so `docs/coverage.md` can list it as exact. - A verb a tool cannot do at all is not faked. Leave it out, or answer `success:false` with `errorCode: "not_supported"` and an `error` that says why.+- Coverage counts only what works. A verb that answers `not_supported` for its whole job is marked `unsupported` in the+ bridge's `tools/equivalents/<bridge>.json` with the reason (`["sch_update_from_library", "unsupported", "the tool's+ library manager asks about each part"]`): listed, not counted. A verb that refuses some of its arguments is `partial`,+ with a note naming them. The entry wins over a name match, so this works for a verb under its standard name too. - Tool-only verbs (Altium 365, OutJobs) keep their own names under the `platform` tier and stay out of the standard. - A job the standard lacks is proposed in `tools/proposed/<thread>.json` and joins once another bridge's thread agrees (README, *Proposing a verb*). Board verbs have no prefix and call a placed part a part; sheet verbs start with `sch_`;@@ -26,6 +30,11 @@ the same way, and lets the shared checks run on any of them. not the standard. A new bridge answers those verbs in mm under `Mm` names. - Schematic sheets follow the same rule: millimetres, the tool's sheet origin, y up. A pin is named `Ref.Pin` (`U1.3`), and an item (a wire, a label, a junction) by the tool's own stable `id`, as `sch_items` lists it.+- `sheet` is the sheet's file path. On a tool whose sheets are not files (Fusion keeps them in one design), `sheet` is+ the sheet's number, from 1, and `filePath` names the design. A tool that stores no item ids builds stable ones (Fusion:+ the item's kind and position) and says so in `sch_items`' hint.+- `save` defaults to true on the sheet verbs, except where a save has a cost the user would notice (Fusion: every save+ is a new cloud version): there it defaults to false, and the verb's describe says so. - Copper layers carry KiCad's names on every tool: `F.Cu`, `In1.Cu` to `In30.Cu`, `B.Cu`, and `*.Cu` for a pad on every copper layer. A layer argument also takes the tool's own id. - Nets are named as the design names them; matching is case-insensitive.
docs/coverage.md+34−34@@ -1,17 +1,17 @@ # Coverage: every standard verb on each bridge -Altium bridge 0.2.76 (the reference), KiCad bridge 1.0.63, Fusion 360 bridge 1.12.1. 54 verbs came from other bridges' proposals (tools/proposed/); they are marked *proposed*.-`exact` is the same job under the same or an equivalent name; `partial` does part of it or does it differently; blank is missing.+Altium bridge 0.2.76 (the reference), KiCad bridge 1.0.63, Fusion 360 bridge 1.12.2. 54 verbs came from other bridges' proposals (tools/proposed/); they are marked *proposed*.+`exact` is the same job under the same or an equivalent name; `partial` does part of it or does it differently (`verbs/coverage.json` names what in `note`); `unsupported` answers `not_supported` for the whole job and is not counted; blank is missing. Generated by `tools/generate.py` from `verbs/coverage.json`; do not edit by hand. | Tier | Verbs | Altium | KiCad | Fusion 360 | |---|---|---|---|---|-| **core** | 93 | 80 | 72 | 29 |-| **native** | 46 | 36 | 35 | 18 |-| **checks** | 37 | 32 | 11 | 4 |+| **core** | 93 | 86 | 72 | 48 |+| **native** | 46 | 36 | 35 | 20 |+| **checks** | 37 | 33 | 11 | 4 | | **app** | 60 | 56 | 25 | 35 | | **platform** | 19 | 19 | 0 | 0 |-| standard (all but platform) | 236 | 204 | 143 | 86 |+| standard (all but platform) | 236 | 211 | 143 | 107 | ## core @@ -22,7 +22,7 @@ Read and edit the design. Every bridge provides these: they are how an AI sees a | `add_body` | Put a 3D body on a footprint of a PcbLib: a STEP model, or an extruded box when no step is given. It REPLACES the footprint's existing 3D bodies (a... | `altium_add_body` | | `fusion_attach_3d_package` (partial) | | `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_add_models` | `kicad_footprint_models` (partial) | | | `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... | `altium_add_symbol_art` | | |-| `align_parts` *proposed* | Line parts up on a common left, right, top, bottom or centre line, or space them evenly, by courtyard box or by anchor point. One undo step, with... | | `kicad_align_parts` | |+| `align_parts` *proposed* | Line parts up on a common left, right, top, bottom or centre line, or space them evenly, by courtyard box or by anchor point. One undo step, with... | `altium_align_parts` | `kicad_align_parts` | | | `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... | `altium_apply_silkscreen` | `kicad_silk_fields_batch / kicad_silk_text_batch / kicad_silk_graphics_batch` | `fusion_apply_silkscreen` | | `board_outline` | Draw the board shape as tracks and arcs on a mechanical layer: the outline a fab house reads from the Gerbers. A board built by script has its shape but... | `altium_board_outline` | `kicad_board_outline` | `fusion_board_outline` | | `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_board_shape` | `kicad_board_outline` | `fusion_board_shape` |@@ -33,12 +33,12 @@ Read and edit the design. Every bridge provides these: they are how an AI sees a | `component_pins` | Every pad of one board component with its net, position, layer, size and hole. | `altium_component_pins` | `kicad_component_pins` | `fusion_component_pins` | | `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_copper_layers` | `kicad_copper_layers` | `fusion_copper_layers` | | `copy_footprint` | Duplicate a footprint inside the current PcbLib under a new name (every primitive replicated). | `altium_copy_footprint` | | |-| `copy_routing` *proposed* | Copy the tracks and vias inside a box to an offset, remapping nets by pairing parts (a designator map or pattern), so a repeated channel gets the same... | | `kicad_copy_routing` | |+| `copy_routing` *proposed* | Copy the tracks and vias inside a box to an offset, remapping nets by pairing parts (a designator map or pattern), so a repeated channel gets the same... | `altium_copy_routing` | `kicad_copy_routing` | | | `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_footprint` | `kicad_create_footprint` | | | `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_create_symbol` | `kicad_create_symbol` | | | `doc_params` | Read or set a sheet's document parameters: the title block (Title, DocumentNumber, Revision, DrawnBy, Author, CompanyName, ...). | `altium_doc_params` | | | | `edit_footprint` *proposed* | Edit a library footprint in place: change, delete, add or renumber pads; add, replace or delete graphics on a layer; set its description, tags and... | | `kicad_fp_edit` | |-| `edit_parts` *proposed* | Edit placed parts: value, designator, any field (add, change, remove), do-not-populate, exclusion from the BOM or position files, mounting type and the... | | `kicad_edit_parts` | |+| `edit_parts` *proposed* | Edit placed parts: value, designator, any field (add, change, remove), do-not-populate, exclusion from the BOM or position files, mounting type and the... | `altium_edit_parts` | `kicad_edit_parts` | | | `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_find_symbol` | `kicad_find_symbol` | | | `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... | `altium_footprint_primitives` | `kicad_footprint_graphics` (partial) | | | `generate_body` *proposed* | Make a part's 3D body from its package family and its datasheet dimensions (chip, SOIC, QFN, QFP, BGA, SOT-23, DFN, MELF, electrolytic can, crystal, pin... | | | |@@ -66,9 +66,9 @@ Read and edit the design. Every bridge provides these: they are how an AI sees a | `read_schematic` | Components on the CURRENT schematic sheet (designator, library reference, comment, position, parameters) in one agent round trip. | `altium_read_schematic` | `kicad_sch_components` (partial) | `fusion_schematic` (partial) | | `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,... | `altium_read_symbol` | `kicad_read_symbol` | | | `remove_footprint` | Delete one footprint from the current PcbLib. | `altium_remove_footprint` | | |-| `remove_graphics` *proposed* | Remove board graphics (lines, rectangles, circles, arcs, polygons, texts, dimensions) by id, or every one on a layer and of a kind. One undo step. | | `kicad_remove_graphics` | |+| `remove_graphics` *proposed* | Remove board graphics (lines, rectangles, circles, arcs, polygons, texts, dimensions) by id, or every one on a layer and of a kind. One undo step. | `altium_remove_graphics` | `kicad_remove_graphics` | | | `remove_items` | Delete specific free tracks and vias, given exactly as altium_routing_state returned them. One undo step. | `altium_remove_items` | `kicad_remove_route` (partial) | `fusion_remove_items` |-| `remove_parts` *proposed* | Remove placed parts from the board by designator, as one undo step. The library is not touched (that is remove_footprint). | | `kicad_remove_parts` | |+| `remove_parts` *proposed* | Remove placed parts from the board by designator, as one undo step. The library is not touched (that is remove_footprint). | `altium_remove_parts` | `kicad_remove_parts` | | | `remove_symbol` | Delete one component from the current SchLib. | `altium_remove_symbol` | `kicad_remove_symbol` | | | `rename_footprint` | Rename a footprint in the current PcbLib. | `altium_rename_footprint` | | | | `rename_symbol` | Rename a component (LibReference) in the current SchLib. | `altium_rename_symbol` | | |@@ -76,32 +76,32 @@ Read and edit the design. Every bridge provides these: they are how an AI sees a | `route_net` | Route one net as tracks, segment by segment; a waypoint on another layer drops a via there. One undo step, read back. | `altium_route_net` | `kicad_route_net / kicad_add_track` | `fusion_route_net` | | `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,... | `altium_routing_state` | `kicad_routing_state` | `fusion_routing_state` | | `rules_by_kind` | The current board's ENABLED design rules grouped by rule kind (Clearance, Width, RoutingVias, ...), each group sorted by priority. Shaped from one... | `altium_rules_by_kind` | `kicad_board_rules` (partial) | `fusion_rules_by_kind` |-| `sch_bus` *proposed* | Draw a bus as a polyline (one bus segment per pair of points), optionally with a bus label such as D[0..7] or a group {SDA SCL} at its first point. One undo... | `altium_sch_bus` | `kicad_sch_bus` | |-| `sch_bus_entry` *proposed* | Add 45-degree bus entries: the short diagonal that joins a member wire's end to a bus. One undo step. | `altium_sch_bus_entry` | `kicad_sch_bus_entry` | |+| `sch_bus` *proposed* | Draw a bus as a polyline (one bus segment per pair of points), optionally with a bus label such as D[0..7] or a group {SDA SCL} at its first point. One undo... | `altium_sch_bus` | `kicad_sch_bus` | `fusion_sch_bus` |+| `sch_bus_entry` *proposed* | Add 45-degree bus entries: the short diagonal that joins a member wire's end to a bus. One undo step. | `altium_sch_bus_entry` | `kicad_sch_bus_entry` | `fusion_sch_bus_entry` | | `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... | `altium_sch_connect` | `kicad_sch_connect_to_net / kicad_sch_no_connect / kicad_sch_wire / kicad_sch_label` | |-| `sch_connect_pins` *proposed* | Wire pins to pins on a sheet by Ref.Pin: an L-shaped route (one horizontal and one vertical leg) for each pair, with a junction dot wherever a route meets... | `altium_sch_connect_pins` | `kicad_sch_connect_pins` | |-| `sch_connect_to_bus` *proposed* | Fan pins onto a bus: for each pin a wire running to the bus, a 45-degree bus entry onto it and a member label (D0, D1 ...) on the wire. One undo step. | `altium_sch_connect_to_bus` | `kicad_sch_connect_to_bus` | |-| `sch_create` *proposed* | Create an empty schematic sheet with a paper size and title block; optionally add it to a project as a child sheet of the root. It places no parts or nets... | `altium_sch_sheet_symbol` (partial) | `kicad_sch_create` | |-| `sch_delete_wire` *proposed* | Delete wires or bus segments by id, by their two ends, or every wire through a point, and remove junction dots that no longer join three or more items. One... | `altium_sch_delete_wire` | `kicad_sch_delete_wire` | |+| `sch_connect_pins` *proposed* | Wire pins to pins on a sheet by Ref.Pin: an L-shaped route (one horizontal and one vertical leg) for each pair, with a junction dot wherever a route meets... | `altium_sch_connect_pins` | `kicad_sch_connect_pins` | `fusion_sch_connect_pins` |+| `sch_connect_to_bus` *proposed* | Fan pins onto a bus: for each pin a wire running to the bus, a 45-degree bus entry onto it and a member label (D0, D1 ...) on the wire. One undo step. | `altium_sch_connect_to_bus` | `kicad_sch_connect_to_bus` | `fusion_sch_connect_to_bus` |+| `sch_create` *proposed* | Create an empty schematic sheet with a paper size and title block; optionally add it to a project as a child sheet of the root. It places no parts or nets... | `altium_sch_sheet_symbol` (partial) | `kicad_sch_create` | `fusion_sch_create` |+| `sch_delete_wire` *proposed* | Delete wires or bus segments by id, by their two ends, or every wire through a point, and remove junction dots that no longer join three or more items. One... | `altium_sch_delete_wire` | `kicad_sch_delete_wire` | `fusion_sch_delete_wire` | | `sch_edit` | Change placed parts on a sheet: move (to x,y mil), moveBy (dx,dy), rotate (degrees), rename (designator), re-comment (comment), delete. One undo step. | `altium_sch_edit` | `kicad_sch_set_property / kicad_sch_move / kicad_sch_delete / kicad_sch_rotate` (partial) | |-| `sch_edit_label` *proposed* | Edit net labels: rotate, move to a point or by a delta, rename, or move every label of a net at once. One undo step. | `altium_sch_edit_label` | `kicad_sch_edit_label` | |-| `sch_fix_connectivity` *proposed* | Snap near-miss wire ends onto the pin, label, sheet pin or wire end they almost touch, within a tolerance. dryRun (the default) lists the moves;... | `altium_sch_fix_connectivity` | `kicad_sch_fix_connectivity` | |-| `sch_hierarchy` *proposed* | The sheet tree of a design, recursively: each sheet's name, file, id, instance path, page number, position, size and pins. renumber:true renumbers pages... | `altium_sch_hierarchy` | `kicad_sch_hierarchy` | |-| `sch_items` *proposed* | List a sheet's wiring items with ids and coordinates: wires, buses, bus entries, net labels (local, global, hierarchical), power ports, junctions,... | `altium_sch_items` | `kicad_sch_items` | |-| `sch_junction` *proposed* | Add junction dots at points, or remove dots by id or point. One undo step. | `altium_sch_junction` | `kicad_sch_junction` | |-| `sch_move_region` *proposed* | Move everything inside a box by (dx, dy): parts, wire ends inside the box (wires crossing its edge stretch), labels, junctions, no-connect markers, texts,... | `altium_sch_move_region` | `kicad_sch_move_region` | |-| `sch_page` *proposed* | Read or set a sheet's page: paper size, orientation and title block (title, date, revision, company, comment lines). | `altium_sch_page` | `kicad_sch_page` | |-| `sch_pins` *proposed* | Every pin of the named parts on a sheet: its absolute position (rotation and mirror applied), number, name, electrical type, the side it leaves the body,... | `altium_read_sheet_file` (partial) | `kicad_sch_pins` | |+| `sch_edit_label` *proposed* | Edit net labels: rotate, move to a point or by a delta, rename, or move every label of a net at once. One undo step. | `altium_sch_edit_label` | `kicad_sch_edit_label` | `fusion_sch_edit_label` |+| `sch_fix_connectivity` *proposed* | Snap near-miss wire ends onto the pin, label, sheet pin or wire end they almost touch, within a tolerance. dryRun (the default) lists the moves;... | `altium_sch_fix_connectivity` | `kicad_sch_fix_connectivity` | `fusion_sch_fix_connectivity` |+| `sch_hierarchy` *proposed* | The sheet tree of a design, recursively: each sheet's name, file, id, instance path, page number, position, size and pins. renumber:true renumbers pages... | `altium_sch_hierarchy` | `kicad_sch_hierarchy` | `fusion_sch_hierarchy` |+| `sch_items` *proposed* | List a sheet's wiring items with ids and coordinates: wires, buses, bus entries, net labels (local, global, hierarchical), power ports, junctions,... | `altium_sch_items` | `kicad_sch_items` | `fusion_sch_items` |+| `sch_junction` *proposed* | Add junction dots at points, or remove dots by id or point. One undo step. | `altium_sch_junction` | `kicad_sch_junction` | `fusion_sch_junction` |+| `sch_move_region` *proposed* | Move everything inside a box by (dx, dy): parts, wire ends inside the box (wires crossing its edge stretch), labels, junctions, no-connect markers, texts,... | `altium_sch_move_region` | `kicad_sch_move_region` | `fusion_sch_move_region` |+| `sch_page` *proposed* | Read or set a sheet's page: paper size, orientation and title block (title, date, revision, company, comment lines). | `altium_sch_page` | `kicad_sch_page` | `fusion_sch_page` |+| `sch_pins` *proposed* | Every pin of the named parts on a sheet: its absolute position (rotation and mirror applied), number, name, electrical type, the side it leaves the body,... | `altium_read_sheet_file` (partial) | `kicad_sch_pins` | `fusion_sch_pins` | | `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... | `altium_sch_place_part` | `kicad_sch_place_symbol` | |-| `sch_reset_fields` *proposed* | Put parts' designator and value text (or the named fields) back where the library symbol places them, through each part's rotation and mirror. One undo step. | `altium_sch_reset_fields` | `kicad_sch_reset_fields` | |-| `sch_sheet_pins` *proposed* | A sheet symbol's pins: list, add, edit (rename, kind, move along an edge) or delete. import:true adds a pin for every hierarchical port inside the child... | `altium_sch_sheet_symbol` (partial) | `kicad_sch_sheet_pins` | |+| `sch_reset_fields` *proposed* | Put parts' designator and value text (or the named fields) back where the library symbol places them, through each part's rotation and mirror. One undo step. | `altium_sch_reset_fields` | `kicad_sch_reset_fields` | `fusion_sch_reset_fields` |+| `sch_sheet_pins` *proposed* | A sheet symbol's pins: list, add, edit (rename, kind, move along an edge) or delete. import:true adds a pin for every hierarchical port inside the child... | `altium_sch_sheet_symbol` (partial) | `kicad_sch_sheet_pins` | `fusion_sch_sheet_pins` | | `sch_sheet_symbol` | Make a design hierarchical: a sheet symbol on the parent sheet for a child sheet, its entries joined to the parent's nets, and matching ports on the child.... | `altium_sch_sheet_symbol` | `kicad_sch_sheet` (partial) | |-| `sch_split_wire` *proposed* | Split the wire through a point into two wires there, with a junction dot at the cut, so a new branch can end on a wire end. One undo step. | `altium_sch_split_wire` | `kicad_sch_split_wire` | |+| `sch_split_wire` *proposed* | Split the wire through a point into two wires there, with a junction dot at the cut, so a new branch can end on a wire end. One undo step. | `altium_sch_split_wire` | `kicad_sch_split_wire` | `fusion_sch_split_wire` | | `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:... | `altium_sch_swap_part` | `kicad_sch_replace_symbol` (partial) | |-| `sch_text` *proposed* | Add free text to a sheet (a note, a title, a design comment) with size, angle, justification, bold and italic. Text has no electrical meaning. One undo step. | `altium_sch_text` | `kicad_sch_text` | |-| `sch_trace_point` *proposed* | Everything electrically connected at a point on a sheet: the wires, labels, pins, junctions, sheet pins and no-connect markers there, and for each net they... | `altium_sch_trace_point` | `kicad_sch_trace_point` | |+| `sch_text` *proposed* | Add free text to a sheet (a note, a title, a design comment) with size, angle, justification, bold and italic. Text has no electrical meaning. One undo step. | `altium_sch_text` | `kicad_sch_text` | `fusion_sch_text` |+| `sch_trace_point` *proposed* | Everything electrically connected at a point on a sheet: the wires, labels, pins, junctions, sheet pins and no-connect markers there, and for each net they... | `altium_sch_trace_point` | `kicad_sch_trace_point` | `fusion_sch_trace_point` | | `schematic_data` | Components on a schematic sheet (filePath, else the CURRENT sheet) with their pins (number, name, electrical type), position and orientation. designator... | `altium_schematic_data` | `kicad_sch_components` (partial) | |-| `set_layer_count` *proposed* | Set the board's copper layer count (2, 4, 6 or 8): the layer table and the stack-up, keeping the board thickness. | | `kicad_set_layer_count` | |+| `set_layer_count` *proposed* | Set the board's copper layer count (2, 4, 6 or 8): the layer table and the stack-up, keeping the board thickness. | `altium_set_layer_count` | `kicad_set_layer_count` | | | `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_set_models` | `kicad_footprint_models` (partial) | | | `set_outline` | Reshape the current board's outline (a rectangle with rounded corners, or a polygon). One undo step. | `altium_set_outline` | `kicad_board_outline` | `fusion_set_outline` | | `set_params` | Set parameters on a SchLib component, optionally its comment, and optionally link a footprint by name. | `altium_set_params` | | |@@ -152,13 +152,13 @@ Wraps the EDA tool's own feature (its DRC, ERC, Gerbers, pours, Update PCB). Eve | `remove_pours` | Delete polygon pours by net (and layer), or all of them, and the pour keepouts (cutouts) apply_pours made. Tracks and vias are untouched. | `altium_remove_pours` | `kicad_remove_zone` | `fusion_remove_pours` | | `render_board_3d` *proposed* | Render a 3D picture of the board from one side to an image file, through the tool's own renderer, without opening a window. | | `kicad_render_board_3d` | | | `render_board_layers` *proposed* | Render chosen board layers to an image file without opening a window: a preset view (copper, silkscreen, solder mask, paste, outline, drill, assembly or... | | `kicad_export_svg` (partial) | `fusion_export_board_image` (partial) |-| `render_schematic` *proposed* | Render a sheet to an image without opening a window, through the tool's own plotter, and keep visual baselines: baseline set stores the image, baseline... | `altium_show_schematic` (partial) | `kicad_render_schematic` | |+| `render_schematic` *proposed* | Render a sheet to an image without opening a window, through the tool's own plotter, and keep visual baselines: baseline set stores the image, baseline... | `altium_show_schematic` (partial) | `kicad_render_schematic` | `fusion_render_schematic` | | `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... | `altium_replicate_layout` | | | | `repour` | Repour every polygon on the board (Altium's Repour All) and answer the copper after. Runs outside the script engine so scoped rules apply. | `altium_repour` | `kicad_repour` | `fusion_repour` | | `routing_drc` | Design-rule violations on the current board WITH locations, plus the unrouted (ratsnest) count, as one clean/not-clean answer. | `altium_routing_drc` | `kicad_routing_validate` (partial) | `fusion_routing_drc` | | `run_drc` | Run the design rule check on a board and read the violation markers back. PCB:DesignRuleCheck opens a MODAL; the bridge clicks 'Run Design Rule Check'... | `altium_run_drc` | `kicad_run_drc` | `fusion_run_drc` | | `run_erc` | Electrical rules check. Same handler as altium_compile: in Altium, compiling the project IS the ERC. | `altium_run_erc` | `kicad_run_erc` | `fusion_run_erc` |-| `sch_update_from_library` *proposed* | Update the placed symbols on a sheet from their libraries (all, or the listed ones) and report which changed, which already matched and which no library has. | `altium_sch_update_from_library` | `kicad_sch_update_from_library` | |+| `sch_update_from_library` *proposed* | Update the placed symbols on a sheet from their libraries (all, or the listed ones) and report which changed, which already matched and which no library has. | `altium_sch_update_from_library` | `kicad_sch_update_from_library` | `fusion_sch_update_from_library` | | `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... | `altium_set_design_rules` | `kicad_set_design_rules` | `fusion_set_design_rules` | | `silkscreen_prep` | Clean the silkscreen off the copper with Altium's own Tools > Silkscreen Preparation: silk clipped clear of every mask opening (pad) by the board's silk... | `altium_silkscreen_prep` | | | | `symbol_mode` | Show one display mode (0 = Normal, 1.. = alternates) of the CURRENT SchLib component in the editor and capture a frame. Drives the editor's own mode toggle,... | `altium_symbol_mode` | | |@@ -180,7 +180,7 @@ Engineering computed from the board model, not by the tool: one shared engine, s | `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... | `altium_build_board` | | | | `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_footprint` | | | | `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... | `altium_build_schematic` | | `fusion_schematic_plan / fusion_schematic_run` (partial) |-| `check_clearance` *proposed* | Measure the gaps between parts, courtyard to courtyard or pad copper to pad copper, for the listed parts or the whole board, and report every pair under a... | | `kicad_check_clearance` | |+| `check_clearance` *proposed* | Measure the gaps between parts, courtyard to courtyard or pad copper to pad copper, for the listed parts or the whole board, and report every pair under a... | `altium_check_clearance` | `kicad_check_clearance` | | | `check_orientation` | Advisory: 2-pad parts whose rotation could be better. Each orthogonal rotation is scored in place by airline length (a routable net's MST with the pad... | `altium_check_orientation` | | | | `copper_balance` | How much of each copper layer is copper (tracks, pads, vias and what Altium actually poured, inside the outline; a plane counts full), and how far apart... | `altium_copper_balance` | | | | `cross_check` | Compare one schematic sheet's designators with a board's. Altium holds ONE current document, so the verb activates the board, reads it, then activates the... | `altium_cross_check` | `kicad_analyze_connections` (partial) | |
package.json+1−1@@ -1,6 +1,6 @@ { "slug": "eda-bridge-standard",- "version": "0.4.0",+ "version": "0.4.1", "type": "skill", "title": "EDA Bridge Standard: one way for an AI to drive every PCB tool", "description": "The standard every Adom EDA bridge follows so one AI can drive Altium, KiCad, Fusion 360 and any future PCB tool the same way: shared verb names in tiers, the board model JSON, reply and refusal conventions, and a coverage table of each bridge against the Altium reference.",
page.json+1−1@@ -4,7 +4,7 @@ "type": "skill", "title": "EDA Bridge Standard: one way for an AI to drive every PCB tool", "brief": "The standard every Adom EDA bridge follows so one AI can drive Altium, KiCad, Fusion 360 and any future PCB tool the same way: shared verb names in tiers, the board model JSON, reply and refusal conventions, and a coverage table of each bridge against the Altium reference.",- "version": "0.4.0",+ "version": "0.4.1", "hero": { "type": "billboard", "headline": "One standard for every EDA bridge",
tools/generate.py+9−3@@ -44,6 +44,8 @@ def strip(name, prefix): return name[len(prefix):] if name.startswith(prefix) else name +# exact and partial count as covered; unsupported (the verb answers not_supported for the whole job) is listed, not counted+MATCHES = ("exact", "partial", "unsupported") PROPOSAL_FIELDS = ["name", "tier", "summary", "input", "output", "hint", "proposedBy", "since", "agreedBy"] @@ -130,7 +132,9 @@ def main(): # the bridge's own equivalents file comes before a name match: a verb can share a standard name and do # another job (kicad_edit_footprint edited placed parts; the standard edit_footprint is the library verb) if s["name"] in eq.get(b, {}):- verb, match = eq[b][s["name"]]+ verb, match, *note = eq[b][s["name"]]+ if match not in MATCHES:+ raise SystemExit(f"tools/equivalents/{b}.json: {s['name']}: match {match!r} is not one of {', '.join(MATCHES)}") parts = [strip(p.strip(), prefixes[b]) for p in re.split(r"\s*[/+]\s*", verb)] # an equivalent counts only when its verbs are in that bridge's reference catalog absent = [p for p in parts if p not in have[b]]@@ -138,6 +142,8 @@ def main(): print(f"warning: {b} {s['name']}: {', '.join(absent)} not in reference/{b}-{bridges[b]['version']}.json, not counted") else: row[b] = {"verb": " / ".join(prefixes[b] + p for p in parts), "match": match}+ if note:+ row[b]["note"] = note[0] if row[b] is None and s["name"] in have[b]: row[b] = {"verb": prefixes[b] + s["name"], "match": "exact"} coverage.append(row)@@ -172,14 +178,14 @@ def main(): "", f"Altium bridge {ref['version']} (the reference), KiCad bridge {others['kicad']['version']}, Fusion 360 bridge {others['fusion360']['version']}. " f"{len(proposed)} verbs came from other bridges' proposals (tools/proposed/); they are marked *proposed*.",- "`exact` is the same job under the same or an equivalent name; `partial` does part of it or does it differently; blank is missing.",+ "`exact` is the same job under the same or an equivalent name; `partial` does part of it or does it differently (`verbs/coverage.json` names what in `note`); `unsupported` answers `not_supported` for the whole job and is not counted; blank is missing.", "Generated by `tools/generate.py` from `verbs/coverage.json`; do not edit by hand.", "", summary, ""] for t in ORDER: md += [f"## {t}", "", TIERS[t], "", "| Verb | What it does | Altium | KiCad | Fusion 360 |", "|---|---|---|---|---|"] for r, s in zip(coverage, standard): if r["tier"] != t: continue- cell = lambda c: "" if not c else (f"`{c['verb']}`" + (" (partial)" if c["match"] == "partial" else ""))+ cell = lambda c: "" if not c else ("unsupported" if c["match"] == "unsupported" else f"`{c['verb']}`" + (" (partial)" if c["match"] == "partial" else "")) summ = s["summary"].replace("|", "/").replace("\n", " ") if len(summ) > 160: summ = summ[:157].rsplit(" ", 1)[0] + "..."
verbs/coverage.json+114−30@@ -1,5 +1,5 @@ {- "standard": "0.4.0",+ "standard": "0.4.1", "reference": { "bridge": "altium", "version": "0.2.76"@@ -7,7 +7,7 @@ "proposed": 54, "compared": { "kicad": "1.0.63",- "fusion360": "1.12.1"+ "fusion360": "1.12.2" }, "tiers": { "core": "Read and edit the design. Every bridge provides these: they are how an AI sees and changes a board.",@@ -60,7 +60,10 @@ "name": "align_parts", "tier": "core", "source": "proposed",- "altium": null,+ "altium": {+ "verb": "altium_align_parts",+ "match": "exact"+ }, "kicad": { "verb": "kicad_align_parts", "match": "exact"@@ -229,7 +232,10 @@ "name": "copy_routing", "tier": "core", "source": "proposed",- "altium": null,+ "altium": {+ "verb": "altium_copy_routing",+ "match": "exact"+ }, "kicad": { "verb": "kicad_copy_routing", "match": "exact"@@ -290,7 +296,10 @@ "name": "edit_parts", "tier": "core", "source": "proposed",- "altium": null,+ "altium": {+ "verb": "altium_edit_parts",+ "match": "exact"+ }, "kicad": { "verb": "kicad_edit_parts", "match": "exact"@@ -676,7 +685,10 @@ "name": "remove_graphics", "tier": "core", "source": "proposed",- "altium": null,+ "altium": {+ "verb": "altium_remove_graphics",+ "match": "exact"+ }, "kicad": { "verb": "kicad_remove_graphics", "match": "exact"@@ -704,7 +716,10 @@ "name": "remove_parts", "tier": "core", "source": "proposed",- "altium": null,+ "altium": {+ "verb": "altium_remove_parts",+ "match": "exact"+ }, "kicad": { "verb": "kicad_remove_parts", "match": "exact"@@ -824,7 +839,10 @@ "verb": "kicad_sch_bus", "match": "exact" },- "fusion360": null+ "fusion360": {+ "verb": "fusion_sch_bus",+ "match": "exact"+ } }, { "name": "sch_bus_entry",@@ -838,7 +856,10 @@ "verb": "kicad_sch_bus_entry", "match": "exact" },- "fusion360": null+ "fusion360": {+ "verb": "fusion_sch_bus_entry",+ "match": "exact"+ } }, { "name": "sch_connect",@@ -866,7 +887,10 @@ "verb": "kicad_sch_connect_pins", "match": "exact" },- "fusion360": null+ "fusion360": {+ "verb": "fusion_sch_connect_pins",+ "match": "exact"+ } }, { "name": "sch_connect_to_bus",@@ -880,7 +904,10 @@ "verb": "kicad_sch_connect_to_bus", "match": "exact" },- "fusion360": null+ "fusion360": {+ "verb": "fusion_sch_connect_to_bus",+ "match": "exact"+ } }, { "name": "sch_create",@@ -894,7 +921,10 @@ "verb": "kicad_sch_create", "match": "exact" },- "fusion360": null+ "fusion360": {+ "verb": "fusion_sch_create",+ "match": "exact"+ } }, { "name": "sch_delete_wire",@@ -908,7 +938,10 @@ "verb": "kicad_sch_delete_wire", "match": "exact" },- "fusion360": null+ "fusion360": {+ "verb": "fusion_sch_delete_wire",+ "match": "exact"+ } }, { "name": "sch_edit",@@ -936,7 +969,10 @@ "verb": "kicad_sch_edit_label", "match": "exact" },- "fusion360": null+ "fusion360": {+ "verb": "fusion_sch_edit_label",+ "match": "exact"+ } }, { "name": "sch_fix_connectivity",@@ -950,7 +986,10 @@ "verb": "kicad_sch_fix_connectivity", "match": "exact" },- "fusion360": null+ "fusion360": {+ "verb": "fusion_sch_fix_connectivity",+ "match": "exact"+ } }, { "name": "sch_hierarchy",@@ -964,7 +1003,10 @@ "verb": "kicad_sch_hierarchy", "match": "exact" },- "fusion360": null+ "fusion360": {+ "verb": "fusion_sch_hierarchy",+ "match": "exact"+ } }, { "name": "sch_items",@@ -978,7 +1020,10 @@ "verb": "kicad_sch_items", "match": "exact" },- "fusion360": null+ "fusion360": {+ "verb": "fusion_sch_items",+ "match": "exact"+ } }, { "name": "sch_junction",@@ -992,7 +1037,10 @@ "verb": "kicad_sch_junction", "match": "exact" },- "fusion360": null+ "fusion360": {+ "verb": "fusion_sch_junction",+ "match": "exact"+ } }, { "name": "sch_move_region",@@ -1006,7 +1054,10 @@ "verb": "kicad_sch_move_region", "match": "exact" },- "fusion360": null+ "fusion360": {+ "verb": "fusion_sch_move_region",+ "match": "exact"+ } }, { "name": "sch_page",@@ -1020,7 +1071,10 @@ "verb": "kicad_sch_page", "match": "exact" },- "fusion360": null+ "fusion360": {+ "verb": "fusion_sch_page",+ "match": "exact"+ } }, { "name": "sch_pins",@@ -1034,7 +1088,10 @@ "verb": "kicad_sch_pins", "match": "exact" },- "fusion360": null+ "fusion360": {+ "verb": "fusion_sch_pins",+ "match": "exact"+ } }, { "name": "sch_place_part",@@ -1062,7 +1119,10 @@ "verb": "kicad_sch_reset_fields", "match": "exact" },- "fusion360": null+ "fusion360": {+ "verb": "fusion_sch_reset_fields",+ "match": "exact"+ } }, { "name": "sch_sheet_pins",@@ -1076,7 +1136,10 @@ "verb": "kicad_sch_sheet_pins", "match": "exact" },- "fusion360": null+ "fusion360": {+ "verb": "fusion_sch_sheet_pins",+ "match": "exact"+ } }, { "name": "sch_sheet_symbol",@@ -1104,7 +1167,10 @@ "verb": "kicad_sch_split_wire", "match": "exact" },- "fusion360": null+ "fusion360": {+ "verb": "fusion_sch_split_wire",+ "match": "exact"+ } }, { "name": "sch_swap_part",@@ -1132,7 +1198,10 @@ "verb": "kicad_sch_text", "match": "exact" },- "fusion360": null+ "fusion360": {+ "verb": "fusion_sch_text",+ "match": "exact"+ } }, { "name": "sch_trace_point",@@ -1146,7 +1215,10 @@ "verb": "kicad_sch_trace_point", "match": "exact" },- "fusion360": null+ "fusion360": {+ "verb": "fusion_sch_trace_point",+ "match": "exact"+ } }, { "name": "schematic_data",@@ -1166,7 +1238,10 @@ "name": "set_layer_count", "tier": "core", "source": "proposed",- "altium": null,+ "altium": {+ "verb": "altium_set_layer_count",+ "match": "exact"+ }, "kicad": { "verb": "kicad_set_layer_count", "match": "exact"@@ -1766,7 +1841,10 @@ "verb": "kicad_render_schematic", "match": "exact" },- "fusion360": null+ "fusion360": {+ "verb": "fusion_render_schematic",+ "match": "exact"+ } }, { "name": "replicate_layout",@@ -1859,7 +1937,10 @@ "verb": "kicad_sch_update_from_library", "match": "exact" },- "fusion360": null+ "fusion360": {+ "verb": "fusion_sch_update_from_library",+ "match": "exact"+ } }, { "name": "set_design_rules",@@ -2040,7 +2121,10 @@ "name": "check_clearance", "tier": "checks", "source": "proposed",- "altium": null,+ "altium": {+ "verb": "altium_check_clearance",+ "match": "exact"+ }, "kicad": { "verb": "kicad_check_clearance", "match": "exact"
verbs/standard.json+2−2@@ -1,5 +1,5 @@ {- "standard": "0.4.0",+ "standard": "0.4.1", "reference": { "bridge": "altium", "version": "0.2.76"@@ -7,7 +7,7 @@ "proposed": 54, "compared": { "kicad": "1.0.63",- "fusion360": "1.12.1"+ "fusion360": "1.12.2" }, "tiers": { "core": "Read and edit the design. Every bridge provides these: they are how an AI sees and changes a board.",