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.