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.20.2: engine 0.17.2, rule names only for rules without an Altium ordinal; kicad 1.0.83
9 files changed
+20−12
README.md+2@@ -158,6 +158,8 @@ Decisions so far (proposals from the KiCad and Fusion bridges, 2026-10-27; issue ## Status +Version 0.20.2: the engine (0.17.2) classes a rule by its own name only when it has no Altium ordinal, so Altium's other rules+no longer read as critical ones (0.20.1 read "Routing Topology (Shortest)" as a short-circuit rule). Version 0.20.1: the engine (0.17.1) fixes fusion-lane's findings in `board_report`: - The bridge's BOM gaps reach the assembly section (`lcscMissing`). - The DRC section reads each tool's own counts (Fusion's `violationCount` and `airwires`).
docs/coverage.md+1−1@@ -1,6 +1,6 @@ # Coverage: every standard verb on each bridge -Altium bridge 0.2.80 (the reference), KiCad bridge 1.0.82, Fusion 360 bridge 1.13.12. 56 verbs came from other bridges' proposals (tools/proposed/); they are marked *proposed*.+Altium bridge 0.2.80 (the reference), KiCad bridge 1.0.83, Fusion 360 bridge 1.13.12. 56 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.
engine/Cargo.lock+1−1@@ -4,7 +4,7 @@ version = 4 [[package]] name = "adom-eda-checks"-version = "0.17.1"+version = "0.17.2" dependencies = [ "roxmltree", "serde_json",
engine/Cargo.toml+1−1@@ -1,6 +1,6 @@ [package] name = "adom-eda-checks"-version = "0.17.1"+version = "0.17.2" edition = "2021" description = "The EDA Bridge Standard's checks and board-file writers, computed from the board model JSON: no bridge calls, no tool." license = "MIT"
engine/README.md+1−1@@ -112,7 +112,7 @@ adom-eda-checks import_svg --svg logo.svg --args '{"at": [10, 10], "widthMm": 20 Replies keep the standard envelope (`success`, `errorCode`, `error`, `_hint`) and name verbs without a prefix (`apply_pours`, `add_rule`, `place_vias`): a bridge adds its own. Every reply also carries `engine`-(`"adom-eda-checks 0.17.1"`), so a bridge reports the engine it runs without writing the version by hand.+(`"adom-eda-checks 0.17.2"`), so a bridge reports the engine it runs without writing the version by hand. ## Tests
engine/src/review.rs+9−3@@ -57,12 +57,15 @@ pub fn rule_class(r: &Value) -> String { } match r["kind"].as_i64() { Some(0) => return "clearance".into(), Some(2) => return "width".into(), Some(42) => return "hole size".into(), Some(15) => return "short circuit".into(),- _ => {}+ // any other Altium ordinal is no critical rule: its descriptor names it ("Routing Topology Rule (Shortest)" is+ // no short-circuit rule, "Polygon Connect (Conductor Width ...)" no width rule)+ Some(_) => return d.split('(').next().unwrap_or("").trim().to_string(),+ None => {} } // a tool's own rule names (Fusion's EAGLE rules: wire-wire, pad-via, minimum width, minimum drill, ...) let t = format!("{} {} {}", s(r, "kindName"), s(r, "name"), d).to_lowercase().replace(['_', '-'], " ");- if t.contains("short") { return "short circuit".into(); }- if t.contains("width") && !t.contains("annular") { return "width".into(); }+ if t.contains("short circuit") || t.contains("shortcircuit") { return "short circuit".into(); }+ if (t.contains("width") || t.contains("minimum wire")) && !t.contains("annular") && !t.contains("conductor") { return "width".into(); } if t.contains("drill") || t.contains("hole size") || t.contains("holesize") { return "hole size".into(); } let copper = !["silk", "mask", "paste", "edge", "board", "courtyard", "component", "hole to hole", "plane"].iter().any(|w| t.contains(w)); if copper && (t.contains("clearance") || t.contains("wire wire") || t.contains("pad via") || t.contains("pad pad")) { return "clearance".into(); }@@ -237,5 +240,8 @@ mod tests { assert_eq!(rule_class(&json!({"name": "Wire-Wire", "value": "0.1mm"})), "clearance"); assert_eq!(rule_class(&json!({"name": "Minimum Drill"})), "hole size"); assert_eq!(rule_class(&json!({"name": "Silk Clearance"})), "");+ // Altium's other ordinals stay what their descriptor says, whatever words they hold+ assert_eq!(rule_class(&json!({"kind": 7, "name": "RoutingTopology", "descriptor": "Routing Topology Rule(Topology=Shortest) (All)"})), "routing topology rule");+ assert_eq!(rule_class(&json!({"kind": 6, "name": "PlaneConnect", "descriptor": "Power Plane Connect Rule(Relief Connect )(Conductor Width=0.254mm)"})), "power plane connect rule"); } }
package.json+1−1@@ -1,6 +1,6 @@ { "slug": "eda-bridge-standard",- "version": "0.20.1",+ "version": "0.20.2", "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.",
verbs/coverage.json+2−2@@ -1,12 +1,12 @@ {- "standard": "0.20.1",+ "standard": "0.20.2", "reference": { "bridge": "altium", "version": "0.2.80" }, "proposed": 56, "compared": {- "kicad": "1.0.82",+ "kicad": "1.0.83", "fusion360": "1.13.12" }, "tiers": {
verbs/standard.json+2−2@@ -1,12 +1,12 @@ {- "standard": "0.20.1",+ "standard": "0.20.2", "reference": { "bridge": "altium", "version": "0.2.80" }, "proposed": 56, "compared": {- "kicad": "1.0.82",+ "kicad": "1.0.83", "fusion360": "1.13.12" }, "tiers": {