Infra Diagrams
This page explains how nanoinfra stores infrastructure diagrams, what the agent may and may not do to one, where a secret goes, and what the gallery tells you when something is wrong.
A diagram here is not a picture. It is a document with ids: labelled nodes, directed edges, and a component type per node that the agent can reason about. The browser draws it, the agent reads and edits it, and both work on the same file.
Where a diagram lives
One JSON file per diagram, under your agent workspace:
~/.nanoinfra/workspaces/default/
└── diagrams/
├── 3f8c2a....json # one diagram, id = file name
├── .seeded # this workspace received the example diagrams
└── catalog/ # optional: your own component types
The id is 32 hex characters, minted when the diagram is created. That shape is enforced everywhere,
because the id becomes a file name and a value like ../../etc must never be able to become a path.
The example diagrams arrive once, the first time a workspace has no diagrams, and .seeded records
that it happened. Deleting the examples is a decision, and that marker is what keeps it one — an
empty gallery does not get refilled on the next start. Delete .seeded if you want them back.
.diagram-previews/ sits beside the workspace and holds no diagram content. It is explained under
Preview and apply.
Secrets belong in Secrets
A component field the catalog declares as kind: "secret" — a database password, an API key, a VPN
auth key — holds a reference and never a value:
secret://prod-db-password
Store the value under Settings → Secrets, then reference it by name in the diagram field. A save that carries anything else is refused, and the refusal names the field.
This is not a style preference. A diagram file is ordinary JSON on disk at mode 0644, it is included
in the WebUI detail payload, and it is sent to your model provider in two separate places: the
/infradiagrams prompt block and the get_diagram tool result. A password typed into that field
would travel all of those. The secret store does not: nothing reads a decrypted value back out of it,
which is exactly the property this field needs.
If you have a diagram from before this rule, it keeps working. The value is withheld from every reader — it does not reach the canvas, the payload or the model — and a warning names the file so you can move it into Secrets.
Preview and apply
When the agent changes a diagram it must show you the change first. update_diagram and
create_diagram default to dry_run=true, which validates the payload and returns a diff without
saving anything.
The server enforces that, and does not take the agent's word for it. When a preview is rendered, the gateway records a digest of exactly the payload an apply may write. An apply is refused when:
| Refusal | What it means |
|---|---|
| no preview was shown | the agent went straight to saving. Ask it to preview the change |
| the payload is not the one that was previewed | you approved a different change than the one being applied |
| the preview is over an hour old | a confirmation from earlier is not a confirmation of what is on disk now |
A preview authorizes one write and is spent by it, so a second save previews again.
Every diagram write is recorded in the audit log, under the mutate.local class. Settings → Gates →
Audit lists them.
Your layout is yours
The agent does not move a node you placed. When it adds nodes, it places the new ones clear of the others; the position of every node that already existed comes from the file, whatever the agent sent.
So rearranging an existing diagram is your action, not the agent's. Use Auto layout in the editor when you want the whole canvas re-flowed.
What the gallery tells you
A row in the gallery can carry a state, and each one means something different:
- Changed outside nanoinfra. The file's content is not what the store wrote. Something else edited
it — a shell command, a file tool, a hand edit, a copy from another workspace. The content still
renders, and its
updated_atis not evidence of anything, because a direct write can claim any history. - Unreadable. The file is on disk and cannot be parsed. Nothing was deleted. This used to be a silent absence, which sent people looking for a file they still had.
- Unusable file name. The file name is not a valid diagram id, so nothing can open it or delete it through the app. Rename it to 32 hex characters, or remove it yourself.
What the store refuses
The store is the last place that can say no to a document no canvas can draw:
- two nodes sharing an id, because a diff keyed by id cannot show them both — you would approve "one node modified" and get two nodes under one id
- a node that is its own parent, or a parent chain that loops
- a node whose component type or provider is not in the catalog
- a format version this build does not know, which is refused rather than parsed by the wrong rules and rewritten
Editing from more than one place
A diagram carries a revision that advances on every write. When the agent applies a change, it carries the revision it read, and the store refuses a write built on a stale one. So this sequence ends in a refusal rather than a lost edit:
- the agent reads the diagram and previews adding a node
- you add a load balancer in the browser and save
- you confirm the agent's change
The agent is told the diagram moved and reads it again. Before this, your load balancer was gone and the only trace was a diff the agent may not have relayed.
Your own component types
Drop a JSON file under <workspace>/diagrams/catalog/ to add component types and providers beyond the
built-in catalog. list_diagram_components shows the agent the merged result, including whether the
skill that operates a component is installed and enabled — a skill you switched off reads as off,
in the agent's view and in the browser's alike.
Pointing the agent at one diagram
Two ways, and they do different things.
@diagram: in the composer references it. The list narrows as you type and matches the targets
as well as the name; the agent gets the id, the name, the node count and the targets — enough to
decide whether reading the whole thing is worth a get_diagram call. A reference costs almost
nothing, which is why an automation can carry one without paying for the canvas on every scheduled
run.
/infradiagrams <name-or-id> attaches it, putting the diagram's contents in the conversation.
That is the verb for "read this now", and it works on any channel rather than only in the WebUI.
Either way the content is framed as data and not as instructions: labels and config in a diagram are written by whoever has WebUI access, or by an earlier turn, so the agent is told to read them and not to follow a directive found inside them.
Related
- Memory — how the agent's durable knowledge works, and what git versions
- Capability Gates — the policy a remote action passes through
- Secrets and Servers — where a value goes, and how a server uses one