← Commit history

0.31.1: sch_no_connect, sch_label, sch_wire, place_parts, edit_tracks, model_check, extensions join (#29); 263 verbs

Colby Knox ·43003f6c85 ·8d ago ·parent e8f9c67
6 files changed +413−23
README.md+6−5
@@ -60,12 +60,12 @@ verb by verb: [docs/coverage.md](docs/coverage.md). <!-- coverage:start (tools/generate.py writes this) --> | Tier | Verbs | Altium | KiCad | Fusion 360 | |---|---|---|---|---|-| **core** | 95 | 95 | 95 | 93 |-| **native** | 54 | 53 | 53 | 51 |-| **checks** | 38 | 38 | 38 | 38 |-| **app** | 69 | 66 | 56 | 61 |+| **core** | 99 | 95 | 99 | 93 |+| **native** | 55 | 53 | 54 | 51 |+| **checks** | 39 | 38 | 39 | 38 |+| **app** | 70 | 66 | 57 | 61 | | **platform** | 18 | 18 | 0 | 1 |-| standard (all but platform) | 256 | 252 | 242 | 243 |+| standard (all but platform) | 263 | 252 | 249 | 243 | <!-- coverage:end -->  The **checks** tier is where the other bridges are furthest behind, and it is the cheapest to close: those verbs are@@ -158,6 +158,7 @@ Decisions so far (proposals from the KiCad and Fusion bridges, 2026-10-27; issue  ## Status +Version 0.31.1: sch_no_connect, sch_label, sch_wire, place_parts, edit_tracks, model_check and extensions join from KiCad (#29), 263 verbs. Version 0.31.0: physical_properties, preferences, select_items and cancel_run join from Fusion (#29), 256 verbs; proposals may now carry the platform tier. Version 0.30.14: coverage reads Fusion 360 bridge 1.13.55 (sch_place_part, sch_swap_part and edit_parts exact). Version 0.30.13: coverage reads Fusion 360 bridge 1.13.52 (public; urgent fix for fusion-bridge#136, no verb changes).
docs/coverage.md+13−6
@@ -1,17 +1,17 @@ # Coverage: every standard verb on each bridge -Altium bridge 0.2.88 (the reference), KiCad bridge 1.0.98, Fusion 360 bridge 1.13.55. 71 verbs came from other bridges' proposals (tools/proposed/); they are marked *proposed*.+Altium bridge 0.2.88 (the reference), KiCad bridge 1.0.98, Fusion 360 bridge 1.13.55. 78 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** | 95 | 95 | 95 | 93 |-| **native** | 54 | 53 | 53 | 51 |-| **checks** | 38 | 38 | 38 | 38 |-| **app** | 69 | 66 | 56 | 61 |+| **core** | 99 | 95 | 99 | 93 |+| **native** | 55 | 53 | 54 | 51 |+| **checks** | 39 | 38 | 39 | 38 |+| **app** | 70 | 66 | 57 | 61 | | **platform** | 18 | 18 | 0 | 1 |-| standard (all but platform) | 256 | 252 | 242 | 243 |+| standard (all but platform) | 263 | 252 | 249 | 243 |  ## core @@ -55,6 +55,7 @@ Read and edit the design. Every bridge provides these: they are how an AI sees a | `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. | `altium_part_parameters` | `kicad_part_parameters` | `fusion_part_parameters` | | `place_on_pcb` | Place ONE footprint from a PcbLib on a new board and return a proof frame. The single-part predecessor of altium_test_board. | `altium_place_on_pcb` | `kicad_place_footprint / kicad_add_footprint` | `fusion_test_board` (partial) | | `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... | `altium_place_on_sch` | `kicad_place_on_sch` | `fusion_make_showcase_project` (partial) |+| `place_parts` *proposed* | Put footprints from a library onto the current board, each with its position, rotation and side, and read them back. One undo step. |  | `kicad_add_footprint` (partial) |  | | `place_vias` | Place vias (through, top to bottom). One undo step, read back. | `altium_place_vias` | `kicad_add_via` | `fusion_place_vias` | | `plate_vias` | Make every drilled pad in a PcbLib a plated MULTI-LAYER pad (all footprints, or footprintName). adom-lbr writes heatsink vias as pads with a hole; Altium... | `altium_plate_vias` | `kicad_plate_vias` | `fusion_plate_vias` | | `project_create` *proposed* | Create a new project folder with a project file, an empty schematic and an empty board (2 to 32 copper layers), with a title and text variables. | `altium_project_create` | `kicad_project_create` | `fusion_project_create` (partial) |@@ -90,7 +91,9 @@ Read and edit the design. Every bridge provides these: they are how an AI sees a | `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` (partial) | | `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_label` *proposed* | Put a net label on an existing wire at a point, or delete one. sch_connect labels a pin through a new stub, and sch_edit_label changes labels that already... |  | `kicad_sch_label` |  | | `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_no_connect` *proposed* | Put a no-connect marker on a sheet, at a point or on a pin, or remove one by its sch_items id. One undo step. |  | `kicad_sch_no_connect` |  | | `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` (partial) | | `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_sch_pins` | `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_part` | `fusion_sch_place_part` |@@ -101,6 +104,7 @@ Read and edit the design. Every bridge provides these: they are how an AI sees a | `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_swap_part` | `fusion_sch_swap_part` | | `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` |+| `sch_wire` *proposed* | Draw a wire through given points on a sheet, in the same units as the other sch_* wiring verbs. One undo step. |  | `kicad_sch_wire` |  | | `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) | `fusion_schematic_data` (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. | `altium_set_layer_count` | `kicad_set_layer_count` | `fusion_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) | `fusion_set_models` |@@ -132,6 +136,7 @@ Wraps the EDA tool's own feature (its DRC, ERC, Gerbers, pours, Update PCB). Eve | `create_part_project` *proposed* | Generate a small real project (schematic and board) around one library part, so the part can be shown and tested in every view: schematic, 2D board and 3D... | `altium_create_part_project` | `kicad_create_part_project` (partial) | `fusion_make_test_project` (partial) | | `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's differential-pair... | `altium_diff_pairs` | `kicad_diff_pairs` (partial) | `fusion_diff_pairs` (partial) | | `edit_pours` *proposed* | Change existing pours in place without redrawing them: clearance, minimum width, thermal relief (on/off, spoke width, gap), priority or rank, the net, and... | `altium_edit_pours` | `kicad_edit_pours` | `fusion_edit_pours` (partial) |+| `edit_tracks` *proposed* | Change given tracks by the handle routing_state returns: width, layer and ends. One undo step, read back. |  | `kicad_modify_track` (partial) |  | | `export_3d` *proposed* | Export the board's 3D model in a mesh or CAD format other than STEP (export_step has STEP), through the tool's own exporter, with an optional web-optimized... | `altium_export_3d` | `kicad_export_3d` | `fusion_export_3d` | | `export_bom` | Bill of materials export: altium_run_outjob with the assembly OutJob and the 'Folder Structure' medium as defaults. | `altium_export_bom` | `kicad_export_bom` | `fusion_export_bom` | | `export_dxf` *proposed* | Export chosen board layers to DXF, one file per layer (the outline, panel drawings, stencils, enclosure work). | `altium_export_dxf` | `kicad_export_dxf` | `fusion_export_dxf` |@@ -205,6 +210,7 @@ Engineering computed from the board model, not by the tool: one shared engine, s | `jlcpcb_order` | A JLCPCB order in one call: the board checked against JLCPCB's fab limits, the Gerbers and drill zipped the way JLCPCB's order page takes them, the JLCPCB... | `altium_jlcpcb_order` | `kicad_jlcpcb_order` | `fusion_jlcpcb_order` | | `length_tune` | Lengthen a routed net to a target length, or to match another net (a pair's skew, a DDR byte lane): a serpentine in its longest straight track that has room... | `altium_length_tune` | `kicad_length_tune` | `fusion_length_tune` | | `lint_library` | Check a .PcbLib or .SchLib before it ships: footprints without pads, courtyard, silkscreen or 3D body, with duplicate or missing pad numbers, an origin off... | `altium_lint_library` | `kicad_lint_library` | `fusion_lint_library` |+| `model_check` *proposed* | Per part: is there a 3D model, where is it, is the file found, and does it hold geometry. For a library footprint or a whole board. Read only. |  | `kicad_model_check` |  | | `net_lengths` | Routed length of every net (or the ones named) on the live board, by layer with its vias; the skew inside each differential pair; and the spread of... | `altium_net_lengths` | `kicad_net_lengths` | `fusion_net_lengths` | | `pin_pad_check` | Do the footprints fit their symbols? Part by part, the symbol's pin numbers (from the sheet files) against the footprint's pad names (from the board): pins... | `altium_pin_pad_check` | `kicad_pin_pad_check` | `fusion_pin_pad_check` | | `place_decoupling` *proposed* | Plan positions for decoupling capacitors beside an IC's power pins (each cap just outside the courtyard, its power pad facing the pin), answered as... | `altium_place_decoupling` | `kicad_place_decoupling` | `fusion_place_decoupling` |@@ -250,6 +256,7 @@ Driving the application itself (launch, licence, dialogs, windows, views). Each | `eval` | Run a DelphiScript snippet inside Altium (optional Var block, then Begin ... End;) on the CURRENT document, or on filePath opened first. | `altium_eval` | `kicad_eval` | `fusion_run_modeling_script` (partial) | | `export_spice` *proposed* | Write the design's SPICE netlist with the tool's own exporter, and say what it holds. | `altium_export_spice` | `kicad_export_spice` | `fusion_export_spice` | | `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. | `altium_extension_ping` | unsupported | `fusion_addin_status` (partial) |+| `extensions` *proposed* | The tool's own plugins and add-ons: list what is installed, install one, remove one. Not install_extension, which is the bridge's own helper inside the tool. |  | `kicad_pcm_list / kicad_pcm_install / kicad_pcm_uninstall` (partial) |  | | `foreground` | Bring Altium in front of the user - the sanctioned exception to the never-foreground rule. | `altium_foreground` | `kicad_foreground` | `fusion_foreground` | | `install` | Install Altium Designer on this machine, STAGED, with the rules in the verb (from 0.2.29). stage: preflight / get_installer / launch / wait / license, or... | `altium_install` | `kicad_upgrade` (partial) | `fusion_install` | | `install_extension` | Install, update or remove the AdomBridge .NET extension (the PowerShell installer shipped beside the bridge). Altium must be CLOSED. | `altium_install_extension` | unsupported | unsupported |
package.json+1−1
@@ -1,6 +1,6 @@ {   "slug": "eda-bridge-standard",-  "version": "0.31.0",+  "version": "0.31.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.",
tools/proposed/kicad-lane.json+7−7
@@ -2341,7 +2341,7 @@    "pin": "U1.12"   },   "proposedBy": "kicad-lane",-  "since": "0.30.15",+  "since": "0.31.1",   "agreedBy": [    "altium-lane"   ]@@ -2385,7 +2385,7 @@    ]   },   "proposedBy": "kicad-lane",-  "since": "0.30.15",+  "since": "0.31.1",   "agreedBy": [    "altium-lane",    "fusion-lane"@@ -2431,7 +2431,7 @@    ]   },   "proposedBy": "kicad-lane",-  "since": "0.30.15",+  "since": "0.31.1",   "agreedBy": [    "altium-lane"   ]@@ -2474,7 +2474,7 @@    ]   },   "proposedBy": "kicad-lane",-  "since": "0.30.15",+  "since": "0.31.1",   "agreedBy": [    "altium-lane"   ]@@ -2514,7 +2514,7 @@    ]   },   "proposedBy": "kicad-lane",-  "since": "0.30.15",+  "since": "0.31.1",   "agreedBy": [    "altium-lane"   ]@@ -2547,7 +2547,7 @@    "filePath": "C:/proj/board.kicad_pcb"   },   "proposedBy": "kicad-lane",-  "since": "0.30.15",+  "since": "0.31.1",   "agreedBy": [    "altium-lane"   ]@@ -2582,7 +2582,7 @@    "action": "list"   },   "proposedBy": "kicad-lane",-  "since": "0.30.15",+  "since": "0.31.1",   "agreedBy": [    "altium-lane"   ]
verbs/coverage.json+82−2
@@ -1,10 +1,10 @@ {- "standard": "0.31.0",+ "standard": "0.31.1",  "reference": {   "bridge": "altium",   "version": "0.2.88"  },- "proposed": 71,+ "proposed": 78,  "compared": {   "kicad": "1.0.98",   "fusion360": "1.13.55"@@ -642,6 +642,18 @@     "note": "a library's components (or the ones named) on a new sheet with a board beside it; Fusion sizes and titles the sheet itself"    }   },+  {+   "name": "place_parts",+   "tier": "core",+   "source": "proposed",+   "altium": null,+   "kicad": {+    "verb": "kicad_add_footprint",+    "match": "partial",+    "note": "one footprint or one row per call, not a parts list; the verb under the standard's name is coming"+   },+   "fusion360": null+  },   {    "name": "place_vias",    "tier": "core",@@ -1245,6 +1257,17 @@     "match": "exact"    }   },+  {+   "name": "sch_label",+   "tier": "core",+   "source": "proposed",+   "altium": null,+   "kicad": {+    "verb": "kicad_sch_label",+    "match": "exact"+   },+   "fusion360": null+  },   {    "name": "sch_move_region",    "tier": "core",@@ -1262,6 +1285,17 @@     "match": "exact"    }   },+  {+   "name": "sch_no_connect",+   "tier": "core",+   "source": "proposed",+   "altium": null,+   "kicad": {+    "verb": "kicad_sch_no_connect",+    "match": "exact"+   },+   "fusion360": null+  },   {    "name": "sch_page",    "tier": "core",@@ -1439,6 +1473,17 @@     "match": "exact"    }   },+  {+   "name": "sch_wire",+   "tier": "core",+   "source": "proposed",+   "altium": null,+   "kicad": {+    "verb": "kicad_sch_wire",+    "match": "exact"+   },+   "fusion360": null+  },   {    "name": "schematic_data",    "tier": "core",@@ -1863,6 +1908,18 @@     "note": "minimum width, clearance, thermals, rank and orphans, refilled and read back (net and layer name a pour when it is the only one there); a pour's net cannot be moved in place (a polygon belongs to its signal)"    }   },+  {+   "name": "edit_tracks",+   "tier": "native",+   "source": "proposed",+   "altium": null,+   "kicad": {+    "verb": "kicad_modify_track",+    "match": "partial",+    "note": "the standard's tracks list is KiCad's changes list; the verb under the standard's name is coming"+   },+   "fusion360": null+  },   {    "name": "export_3d",    "tier": "native",@@ -3007,6 +3064,17 @@     "note": "a .lbr read offline (packages: pads, tKeepout courtyard, tPlace silk, 3D packages, description; components: pins, footprint, MPN) and judged by the shared engine"    }   },+  {+   "name": "model_check",+   "tier": "checks",+   "source": "proposed",+   "altium": null,+   "kicad": {+    "verb": "kicad_model_check",+    "match": "exact"+   },+   "fusion360": null+  },   {    "name": "net_lengths",    "tier": "checks",@@ -3669,6 +3737,18 @@     "note": "the add-in (Fusion's counterpart of the .NET extension) answering or not, with its port and version"    }   },+  {+   "name": "extensions",+   "tier": "app",+   "source": "proposed",+   "altium": null,+   "kicad": {+    "verb": "kicad_pcm_list / kicad_pcm_install / kicad_pcm_uninstall",+    "match": "partial",+    "note": "three verbs for KiCad's Plugin and Content Manager; one verb under the standard's name is coming"+   },+   "fusion360": null+  },   {    "name": "foreground",    "tier": "app",
verbs/standard.json+304−2
@@ -1,10 +1,10 @@ {- "standard": "0.31.0",+ "standard": "0.31.1",  "reference": {   "bridge": "altium",   "version": "0.2.88"  },- "proposed": 71,+ "proposed": 78,  "compared": {   "kicad": "1.0.98",   "fusion360": "1.13.55"@@ -1325,6 +1325,52 @@    "longRunning": false,    "timeoutSeconds": 90   },+  {+   "name": "place_parts",+   "tier": "core",+   "source": "proposed",+   "summary": "Put footprints from a library onto the current board, each with its position, rotation and side, and read them back. One undo step.",+   "input": {+    "filePath": "the board (default the current one)",+    "parts": "[{library, footprint, ref?, value?, x, y, rotation?: 0, side?: top|bottom, nets?: {pad: net}}] mm and degrees (required)",+    "dryRun": "bool, default false: answer the plan and change nothing",+    "expectedRevision": "optional: refused with stale_board if the board changed"+   },+   "output": {+    "results": "[ok|err:...] per part",+    "placed": "[{ref, x, y, rotation, side}]",+    "revision": "string"+   },+   "hint": "For parts with no sheet behind them: mounting hardware, test points, or a board built without a schematic. A taken designator is refused and the next free one is named.",+   "pitfalls": [+    "On a board with a schematic, parts normally arrive through update_pcb: a part placed here is on no sheet, and the next update_pcb lists it in removeParts.",+    "Fusion's linked board is partial: only a standalone board takes a direct add."+   ],+   "related": [+    "update_pcb",+    "move_parts",+    "remove_parts",+    "routing_state"+   ],+   "example": {+    "parts": [+     {+      "library": "Resistor_SMD",+      "footprint": "R_0603_1608Metric",+      "ref": "R12",+      "x": 120.0,+      "y": 95.0+     }+    ]+   },+   "longRunning": false,+   "timeoutSeconds": null,+   "proposedBy": "kicad-lane",+   "since": "0.31.1",+   "agreedBy": [+    "altium-lane"+   ]+  },   {    "name": "place_vias",    "tier": "core",@@ -2712,6 +2758,54 @@     "altium-lane"    ]   },+  {+   "name": "sch_label",+   "tier": "core",+   "source": "proposed",+   "summary": "Put a net label on an existing wire at a point, or delete one. sch_connect labels a pin through a new stub, and sch_edit_label changes labels that already exist.",+   "input": {+    "sheet": "path to the schematic sheet file (required)",+    "text": "the net name (required to add)",+    "at": "[x, y] mm: a point on the wire",+    "kind": "local|global|hierarchical, default local",+    "rotation": "0|90|180|270, default 0",+    "remove": "bool, default false: delete the label named by id, or by text with at",+    "id": "a label's id from sch_items (with remove)",+    "dryRun": "bool, default false: answer the plan and change nothing",+    "save": "bool, default true: save the sheet after the edit"+   },+   "output": {+    "label": "{id, text, kind, at, rotation} when added",+    "removed": "[id]",+    "saved": "bool"+   },+   "hint": "The label names the net of the wire it touches: check with sch_trace_point at the same point, or netlist.",+   "pitfalls": [+    "A label placed where no wire runs connects nothing, and is reported by the ERC, not by this verb."+   ],+   "related": [+    "sch_connect",+    "sch_edit_label",+    "sch_items",+    "sch_trace_point"+   ],+   "example": {+    "sheet": "C:/proj/board.kicad_sch",+    "text": "VIN",+    "at": [+     63.5,+     54.61+    ]+   },+   "longRunning": false,+   "timeoutSeconds": null,+   "proposedBy": "kicad-lane",+   "since": "0.31.1",+   "agreedBy": [+    "altium-lane",+    "fusion-lane"+   ]+  },   {    "name": "sch_move_region",    "tier": "core",@@ -2762,6 +2856,49 @@     "altium-lane"    ]   },+  {+   "name": "sch_no_connect",+   "tier": "core",+   "source": "proposed",+   "summary": "Put a no-connect marker on a sheet, at a point or on a pin, or remove one by its sch_items id. One undo step.",+   "input": {+    "sheet": "path to the schematic sheet file (required)",+    "at": "[x, y] mm: a point",+    "points": "[[x, y]] mm: several points",+    "pin": "designator.pin, e.g. U1.12",+    "pins": "[designator.pin]",+    "id": "a marker's id from sch_items (with remove)",+    "remove": "bool, default false: remove the marker at id or at",+    "dryRun": "bool, default false: answer the plan and change nothing",+    "save": "bool, default true: save the sheet after the edit"+   },+   "output": {+    "added": "[{id, at}]",+    "removed": "[id]",+    "failed": "[{item, error}]",+    "saved": "bool"+   },+   "hint": "Use it for a pin left open on purpose, so the ERC stops reporting it. sch_items {kinds:[noConnects]} lists the markers with their ids.",+   "pitfalls": [+    "A bridge whose tool has no such marker answers not_supported, with the reason (Fusion's schematic has none)."+   ],+   "related": [+    "sch_items",+    "sch_connect",+    "run_erc"+   ],+   "example": {+    "sheet": "C:/proj/board.kicad_sch",+    "pin": "U1.12"+   },+   "longRunning": false,+   "timeoutSeconds": null,+   "proposedBy": "kicad-lane",+   "since": "0.31.1",+   "agreedBy": [+    "altium-lane"+   ]+  },   {    "name": "sch_page",    "tier": "core",@@ -3216,6 +3353,54 @@     "altium-lane"    ]   },+  {+   "name": "sch_wire",+   "tier": "core",+   "source": "proposed",+   "summary": "Draw a wire through given points on a sheet, in the same units as the other sch_* wiring verbs. One undo step.",+   "input": {+    "sheet": "path to the schematic sheet file (required)",+    "points": "[[x, y], ...] mm, two or more (required)",+    "junctions": "bool, default true: add a junction where the wire ends on another wire",+    "dryRun": "bool, default false: answer the plan and change nothing",+    "save": "bool, default true: save the sheet after the edit"+   },+   "output": {+    "wires": "[{id, from, to}] one per segment",+    "junctionsAdded": "[{id, at}]",+    "saved": "bool"+   },+   "hint": "For wiring between points that aren't pins, such as a bus of stubs or a route around a part. sch_connect_pins draws between two pins and works out the path.",+   "pitfalls": [+    "Points that are not on the sheet's grid may not reach a pin: read the pin's position first with sch_pins."+   ],+   "related": [+    "sch_connect_pins",+    "sch_split_wire",+    "sch_delete_wire",+    "sch_items"+   ],+   "example": {+    "sheet": "C:/proj/board.kicad_sch",+    "points": [+     [+      50.8,+      54.61+     ],+     [+      76.2,+      54.61+     ]+    ]+   },+   "longRunning": false,+   "timeoutSeconds": null,+   "proposedBy": "kicad-lane",+   "since": "0.31.1",+   "agreedBy": [+    "altium-lane"+   ]+  },   {    "name": "schematic_data",    "tier": "core",@@ -4169,6 +4354,49 @@     "altium-lane"    ]   },+  {+   "name": "edit_tracks",+   "tier": "native",+   "source": "proposed",+   "summary": "Change given tracks by the handle routing_state returns: width, layer and ends. One undo step, read back.",+   "input": {+    "filePath": "the board (default the current one)",+    "tracks": "[{id, width?, layer?, start?: [x, y], end?: [x, y]}] mm; id is the track's handle from routing_state (required)",+    "dryRun": "bool, default false: answer the plan and change nothing",+    "expectedRevision": "optional: refused with stale_board if the board changed"+   },+   "output": {+    "results": "[ok|err:...] per track",+    "changes": "[{id, before, after}]",+    "verified": "bool: every change read back",+    "revision": "string"+   },+   "hint": "set_track_width works by net or class; this works on the tracks you name, for one neck or one layer swap. A track that moves off its pad is refused or shows in routing_drc, depending on the bridge.",+   "pitfalls": [+    "Changing a track's layer does not add the vias its ends now need: check with routing_drc."+   ],+   "related": [+    "routing_state",+    "set_track_width",+    "remove_items",+    "routing_drc"+   ],+   "example": {+    "tracks": [+     {+      "id": "<handle>",+      "width": 0.5+     }+    ]+   },+   "longRunning": false,+   "timeoutSeconds": null,+   "proposedBy": "kicad-lane",+   "since": "0.31.1",+   "agreedBy": [+    "altium-lane"+   ]+  },   {    "name": "export_3d",    "tier": "native",@@ -6802,6 +7030,42 @@    "longRunning": false,    "timeoutSeconds": 600   },+  {+   "name": "model_check",+   "tier": "checks",+   "source": "proposed",+   "summary": "Per part: is there a 3D model, where is it, is the file found, and does it hold geometry. For a library footprint or a whole board. Read only.",+   "input": {+    "filePath": "a board: every part on it",+    "library": "a footprint library (with footprint)",+    "footprint": "one footprint's name",+    "limit": "int, default 50: parts reported on a board"+   },+   "output": {+    "parts": "[{name, models: [{path, location: embedded|file|cloud, found: bool, hasGeometry: bool}], issues: [string]}]",+    "checked": "int",+    "ok": "bool: every part has a model that is found and holds geometry"+   },+   "hint": "Run it before a 3D export or a fab handoff. Whether the body sits in the right place stays with bodies: this verb only says the model is there and usable.",+   "pitfalls": [+    "A bridge whose models live in the cloud reports found as whether the reference resolves."+   ],+   "related": [+    "bodies",+    "lint_library",+    "export_3d"+   ],+   "example": {+    "filePath": "C:/proj/board.kicad_pcb"+   },+   "longRunning": false,+   "timeoutSeconds": null,+   "proposedBy": "kicad-lane",+   "since": "0.31.1",+   "agreedBy": [+    "altium-lane"+   ]+  },   {    "name": "net_lengths",    "tier": "checks",@@ -8124,6 +8388,44 @@    "longRunning": false,    "timeoutSeconds": 60   },+  {+   "name": "extensions",+   "tier": "app",+   "source": "proposed",+   "summary": "The tool's own plugins and add-ons: list what is installed, install one, remove one. Not install_extension, which is the bridge's own helper inside the tool.",+   "input": {+    "action": "list|install|remove, default list",+    "id": "the package's identifier (install, remove)",+    "source": "a repository URL or a local package file (install)",+    "version": "optional (install)",+    "checkUpdates": "bool, default true (list)"+   },+   "output": {+    "extensions": "[{id, name, version, kind, updateAvailable?, latestVersion?}]",+    "count": "int",+    "installed": "{id, version} after install",+    "removed": "id after remove"+   },+   "hint": "Read the list before installing, and restart the tool if the reply says the plugin loads at startup.",+   "pitfalls": [+    "Altium and Fusion list, and refuse install and remove by name: their pages can't be driven."+   ],+   "related": [+    "install_extension",+    "extension_ping",+    "state"+   ],+   "example": {+    "action": "list"+   },+   "longRunning": false,+   "timeoutSeconds": null,+   "proposedBy": "kicad-lane",+   "since": "0.31.1",+   "agreedBy": [+    "altium-lane"+   ]+  },   {    "name": "foreground",    "tier": "app",