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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://wiki.adom.inc/adom/eda-bridge-standard/schema/board.schema.json",
"title": "Board model (routing_state)",
"description": "One PCB as every bridge's <prefix>_routing_state returns it. Millimetres, absolute board coordinates in the standard frame: the tool's origin and x axis, y up (a y-down tool such as KiCad negates y), angles counterclockwise as seen. Copper layers carry KiCad's names whatever the tool: F.Cu, In1.Cu..In30.Cu, B.Cu, and *.Cu for a pad on every copper layer. Reference: altium-bridge 0.2.75; settled points: docs/board-model.md.",
"type": "object",
"required": [
"units",
"revision",
"nets",
"tracks",
"arcs",
"vias",
"pads",
"components",
"polygons",
"outline",
"outlineEdges",
"unconnected"
],
"$defs": {
"xy": {
"type": "object",
"required": [
"x",
"y"
],
"properties": {
"x": {
"type": "number"
},
"y": {
"type": "number"
}
}
},
"pt": {
"type": "array",
"items": {
"type": "number"
},
"minItems": 2,
"maxItems": 2,
"description": "[x, y] mm"
},
"layer": {
"type": "string",
"description": "F.Cu | In<n>.Cu | B.Cu | *.Cu for copper; a non-copper layer is the tool's own name or id (L57 on Altium is Mechanical 1)"
},
"net": {
"type": "string",
"description": "the net's name; empty for no net (a hatched pour's pieces, free copper)"
}
},
"properties": {
"units": {
"const": "mm"
},
"file": {
"type": [
"string",
"null"
],
"description": "the board file's path"
},
"boardId": {
"type": [
"string",
"null"
],
"description": "identifies the board; the file path where there is one"
},
"revision": {
"type": "string",
"description": "a hash of copper, parts and outline: it changes when they change and only then. Edit verbs take it back as expectedRevision and refuse with stale_board when the board moved on. Independent of item order is better (KiCad's is); stable for an unchanged board is required"
},
"counts": {
"type": "object",
"description": "tracks, arcs, vias, pads, components, polygons, nets"
},
"unconnected": {
"type": "integer",
"description": "connections still to make, computed from the copper itself: per net, pads, tracks, vias and poured copper joined where they touch on a shared layer, and every group beyond the first is one connection. A group that is only poured copper (an island, or a pour that reaches no pad) is not counted: it goes in isolatedCopper. A stray track or via is counted. The tool's own count may ride along under its own key (altiumRatsnest, fusionAirwires)"
},
"splitNets": {
"type": "array",
"description": "nets whose copper is in more than one piece"
},
"isolatedCopper": {
"type": "array",
"description": "poured copper that touches nothing else of its net: listed, not counted in unconnected (KiCad's DRC calls it isolated copper, a warning)",
"items": {
"type": "object",
"required": [
"net",
"layer"
],
"properties": {
"net": {
"$ref": "#/$defs/net"
},
"layer": {
"$ref": "#/$defs/layer"
},
"at": {
"$ref": "#/$defs/xy",
"description": "a point on or in it"
},
"areaMm2": {
"type": "number"
}
}
}
},
"nets": {
"type": "array",
"items": {
"type": "string"
}
},
"tracks": {
"type": "array",
"items": {
"type": "object",
"required": [
"start",
"end",
"width",
"layer",
"net"
],
"properties": {
"id": {
"type": "string",
"description": "the track's handle for edit_tracks (optional): a bridge that answers edit_tracks gives one. It need only hold until the board changes, and it never counts toward revision"
},
"start": {
"$ref": "#/$defs/xy"
},
"end": {
"$ref": "#/$defs/xy"
},
"width": {
"type": "number"
},
"layer": {
"$ref": "#/$defs/layer"
},
"layerId": {
"description": "the tool's own layer id (optional)"
},
"net": {
"$ref": "#/$defs/net"
}
}
}
},
"arcs": {
"type": "array",
"items": {
"type": "object",
"required": [
"center",
"radius",
"startAngle",
"endAngle",
"width",
"layer",
"net"
],
"properties": {
"center": {
"$ref": "#/$defs/xy"
},
"radius": {
"type": "number"
},
"startAngle": {
"type": "number",
"description": "degrees, counterclockwise from +x"
},
"endAngle": {
"type": "number"
},
"width": {
"type": "number"
},
"layer": {
"$ref": "#/$defs/layer"
},
"net": {
"$ref": "#/$defs/net"
}
}
}
},
"vias": {
"type": "array",
"items": {
"type": "object",
"required": [
"position",
"size",
"drill",
"layers",
"net"
],
"properties": {
"position": {
"$ref": "#/$defs/xy"
},
"size": {
"type": "number",
"description": "diameter mm"
},
"drill": {
"type": "number"
},
"layers": {
"type": "array",
"items": {
"$ref": "#/$defs/layer"
},
"description": "[from, to]"
},
"net": {
"$ref": "#/$defs/net"
}
}
}
},
"pads": {
"type": "array",
"items": {
"type": "object",
"required": [
"ref",
"name",
"x",
"y",
"sizeX",
"sizeY",
"rotation",
"layer",
"drill",
"net"
],
"properties": {
"ref": {
"type": "string",
"description": "the part's designator; empty for a free pad (a mounting hole, a fiducial)"
},
"name": {
"type": "string",
"description": "the pad's number/name"
},
"x": {
"type": "number"
},
"y": {
"type": "number"
},
"sizeX": {
"type": "number"
},
"sizeY": {
"type": "number"
},
"rotation": {
"type": "number",
"description": "degrees, counterclockwise as seen"
},
"layer": {
"$ref": "#/$defs/layer"
},
"drill": {
"type": "number",
"description": "0 for SMD"
},
"net": {
"$ref": "#/$defs/net"
},
"shape": {
"type": "string",
"description": "round (a circle when sizeX = sizeY, otherwise a stadium: semicircle ends on the long axis) | circle | rect | roundrect | octagonal | rotated-rect | other. A tool's oval or obround is round. A custom-shape pad (copper drawn as regions) is its bounding rectangle: rect, rotation 0, with its real outline in copperPoints when the bridge has it"
},
"customShape": {
"type": "boolean",
"description": "the pad's copper is a drawn shape, not a primitive"
},
"copperPoints": {
"type": "array",
"items": {
"$ref": "#/$defs/pt"
},
"description": "a custom pad's real copper outline, absolute mm. Checks use it when present and the bounding rectangle otherwise. One drawn polygon can join several pads (a power FET's drain)"
}
}
}
},
"components": {
"type": "array",
"items": {
"type": "object",
"required": [
"ref",
"x",
"y",
"rotation",
"side"
],
"properties": {
"ref": {
"type": "string"
},
"x": {
"type": "number"
},
"y": {
"type": "number"
},
"rotation": {
"type": "number"
},
"side": {
"enum": [
"top",
"bottom"
]
},
"pattern": {
"type": "string",
"description": "the footprint's name"
},
"has3d": {
"type": [
"boolean",
"null"
]
}
}
}
},
"polygons": {
"type": "array",
"description": "pours as drawn (their boundary). What was actually poured is the pours model (pour_state)",
"items": {
"type": "object",
"required": [
"net",
"layer",
"points"
],
"properties": {
"net": {
"$ref": "#/$defs/net"
},
"layer": {
"$ref": "#/$defs/layer"
},
"points": {
"type": "array",
"items": {
"$ref": "#/$defs/pt"
}
},
"kind": {
"enum": [
"zone",
"graphic"
],
"description": "zone (a pour; the default when absent) or graphic (a filled copper shape drawn on the layer)"
}
}
}
},
"outline": {
"type": "array",
"items": {
"$ref": "#/$defs/pt"
},
"description": "the board outline's vertices in order"
},
"outlineEdges": {
"type": "array",
"description": "the outline as edges: line, or arc (center, radius, angle1, angle2 in degrees). Sample arcs finely (every 2 degrees) before measuring against them",
"items": {
"type": "object",
"required": [
"kind",
"start"
],
"properties": {
"kind": {
"enum": [
"line",
"arc"
]
},
"start": {
"$ref": "#/$defs/pt"
},
"end": {
"$ref": "#/$defs/pt"
},
"center": {
"$ref": "#/$defs/pt"
},
"radius": {
"type": "number"
},
"angle1": {
"type": "number"
},
"angle2": {
"type": "number"
}
}
}
}
}
}