Skip to content

Driving the Canvas from an Agent

This page is the practical pattern behind Draw a diagram from an agent — the same steps, generalized past a single rectangle.

The pattern: discover, read, write, check

  1. Discover the tools available — server/discover's capabilities or a tools/list call — rather than hardcoding tool names. See Tool Namespaces.
  2. Read before you write. Call canvas_get_state to get the current scene and its revision. You need that revision for step 3 regardless of how confident you are that nothing's changed since your last call.
  3. Write, carrying that revision as expectedRevision and a clean, single-line reason. Every write tool — creating, updating, moving, connecting, locking, deleting, or restoring elements — follows this same shape. See MCP Tools for the full list.
  4. Check the outcome explicitly. A write returns applied, proposed, conflict, or rejected — never a bare success/failure boolean, and never an exception for a normal disagreement like a stale revision. See Revisions & Conflicts for handling anything other than applied.

Reading only part of a large scene

canvas_query_region reads the elements within a bounded region rather than the whole scene — useful once a canvas has grown large enough that pulling the entire state for every read is wasteful. It's a read, so it needs no role beyond viewer and never touches the revision counter.

Protecting elements mid-edit

canvas_lock_elements locks specific elements against concurrent modification. Reach for it when a multi-step change to a group of elements would otherwise be vulnerable to another writer touching the same elements between your steps — locking narrows the window a conflict can come from, rather than eliminating revisions entirely.

Deleting and restoring

canvas_delete_elements and canvas_restore_elements are both ordinary writes, following the identical outcome contract as everything else in the table — a deletion that would conflict with what's actually on the canvas returns conflict exactly like a move or an update would. Nothing about delete/restore is a special case in the outcome contract.

Role still governs every write in this pattern

None of the steps above change the fact that a write from a viewer returns rejected, and a write from a commenter returns proposed rather than applying directly. See Roles & Permissions — confirm the calling agent's role before debugging anything else if writes keep coming back rejected.

Confirming it landed

A canvas is shared state, not a private view an agent renders for itself. A change that resolves to applied is visible to a human looking at the same canvas in NEXUS immediately, and to every other agent with at least viewer on it via its own next canvas_get_state call — there's no separate publish or sync step.

Where to go next

Built with purpose.