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.
main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
//! adom-eda-checks: the EDA Bridge Standard's checks tier, computed from the board model and its companions as plain
//! JSON, plus board-file writers (`writers`: GenCAD, DXF, SVG to regions) for a bridge whose tool has no native
//! exporter. No bridge calls, no tool, no I/O: a bridge links this crate (or runs the `adom-eda-checks` command) and
//! answers the verb under its own prefix (`kicad_return_path`). Replies keep the standard envelope (`success`,
//! `errorCode`, `error`, `_hint`) and name verbs without a prefix.
//!
//! Every check takes one input bundle, `{board, stack?, pours?, rules?, silk?, fab?, bodies?, prices?, sheetParts?, netlist?, sheetDrawing?, library?, args?}` (see `input`).
use serde_json::Value;
pub mod assembly;
pub mod autoclass;
pub mod bodies;
pub mod bom;
pub mod coppermap;
pub mod cost;
pub mod current;
pub mod fab;
pub mod features;
pub mod geom;
pub mod impedance;
pub mod input;
pub mod landpattern;
pub mod lengths;
pub mod lengthtune;
pub mod liblint;
pub mod pairroute;
pub mod panel;
pub mod report;
pub mod review;
pub mod placement;
pub mod placetools;
pub mod route;
pub mod schreview;
pub mod silkplace;
pub mod space;
pub mod teardrops;
pub mod writers;
/// This engine's version. Every reply carries it as `engine` ("adom-eda-checks 0.3.0"), so a bridge never writes it by hand
/// (kicad-lane's replies said 0.1.2 for three releases after re-vendoring).
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
/// The checks this build answers, by standard verb name.
pub const CHECKS: &[&str] = &["assembly_check", "auto_classes", "board_report", "bom", "check_clearance", "check_orientation", "copper_balance", "cross_check", "current_capacity", "estimate_cost", "fab_check", "find_space", "footprint_from_land_pattern", "height_check", "impedance", "length_tune", "lint_library", "net_lengths", "panelize", "pin_pad_check", "place_decoupling", "placement_check", "plan_fanout", "plan_route", "return_path", "review_board", "route_pair", "schematic_review", "silk_designators", "teardrops", "thermal_vias", "via_fence"];
/// Run one check or writer by its standard name. The reply carries `engine`.
pub fn run(check: &str, input: &Value) -> Value {
let mut out = answer(check, input);
if let Some(o) = out.as_object_mut() { o.entry("engine").or_insert(Value::String(format!("adom-eda-checks {VERSION}"))); }
out
}
fn answer(check: &str, input: &Value) -> Value {
if let Some(out) = writers::run(check, input) { return out; }
match check {
"assembly_check" => assembly::assembly_check(input),
"auto_classes" => autoclass::auto_classes(input),
"board_report" => report::board_report(input),
"bom" => bom::bom(input),
"check_clearance" => placetools::check_clearance(input),
"check_orientation" => space::check_orientation(input),
"copper_balance" => coppermap::copper_balance(input),
"cross_check" => bom::cross_check(input),
"current_capacity" => current::current_capacity(input),
"estimate_cost" => cost::estimate_cost(input),
"find_space" => space::find_space(input),
"footprint_from_land_pattern" => landpattern::footprint_from_land_pattern(input),
"fab_check" => fab::fab_check(input),
"height_check" => bodies::height_check(input),
"impedance" => impedance::impedance(input),
"length_tune" => lengthtune::length_tune(input),
"lint_library" => liblint::lint_library(input),
"net_lengths" => lengths::net_lengths(input),
"panelize" => panel::panelize(input),
"pin_pad_check" => schreview::pin_pad_check(input),
"place_decoupling" => placetools::place_decoupling(input),
"plan_fanout" => placetools::plan_fanout(input),
"placement_check" => placement::placement_check(input),
"plan_route" => route::plan_route(input),
"return_path" => coppermap::return_path(input),
"review_board" => review::review_board(input),
"route_pair" => pairroute::route_pair(input),
"schematic_review" => schreview::schematic_review(input),
"silk_designators" => silkplace::silk_designators(input),
"teardrops" => teardrops::teardrops(input),
"thermal_vias" => features::thermal_vias(input),
"via_fence" => features::via_fence(input),
_ => input::refuse("not_supported", &format!("{check} is not a verb this engine answers (checks: {}; writers: {})", CHECKS.join(", "), writers::WRITERS.join(", "))),
}
}
#[cfg(test)]
mod tests {
#[test]
fn every_reply_names_the_engine_version() {
let r = super::run("copper_balance", &serde_json::json!({}));
assert_eq!(r["engine"], format!("adom-eda-checks {}", super::VERSION));
assert_eq!(super::run("no_such_check", &serde_json::json!({}))["engine"], r["engine"]);
}
}