1. Read a design

Confirm the tool read your board the way you expect, before trusting anything downstream.

Every finding in every later rung assumes the tool read your board correctly. A schematic that half-loaded still produces a report, and that report looks exactly like a real one. So the first thing to do with a new design is confirm what was read, not check it.

The board

This rung runs on a real board, Antmicro’s open-source baseboard for the NVIDIA Jetson AGX Thor module, drawn in KiCad 9 and published under Apache-2.0. It is not in the repo, because it is someone else’s design, so fetch it first:

git clone https://github.com/panyam/agni
cd agni
make samples-oracle
cd tools/samples/boards/jetson-agx-thor-baseboard

Run every command on this page from that folder. Here is one of its fifteen sheets, the power entry. Drag to pan, scroll to zoom.

A carrier board takes a compute module through one large connector and breaks its interfaces out to the outside world. This one carries USB-C, an SFP cage, two M.2 sockets, two camera connectors and an FMC+ expansion header, and it makes all their rails from one DC input. It has 1123 parts on fifteen sheets.

The commands below read the same files, and Agni rendered this drawing from them. It is not a screenshot of another tool.

What was read

$ agni stats .
design:              Antmicro Baseboard for Jetson AGX Thor
source format:       kicad-sch
libraries:           38
components:          1123 (unique ref_des)
sections:            1141 (source instances)
multi-section:       3 (one ref_des, several sections)
nets:                1355

You already know roughly how many parts and nets your board has. Compare against that number first. Suppose the component count is half what you expect. Then a library or a sheet did not resolve, and every rule that quantifies over parts will quietly under-report. Nothing downstream will tell you, because a rule that finds no members produces no findings. That output is indistinguishable from a rule that found nothing wrong.

sections counts source instances and components counts distinct reference designators. They differ when one part is drawn as several units, which is normal. multi-section is how many parts that applies to.

The folder holds one design.yaml, which names the root schematic as the design’s entry and the .kicad_pcb as the same board’s copper. So naming the folder reads the whole design.

Did anything fail to load

stats tells you what came through. validate tells you whether it holds together, file by file:

$ agni validate .
FILE                                 FORMAT  STATUS  DETAIL
csi.kicad_sch                        kicad   ok      73 comps, 129 nets · 1 sheets, 125 placements (125 resolved), 457 wires
dcdc.kicad_sch                       kicad   ok      198 comps, 99 nets · 1 sheets, 374 placements (374 resolved), 753 wires
expansion_connector.kicad_sch        kicad   ok      38 comps, 327 nets · 1 sheets, 77 placements (77 resolved), 989 wires
jetson-agx-thor-baseboard.kicad_pcb  kicad   ok      1123 comps, 1387 nets
jetson-agx-thor-baseboard.kicad_pro  kicad   ok      1123 comps, 1387 nets · 15 sheets, 1855 placements (1855 resolved), 6231 wires
jetson-agx-thor-baseboard.kicad_sch  kicad   ok      1123 comps, 1355 nets · 15 sheets, 1855 placements (1855 resolved), 6231 wires
level_shifter_x8.kicad_sch           kicad   ok      6 comps, 23 nets · 1 sheets, 18 placements (18 resolved), 42 wires
m2.kicad_sch                         kicad   ok      53 comps, 122 nets · 1 sheets, 76 placements (76 resolved), 234 wires
peripherals.kicad_sch                kicad   ok      74 comps, 70 nets · 1 sheets, 131 placements (131 resolved), 330 wires
power.kicad_sch                      kicad   ok      76 comps, 44 nets · 1 sheets, 137 placements (137 resolved), 241 wires
recovery_usb.kicad_sch               kicad   ok      49 comps, 52 nets · 1 sheets, 78 placements (78 resolved), 211 wires
sfp.kicad_sch                        kicad   ok      35 comps, 27 nets · 1 sheets, 54 placements (54 resolved), 118 wires
som_io.kicad_sch                     kicad   ok      40 comps, 181 nets · 1 sheets, 77 placements (77 resolved), 449 wires
som_io2.kicad_sch                    kicad   ok      75 comps, 291 nets · 1 sheets, 103 placements (103 resolved), 708 wires
som_power.kicad_sch                  kicad   ok      116 comps, 64 nets · 1 sheets, 175 placements (175 resolved), 315 wires
usb.kicad_sch                        kicad   ok      88 comps, 155 nets · 1 sheets, 138 placements (138 resolved), 511 wires
usb_debug_pd.kicad_sch               kicad   ok      96 comps, 93 nets · 1 sheets, 146 placements (146 resolved), 374 wires
usb_dp.kicad_sch                     kicad   ok      65 comps, 70 nets · 1 sheets, 100 placements (100 resolved), 316 wires
usb_hub.kicad_sch                    kicad   ok      131 comps, 129 nets · 1 sheets, 194 placements (194 resolved), 557 wires

19 passed, 0 failed, 4 skipped (no reader)

Every file reads. The board and the project file count 1387 nets against the schematic’s 1355, because each view of a board names and splits nets its own way, and the design’s count is the schematic’s, since it is the entry. The list is the folder rather than the design. So it includes each sub-sheet read on its own, the project file, the board, and usb.kicad_sch, which sits in the folder although the root never includes it. That form helps when someone has just handed you a folder of exports and you want to know which of them the tool can actually read.

A file with an extension nothing claims is reported as skipped, not failed, so a silently skipped file never becomes a missing report.

The failure that costs the most

The board is fifteen files. Someone working on its power tree opens som_power.kicad_sch and points the tool at the file in front of them:

$ agni stats som_power.kicad_sch
design:              Antmicro Baseboard for Jetson AGX Thor
source format:       kicad-sch
libraries:           19
components:          116 (unique ref_des)
sections:            116 (source instances)
multi-section:       0 (one ref_des, several sections)
nets:                64

The design’s own name, a hundred and sixteen components and sixty-four nets. Nothing says that this is one sheet of fifteen. A sub-sheet is a complete KiCad file with its own parts and wires, and it connects to other sheets by name, so read alone it is a small, plausible design.

Now run the checks on it. It does not error, and it is not silent either:

$ agni check som_power.kicad_sch
findings by rule:
  bulk-cap               1
  intent/exposure-declared 9
  unconnected-pin        372

first 50:
  [warning] bulk-cap: Net-(D1-C) (power rail has no bulk capacitor)
  [warning] intent/exposure-declared: J10 (J10 is declared internal, and the design has no component J10)
  [warning] intent/exposure-declared: J11 (J11 is declared internal, and the design has no component J11)
  [warning] intent/exposure-declared: J13 (J13 is declared internal, and the design has no component J13)
...
382 finding(s) total

The design read whole, for comparison:

$ agni check .
79 finding(s) total
24117 subject(s) considered by 35 rule(s), 615 not considered (--verdicts for the detail)

More findings from one sheet than from the whole board. All 372 unconnected-pin findings are pins of the module connector J1. J1’s signals go to the other fourteen sheets, and this read never opened those. The exposure-declared warnings are the one clue, saying the design has no J10, no J11, no J13. Nothing in the output says “you read one sheet of a hierarchy”. It looks like a board in serious trouble, and a reader who skipped stats would spend an afternoon on it.

Name the design, the folder or its root schematic, and the hierarchy is walked from the top.

So this rung comes first.

A summary you can share

agni intake produces a description of the design that is safe to hand to someone who should not see the design itself. It carries counts, classes, rail voltages, and the parts list, and it structurally cannot carry a net name or a connection.

$ agni intake .
## Aggregates
- Components: 1123 | Sections: 1141 | Nets: 1355

## Class summary (query-derived)
| Class | Ref count |
|-------|-----------|
| resistor | 403 |
| capacitor | 377 |
| test_point | 115 |
| diode | 82 |
| ic | 55 |
| tvs | 39 |
| transistor | 36 |
| led | 34 |
| connector | 20 |
| inductor | 8 |
| clock | 4 |
| oscillator | 4 |
| zener | 1 |
| unclassified | 23 |

## Rails (nominal only; net names withheld)
- 1.15V
- 1.8V
- 3.3V
- 5V
- 12V
- 16V
- 20V

## Parts (BOM by distinct type; --parts full for the per-component AVL)
...

Read the class summary as a second opinion on the read. A large unclassified count is the same warning as a low component count, arriving from a different direction. Here it is 23, and no rule needs a class for any of them. They are thirteen standoffs, the three mounts for the module and the M.2 cards, six buttons, and a coin-cell holder.

The rails section prints nominal voltages and withholds the net names. The whole command follows that pattern. It lets the structure of the design cross the boundary and keeps the design itself back.

Then read the gaps

The intake’s parts table carries each part’s MPN, because this board’s schematic records them. It cannot say yet which parts have a datasheet behind them. That needs a parameter set, a project’s params/ or --params <dir>, and with one attached the intake ends with the parts that have none. That list is the work queue for rung 6.

Next

Run the catalog, now that you trust the read.