The .nbflow Schema (Light)¶
A .nbflow is a JSON file that describes a complete workflow — every node, every link, every property. This page covers the schema at a level useful for understanding what the agents produce. The full schema is too dense for a wiki page; this is the navigable subset.
High-level shape¶
{
"name": "XYZG1-V0-3",
"tabs": [
{
"name": "Account A",
"graphData": {
"nodes": [ /* ... node objects ... */ ],
"links": [ /* ... link tuples ... */ ]
}
},
{
"name": "Account B",
"graphData": { /* ... */ }
}
]
}
Top-level fields:
name— the workflow's version-stringed name (matches the file basename)tabs— array. One tab per account in a multi-account workflow.
Each tab has:
name— the account code or labelgraphData— the nodes and links that make up the graph for this account
Nodes¶
Each node in graphData.nodes is an object:
{
"id": 12,
"type": "nanobanana/NanobananaAPI",
"title": "Scene 03 — image gen",
"pos": [120, 240],
"size": [240, 180],
"inputs": [
{"name": "prompt", "type": "string", "link": 45},
{"name": "image 1", "type": "*", "link": 8},
{"name": "image 2", "type": "*", "link": null}
],
"outputs": [
{"name": "output", "type": "*", "links": [67]}
],
"properties": {
"model": "nano_banana_2",
"outputCount": 4,
"aspectRatio": "9:16",
"_savedImages": ["https://pub-xxx.r2.dev/.../scene03-c1.png", "..."]
}
}
Key fields:
| Field | Purpose |
|---|---|
id |
Unique numeric ID for this node. Globally unique across all tabs in a multi-account file. |
type |
Node type identifier (e.g. nanobanana/Prompt, nanobanana/NanobananaAPI, nanobanana/Veo3, nanobanana/Media, Approve) |
title |
Human-readable label (shown in PatchWork UI) |
pos |
Canvas position [x, y] for visual layout |
size |
Canvas size [width, height] |
inputs |
Array of input slots. Each has name, type, and link (ID of the link feeding it, or null) |
outputs |
Array of output slots. Each has name, type, and links (array of link IDs originating from it) |
properties |
Type-specific properties (prompt text, model name, R2 URLs of generated outputs, etc.) |
Links¶
Each link in graphData.links is a tuple (5-6 element array):
[
45, // link_id
3, // source_node_id
0, // source_slot_index
12, // target_node_id
0, // target_slot_index
"string" // type (optional)
]
This represents an edge: output slot 0 of node 3 connects to input slot 0 of node 12.
Important: links live in TWO places:
- The central
tab.graphData.linksarray (above) - The per-node
outputs[].linksandinputs[].linkreferences
These must stay in sync. If they don't, you get the stale-per-node-refs bug.
Node types you'll see¶
| Type | Purpose |
|---|---|
nanobanana/Prompt |
Holds prompt text. Modes: plain, template (with {placeholder}), dynamic (multi-row) |
nanobanana/Media |
Holds an image (reference upload or generated output) |
nanobanana/NanobananaAPI |
Generates images via G-Labs / NanoBanana 2 |
nanobanana/Veo3 |
Generates video clips via Veo 3.1 |
Approve / Approval |
Gate node — surfaces candidates in a gallery for the user to pick |
Each type has type-specific properties fields. See Chapter 2's Node Types Reference for the per-type properties.
What gets serialized¶
When the PatchWork Importer assembles a .nbflow:
- All node positions / layouts
- All prompt text
- All node properties (model, outputCount, etc.)
- All wiring (links + per-node refs)
When the Generation Runner finishes a pass:
- The generated R2 URLs get added to each gen node's
properties._savedImages/properties._savedClips - The Approve nodes track which candidate was picked
- The whole file is exported as
-generated.nbflow
The -generated.nbflow is the same shape as the input, just with R2 URLs baked in.
What's NOT in the schema¶
- API keys / credentials (these live separately)
- The G-Labs tunnel URL (set in PatchWork's app-level settings)
- Generation history beyond the latest pass (use git + version registry for that)
- User picks across multiple browser sessions (stored in browser local storage, not in the file)
Multi-account specifics¶
In a multi-account .nbflow:
- Each tab has its own complete
graphData— own nodes, own links - Node IDs must be globally unique across ALL tabs (not just per-tab unique)
- Reference image Media nodes are per-tab — each account's tab has its own Media node with the account's avatar reference URL
This is the source of the "renumber" requirement during fan-out — duplicate IDs across tabs break everything.
When you'd actually read the schema¶
Most of the time, you don't. You work through PatchWork's UI or by talking to Claude.
You'd dig into the JSON when:
- Diagnosing a build failure (sanity check told you a specific node is wrong)
- Writing a custom script that mutates
.nbflowfiles (fan-out, variant patcher) - Manually fixing a broken link or node
- Recovering from a corrupted file
For all of those, the pre-generation sanity check gives you specific node IDs to look at, so you're not reading the whole file — you're inspecting specific nodes.
When you're ready¶
→ Next: Pipeline Variants — AI Self / Voice Cloning — specialized pipeline configurations for when the standard workflow doesn't fit.