Just the graph
You want JSON, a diagram in a doc, a check in CI, or an agent that can see structure.
nao analyze . -f json -o analysis.json
The engine →How it fits together
Most tools like this are one thing you install whole. nao is not: the analysis, the picture and the editor integration are separate programs in separate languages, and they depend on each other in one direction only. That is worth knowing before you install anything, because it decides how much you install.
A thin extension that embeds the visualizer as a webview and manages a `nao watch` process for the open folder. The graph is the same app; what the extension adds is everything that needs an editor.
A single-page Svelte app: force-directed graph, scope trees, filters, quality report. It speaks one small read-only HTTP API and does not care who answers it.
The `nao` and `elevator` binaries. Ten tree-sitter parsers feeding one shared model — entities, typed relationships, metrics, smells — with JSON, DOT, Mermaid and ASCII on the way out, plus an MCP server for coding agents.
The dependency, stated plainly
| Component | Lives in | Needs | Runs alone |
|---|---|---|---|
| Engine | src/ — Rust | Nothing. A Rust toolchain to build it, then it is one binary. | yes |
| Visualizer | ui/ — Svelte | A graph API — a running binary, or pre-baked files on a static host. | no |
| VS Code extension | vscode-extension/ — TypeScript | Both — it spawns the binary and embeds the UI. | no |
The arrow only ever points down. The engine has never heard of the UI; the UI has never heard of VS Code. That is why the engine is useful to an agent that will never draw anything, and why the same UI code runs in a webview and in a browser tab without a fork.
Pick your entry point
You want JSON, a diagram in a doc, a check in CI, or an agent that can see structure.
nao analyze . -f json -o analysis.json
The engine →You want to look at it — scopes, filters, the quality report — in a browser tab.
nao watch . --port 3200
The visualizer →You want the graph to follow your cursor, and a click on a node to open the file.
./scripts/install.sh
The extension →A consequence worth naming
Because the visualizer only ever talks to a small read-only HTTP API, that API does not have to be a running program. Every endpoint takes a slug and nothing else — no query parameters, no search — so the whole surface is a finite set of files.
Bake them once and any static host can answer them. The app cannot tell the difference, and never learns there is no engine behind it.
This site is the proof: /visualizer is the real UI out of the repository, served by files on a CDN. Nothing here analyzes anything.
Live versus frozen →# what this website does, in three commands
nao analyze ./some-repo -f json -o graph.json # the engine, once
cargo run --bin llvator-bake -- --visualizer # freeze every API response
# then: serve those files. No process, no analysis, no server.What is deliberately lost: anything that would re-run the analyzer. Scope changes, commit diffs and the on-disk context panel answer 403 on a frozen host, and work normally the moment you run the binary yourself.
And one more thing, off to the side
It is a second binary out of the same crate, reading .elv spec files instead of
source. It sits above all three components rather than inside the stack — the one
layer that is authored rather than derived.