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.4, engine 0.1.3: min_clearance counts only copper-to-copper clearance; rules naming the edge, mask, silk, holes, keepouts, the courtyard or the same net are skipped (fusion-lane #13)
8 files changed
+30−9
README.md+2@@ -155,6 +155,8 @@ Decisions so far (proposals from the KiCad and Fusion bridges, 2026-10-27; issue ## Status +Version 0.4.4: the engine (0.1.3) counts only copper-to-copper clearance rules: a rule naming the edge, mask, silk,+holes, a keepout or the same net is skipped (fusion-lane #13). Version 0.4.3: the engine (0.1.2) reads a clearance rule written as a `value` with its unit (`0.1mm`, Fusion's form) and leaves same-net spacing rules out; Altium and Fusion now both answer their checks from the engine. Version 0.4.2: the engine (0.1.1) names a stack's copper layers by the stack entry's `layer`, or by place (`In<n>.Cu`),
engine/Cargo.lock+1−1@@ -4,7 +4,7 @@ version = 4 [[package]] name = "adom-eda-checks"-version = "0.1.2"+version = "0.1.3" dependencies = [ "serde_json", ]
engine/Cargo.toml+1−1@@ -1,6 +1,6 @@ [package] name = "adom-eda-checks"-version = "0.1.2"+version = "0.1.3" edition = "2021" description = "The EDA Bridge Standard's checks, computed from the board model JSON: no bridge calls, no tool." license = "MIT"
engine/README.md+1−1@@ -33,7 +33,7 @@ Every check takes one JSON object: | `board` | the board model, `<prefix>_routing_state` (`schema/board.schema.json`) | | `stack` | the stack-up companion, `<prefix>_layer_stack` | | `pours` | poured copper, `<prefix>_pour_state` (its `zones`) |-| `rules` | the board's rules, `<prefix>_read_rules`: a clearance rule as `{kind: "clearance", clearanceMm}` |+| `rules` | the board's rules, `<prefix>_read_rules`: a clearance rule as `{kind: "clearance", clearanceMm}` (a `value` with its unit, `"0.1mm"`, works too). Only copper-to-copper clearance counts: a rule whose kind or name names the board edge, mask, silk, paste, holes, a keepout or restrict area, the courtyard or the same net is skipped | | `silk` | `<prefix>_silk_state` | | `fab` | one record from adom/pcb-design-rules `rules/records/<vendor>.json`, with `vendor` | | `args` | the check's own arguments, as the standard verb documents them |
engine/src/fab.rs+22−3@@ -132,14 +132,19 @@ fn length_mm(text: &str) -> Option<f64> { } } -/// The smallest clearance among the board's enabled clearance rules, in mm. A rule gives it as a number+/// A clearance rule that names another object than copper of another net: the board edge, solder mask, silkscreen,+/// holes, keepouts, the courtyard, or the same net (Fusion's Solder-Mask Clearance is a mask expansion, often 0.05 mm).+const NOT_COPPER_CLEARANCE: &[&str] = &["dimension", "edge", "board", "mask", "silk", "paste", "hole", "restrict", "keepout", "keep-out",+ "courtyard", "component", "body", "same net", "samenet", "same-net"];++/// The smallest copper-to-copper clearance among the board's enabled rules, in mm. A rule gives it as a number /// (`clearanceMm`, `gapMm` or `minMm`), as a `value` with its unit ("0.1mm": Fusion's form), or in a descriptor the tool-/// wrote ("Gap=10mil", "Gap=0.2mm": Altium's form). Same-net spacing rules are not clearance between nets: left out.+/// wrote ("Gap=10mil", "Gap=0.2mm": Altium's form). Clearance rules about anything but copper of another net are left out. pub fn min_clearance(rules: &[Value]) -> Option<f64> { let text = |r: &Value, k: &str| r[k].as_str().map(|s| s.to_lowercase()).unwrap_or_default(); rules.iter().filter(|r| r["kind"].as_i64() == Some(0) || text(r, "kind").contains("clearance") || r["kindName"].as_str() == Some("Clearance") || text(r, "name").contains("clearance"))- .filter(|r| !["kind", "name", "kindName"].iter().any(|k| { let t = text(r, k); t.contains("same net") || t.contains("samenet") || t.contains("same-net") }))+ .filter(|r| !["kind", "name", "kindName"].iter().any(|k| { let t = text(r, k); NOT_COPPER_CLEARANCE.iter().any(|w| t.contains(w)) })) .filter(|r| r["enabled"].as_bool() != Some(false)) .filter_map(|r| { if let Some(v) = ["clearanceMm", "gapMm", "minMm"].iter().find_map(|k| r[*k].as_f64()) { return Some(v); }@@ -320,4 +325,18 @@ mod tests { assert_eq!(length_mm("100um"), Some(0.1)); assert_eq!(length_mm("0.2"), None, "a bare number has no unit: never guessed"); }++ #[test]+ fn only_copper_to_copper_clearance_counts() {+ // Fusion's rule set (#13): only Copper Clearance is the clearance between nets+ let fusion = vec![json!({"kind": "Copper Clearance", "value": "0.1mm"}), json!({"kind": "Dimension Clearance", "value": "0.3mm"}),+ json!({"kind": "Solder-Mask Clearance", "value": "0.05mm"}), json!({"kind": "Restrict Clearance", "value": "0.02mm"}),+ json!({"kind": "Via Restrict Clearance", "value": "0.02mm"}), json!({"kind": "Keepout Clearance", "value": "0.01mm"})];+ assert_eq!(min_clearance(&fusion), Some(0.1));+ // Altium names its other clearances by object too+ let altium = vec![json!({"kind": 0, "name": "Clearance", "descriptor": "Clearance Constraint (Gap=0.2mm) (All),(All)"}),+ json!({"kind": 17, "name": "HoleToHoleClearance", "descriptor": "Gap=0.1mm"}),+ json!({"kind": 20, "name": "SilkToSolderMaskClearance", "descriptor": "Gap=0.05mm"})];+ assert_eq!(min_clearance(&altium), Some(0.2));+ } }
package.json+1−1@@ -1,6 +1,6 @@ { "slug": "eda-bridge-standard",- "version": "0.4.3",+ "version": "0.4.4", "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+1−1@@ -1,5 +1,5 @@ {- "standard": "0.4.3",+ "standard": "0.4.4", "reference": { "bridge": "altium", "version": "0.2.76"
verbs/standard.json+1−1@@ -1,5 +1,5 @@ {- "standard": "0.4.3",+ "standard": "0.4.4", "reference": { "bridge": "altium", "version": "0.2.76"