Revisions and Conflicts
Every persisted scene in zindex has an immutable revision history. Understanding revisions is essential for safe multi-step agent workflows.
For the full agent behavioral guide, see How AI Agents Should Use Zindex.
How revisions work
- Creating a scene produces revision 1.
- Each successful
applyOpscall increments the revision by 1. - Revisions are immutable - earlier revisions are never modified.
- You can retrieve any previous revision with
GET /v1/scenes/{id}?revision=N. - You can list all revisions with
GET /v1/scenes/{id}/revisions.
The baseRevision field
When applying operations, you must include baseRevision in the request. You can also include an optional message describing what this batch does (like a git commit message):
{
"schemaVersion": "0.1",
"sceneId": "my-scene",
"baseRevision": 3,
"ops": [ ... ],
"message": "Added cache layer between API and database"
}
baseRevision declares which revision your ops were planned against. The server checks that baseRevision matches the scene’s current revision before applying.
Conflict detection (409)
If another writer updated the scene between your read and your write, baseRevision won’t match. The server returns 409 Conflict:
{ "error": "Revision conflict", "currentRevision": 5 }
This prevents stale writes from silently overwriting concurrent changes.
Conflict recovery pattern
- Read the latest scene:
GET /v1/scenes/{id} - Compare your intended change to the current state
- Re-plan a fresh minimal patch against the new revision
- Apply with the new
baseRevision
Do not:
- Blindly replay the same ops - the scene state may have changed
- Retry without re-reading - you’ll get 409 again
- Force-overwrite - there is no mechanism for this (by design)
Revision list with metadata
GET /v1/scenes/:id/revisions returns rich metadata per revision:
{
"sceneId": "my-diagram",
"currentRevision": 3,
"revisions": [
{ "revision": 3, "createdAt": "2026-04-01T12:00:00Z", "message": "Added cache layer", "summary": { "added": 1, "removed": 0, "modified": 1 } },
{ "revision": 2, "createdAt": "2026-04-01T11:30:00Z", "message": "Initial structure", "summary": { "added": 5, "removed": 0, "modified": 0 } },
{ "revision": 1, "createdAt": "2026-04-01T11:00:00Z", "message": null, "summary": null }
]
}
Each revision includes:
- createdAt - ISO 8601 timestamp
- message - the revision message (from
applyOpsrequest), or null - summary - change counts (added/removed/modified elements) compared to the previous revision. Null for revision 1.
Revision watermark on rendered output
When rendering a persisted scene, the output includes metadata in the bottom corners:
zindex.ai my-diagram | Rev 5 - 2026-04-01
- Bottom-left:
zindex.aibranding - Bottom-right: scene ID, revision number, and date
The watermark is binary - full metadata or nothing:
- Default ON for persisted renders (
POST /v1/scenes/:id/render, requires API key) - stamps both parts of the watermark - Never shown for stateless renders (
POST /v1/scenes/render, public) - stateless output is always clean, no watermark at all - Suppressible on persisted renders with
"showRevision": false- turns the full watermark off entirely (there is no middle state)
The watermark color adapts to the canvas background:
- Dark backgrounds: subtle light text (
rgba(255,255,255,0.25)) - Light backgrounds: subtle dark text (
rgba(0,0,0,0.2))
The scene ID in the watermark makes every rendered artifact self-identifying. An agent seeing a diagram can read the scene ID and call GET /v1/scenes/:id or dsp_get_scene to retrieve and edit it.
Diffing revisions
Compare any two revisions to see exactly what changed:
GET /v1/scenes/:id/diff?from=1&to=3
The to parameter is optional - defaults to the current (latest) revision.
Response:
{
"sceneId": "my-diagram",
"fromRevision": 1,
"toRevision": 3,
"summary": { "added": 2, "removed": 1, "modified": 1 },
"added": ["node-x", "edge-y"],
"removed": ["node-old"],
"modified": ["node-a"],
"changedConstraintIds": []
}
- added - elements present in
toRevisionbut not infromRevision - removed - elements present in
fromRevisionbut not intoRevision - modified - elements present in both but with different content
- summary - quick counts for each category
Use diff to:
- Show architectural changes in PR reviews
- Build incident timelines (what changed between healthy and broken states)
- Track how a diagram evolved over time
- Verify that an agent’s edits had the intended effect
Visual diff rendering
Render a color-coded diagram showing changes between revisions. Pass diff.fromRevision on the render request:
POST /v1/scenes/my-diagram/render
{ "format": "svg", "diff": { "fromRevision": 1 } }
Added elements render in green, removed as red dashed ghosts, modified in amber, unchanged muted. A color legend is included. See Rendering: Visual diff for details.
Best practices
- Always
GETthe scene before editing it - Always use the revision from the most recent read as
baseRevision - Keep op batches small so conflicts are less likely and easier to re-plan
- Treat 409 as a normal control flow signal, not an error - re-fetch and retry
Retrieving previous revisions
GET /v1/scenes/my-scene?revision=1
Returns the scene as it was at revision 1. Useful for:
- Inspecting what changed between revisions
- Debugging unexpected state
- Showing revision history to users