3. See it

Draw the board, and get a picture of a netlist that has no drawing.

A finding names a net. Nobody thinks about a board as a list of net names, so at some point you need a picture. There are two different situations here and they need different answers.

If your design carries its own geometry, the tool draws that geometry, and the picture matches what your CAD tool would draw. If your design is a netlist, there is no geometry to draw, because a netlist records what is connected and never records where anything sits. In that case the tool computes a layout from the connections.

The Jetson baseboard is the first case. Run the next command from its folder, as in rung 1.

Draw a sheet

$ agni render . --sheet Power -o power.svg
note: reading jetson-agx-thor-baseboard.kicad_sch (the entry design.yaml declares), with board geometry from jetson-agx-thor-baseboard.kicad_pcb.
wrote power.svg (sheet "Power", 137 placements, 241 wires)

The command reads placements and wires out of the file rather than computing them, so the result is the drawing somebody drew. Faithful is the default. --sheet takes a sheet’s name or its index, and without it you get the root sheet, which on a hierarchical design is mostly the boxes standing for the others.

The design has sixteen sheets in all. Fifteen come from the schematic. The sixteenth, Board, is the copper. It comes from the .kicad_pcb that the design’s design.yaml declares, and the viewer at the end of this page draws it.

Draw a netlist

The other case needs a design with no drawing, and the Jetson board does not have one. The synthetic board in examples/tutorial-project ships an EDIF netlist, gateway.edn, for exactly this, so run the next two commands from that folder instead:

$ agni render designs/gateway/gateway.edn --layout layered -o gateway.svg
note: reading gateway.edn with sheets from gateway.kicad_sch and board geometry from gateway.kicad_pcb (declared by designs/gateway/design.yaml). Pass --as-named for the file alone.
layout "layered": 19 nodes, 15 nets, 56 segments, 95 crossings, edge length 20826
wrote gateway.svg (sheet "netlist graph", 19 placements, 15 wires)

The line it prints is a quality report on the drawing, not on your board. crossings counts wires that cross each other, and crossings mainly make a generated schematic hard to follow.

This is a drawing of the netlist, not a reproduction of a schematic. Parts sit where the layout algorithm put them. It is for following connectivity, not for judging the layout itself.

A computed layout works well on a board of this size. On the Jetson’s 1123 parts the best of the five layouts below still crosses wires about 75,000 times, so it is for a netlist that has no drawing, never a substitute for one.

Pick a layout

There are five, and the board decides which one reads best, so compare them rather than guess:

$ agni render designs/gateway/gateway.edn --compare
layout      nodes  nets  segments  crossings  bends  edge-length  stress  truth-residual
force       19     15    56        43         0      9052         0.346   0.997
grid        19     15    56        133        0      7798         0.486   0.978
layered     19     15    56        95         0      20826        0.582   0.960
orthogonal  19     15    84        104        28     9200         0.457   0.961
stress      19     15    56        73         0      7218         0.457   0.961

For this board force has by far the fewest crossings and grid is the worst by that measure, while stress draws the most compact picture by edge length. Only orthogonal bends wires into right angles, as a schematic normally draws them, and it costs more segments and more crossings.

Lower stress means the drawn distances better match how far apart things actually are in the connection graph. There is no single winner. Render the two or three that score well and look at them.

The same board, twice

Back in the Jetson board’s folder, the .kicad_sch and the .kicad_pcb are two views of one design. The obvious question is whether they still agree. Ask directly, reading each file as itself with --as-named rather than as the design its design.yaml declares:

$ agni diff --as-named jetson-agx-thor-baseboard.kicad_sch jetson-agx-thor-baseboard.kicad_pcb
diff jetson-agx-thor-baseboard.kicad_sch -> jetson-agx-thor-baseboard.kicad_pcb

Components: +0  -0  ~0
Nets:       new 32  deleted 0  renamed 0  hard 10  soft 0

Nets changed (42):
  [hard]    unconnected-(U11-GL-Pad10): +[] -[U11.10 U11.28]
  [hard]    unconnected-(U12-GL-Pad10): +[] -[U12.10 U12.28]
  [hard]    unconnected-(U13-GL-Pad10): +[] -[U13.10 U13.28]
  [hard]    unconnected-(U30B-DRAIN1-Pad15): +[] -[U30.15 U30.19 U30.8]
  [hard]    unconnected-(U30C-DRAIN2-Pad52): +[] -[U30.52 U30.57 U30.7]
  [hard]    unconnected-(U36-Pad4): +[] -[U36.7]
...

No component changed, and no net was renamed or lost. The changes that remain are one shape. Some parts have several pins of one function stacked on top of each other, such as a regulator’s GL pins or a PD controller’s drain pins. On the schematic those pins touch, so they form one no-connect net. KiCad’s board gives each unconnected pad a net of its own, suffixed _1, _2. That is a real difference in how KiCad records the two views, and it is the only one.

The whole engine depends on that near-empty delta. Analysis runs over one internal representation, and once the file is read, the format you started from stops mattering. A diff of two views reads this cleanly for two reasons. The reader names a schematic’s nets exactly as KiCad does. And the diff compares only what both views record, so a board’s silence about a part’s symbol library is not a change.

This is also the practical way to check a CAD migration. Export from the old tool and the new one, diff the two, and a net delta you can explain line by line is real evidence the design survived the move.

In the browser

agni open serves one design and prints the URL that shows it. It needs the viewer’s built assets. A checkout builds them into web/ with make ui, and agni open looks for them in ./web unless told otherwise. The board’s folder is four levels below the checkout, so point at them from there:

agni open . --web-dir ../../../../web

It picks a free port on loopback, so it will not collide with anything you already have running, and it serves only this design and the project around it. The URL it prints goes straight to the board rather than to a file browser. Without the flag it stops before serving anything, with an error that names the flag and the two other ways to say the same thing.

AGNI_WEB_DIR and a web_dir: line in agni.yaml do the same thing without repeating the flag. A build that is not a release, such as make agni or go install ...@main, has no viewer bundle of its own. From there use a checkout’s web/ after make ui, or the container image. A release binary finds its own viewer.

The viewer pans and zooms, and its panels run the same checks the CLI runs, over the same catalog, so the findings you saw in rung 2 appear against the drawing rather than as a list. The viewer draws a design with no drawing, such as gateway.edn alone, on the grid layout, and a note above the canvas names the file that would draw it. The Board sheet in its list is the copper. Later rungs add tiers to that catalog, and the viewer picks them up the same way the CLI does.

agni open also prints a ready-made agni check command pointed at the server it just started. Rung 11 uses that command to turn a report’s subjects into links.

For several designs at once, or for a server other people reach, agni serve takes a mount per folder, and finds the viewer’s assets the same way.

Next

Your names, where the tool stops being generic and starts knowing your team’s conventions.