AgentCanvas ← index / works
Visual agent design platform · embodied AI

AgentCanvas

One typed graph, two roles — a harness that runs embodied agents, and a scaffold that lets coding agents edit and verify them. Perception, memory, planning, and action become node-and-wire programs that execute live inside stateful simulators, with typed ports, batch-optimized evaluation, and episode-level logs that serve both.

editor.canvas// load · lay out · run
Recorded live from the editor — three acts. (1) Overview: the MapGPT executor (22 typed nodes) loads and auto-lays out as a node-and-wire graph. (2) Run it live: press Play and a real R2R episode runs end-to-end — the whole pipeline (map, planner LLM, the wires) executes while the in-graph Panorama Viewer floods with the agent's 36-view observation and the Thinking / Action logs fill with the planner's own words, viewpoint by viewpoint. (3) Inspect: the Logs Detail view of the same episode, scrolled top-to-bottom — every node firing, with the agent's 36-view panorama and candidate tiles rendered inline, fully recorded.
01 — why a substrate

Embodied agents have no shared substrate

Every embodied agent is bespoke plumbing — perception, memory, planning, and action hand-wired in Python and bolted to a single simulator. Swapping a module, swapping the simulator, or running the same agent across navigation, QA, and manipulation means rewriting the glue each time; heavyweight simulators reload per worker; orchestration is a hand-coded loop; and results rarely reduce to a number someone else can reproduce.

AgentCanvas makes the agent a single typed graphone JSON is one agent — run by a graph executor where typed wires and ports drive scheduling, simulators live as shared server-mode services, and nodes auto-discover with no central registry. The agent becomes a program: configurable, swappable, run at scale, and reproducible to a fixed SR / SPL / accuracy on one substrate that spans all three domains.

why.diagrambespoke glue → typed graph
A hand-wired Python agent bolted to one simulator, lifted into the real MapGPT executor as a typed node-and-wire graph with a back-edge loop BESPOKE PLUMBING agent.py bolted → MP3D AgentCanvas lifts to ONE TYPED GRAPH real MapGPT executor · 22 typed nodes loop Observe Update Map Build Options Render Prompt Planner LLM Parse Action MP3D: Step Thinking Log env (teal) · method (blue) · LLM (violet) · viewer (amber) — a loop is just a back-edge
The same agent, two ways. Bespoke: hand-wired Python bolted to one simulator. Lifted: the real MapGPT executor as a typed graph — observe → map → prompt → plan → act, with a back-edge loop and a live viewer tap.
why.diagramone substrate · three real executors
Three structurally different executors — MapGPT, Explore-EQA, VoxPoser — running on one graph executor; only the env nodeset is swapped NAVIGATION MapGPT single LLM-planner loop MP3D · 22 typed nodes SR / SPL EQA Explore-EQA TSDF map + VLM scoring HM-EQA · 28 typed nodes success · EM MANIPULATION VoxPoser LMP planner + nested graph LIBERO · 17 nodes (+nested) success % ↕ swap only this layer MP3D HM-EQA LIBERO GRAPH EXECUTOR one substrate · typed wires · ports · state · hooks
Three structurally different executors — a single LLM-planner loop, a TSDF+VLM frontier explorer, and an LMP planner with a nested sub-graph — all run on one graph executor. Only the env nodeset is swapped.
02 — the substrate

A typed graph, run by an executor

An executor is one node-and-wire JSON graph — the complete topology, with no hidden Python state; whatever mutates lives in state containers, not globals. Each node is a Python module that exposes typed input / output ports, and nodes are auto-discovered from nodeset libraries: env (simulators), method (the agent logic), model (LLM / VLM services), and policy (neural controllers) — swap a nodeset to swap a capability.

A graph executor runs it: typed wires connect compatible ports, and those wires drive the scheduling — there is no hand-coded orchestration loop, and a loop is just a back-edge.

substratenode · nodeset palette
A node is a typed Python module with typed ports; its colour marks the nodeset it comes from — env, method, model, or policy A NODE = A TYPED PYTHON MODULE method node Render Prompt topo_snapshot options_text prompt image_list typed ports in → module → typed ports out NODESET PALETTE — colour = where a node comes from envenv_mp3d · env_hmeqa · env_libero · env_simpler methodmapgpt · navgpt · voxposer · explore_eqa modelllmCall · vlm_prismatic · vlm_qwen · sam policypolicy_vla · policy_cma · policy_rt1x built-initer_in · iter_out · metrics · viewers auto-discovered · folder-form convention · no central registry
Every node is a typed Python module with typed ports; its colour marks the nodeset it comes from — env · method · model · policy, plus built-in scaffolding. Swap a nodeset to swap a capability.
03 — runtime isolation

Each nodeset, its own interpreter

Embodied research tools demand mutually incompatible Python environments — Habitat-Sim pins Python 3.8, modern SAM / HF models need torch ≥ 2, ROS-based SLAM wants its own stack. They cannot share one interpreter. So any nodeset can run in server mode: its own subprocess, its own interpreter (a named conda env), GPU-isolated.

There is no server code to write. AgentCanvas introspects the nodeset's typed ports and auto-generates an HTTP plugin server (/manifest + /call), then drops proxy nodes on the canvas that look and wire up exactly like local ones — an author never knows, or cares, which interpreter a node lives in. The same server mode is what fans a simulator nodeset out to N isolated workers under batch eval.

A server-mode node pays an IPC hop per call — typed payloads cross the process boundary as serialized values — so lightweight inner-loop logic stays local, while heavyweight or dependency-conflicting tools (simulators, big models) run server-side.

runtimeproxy nodes · isolated interpreters
One canvas with proxy nodes routing to nodesets that run in their own isolated interpreters via auto-generated HTTP plugin servers PRIMARY · agentcanvas · py3.10 — canvas + graph executor Render Prompt Planner LLM MP3D: Step + iter · viewers (local) HTTP HTTP model service vlm_prismatic · llmCall batched HTTP · singleton service habitat_vlnce · py3.8 env_mp3d nodeset auto HTTP · /manifest · /call solid = local node · dashed = proxy → real tool runs in an isolated interpreter
Any nodeset can run in its own subprocess and interpreter (a named conda env); AgentCanvas auto-generates an HTTP plugin server from its typed ports and drops proxy nodes on the canvas — identical to local ones. Habitat's Python 3.8 and a modern model stack coexist on the same graph.
04 — run at scale

Autonomous evaluation, batched at scale

Pick a graph and a worker count, then Start: AgentCanvas evaluates candidates across the simulator suite with no human in the loop. The same server mode that isolates a nodeset now fans it out — N tagged copies of the env subprocess (#0, #1, …) step concurrently, draining one shared queue of episodes, while every shared foundation-model node stays a single batched service the workers call together.

So weights load once, not per worker — VRAM stays flat — and there is no lockstep barrier: a naive batch eval makes every worker wait on the slowest module each step, but here workers proceed independently and the model batches whoever is ready within a short window. Throughput is bound by per-worker speed, not the slowest module; at worker count 1 the run is bit-identical to a plain sequential eval.

evaluatesync lockstep vs. per-module contract
Top: sync lockstep barriers every phase so fast episodes idle (the straggler effect). Bottom: AgentCanvas's per-module contract — workers proceed independently and the model batches whoever submits within ~50ms. ⚠ Sync lockstep · straggler effect every step waits on the slowest module — N workers can't help ep₁ep₂ep₃ep₄ sim FM sim barrier barrier barrier sim FM idle → throughput ≈ slowest module ✓ AgentCanvas · per-module contract elastic FM batching · workers proceed independently · no global barrier t−1tt+1 W₀W₁W₂W₃ batch{W₀,W₁}batch{W₀,W₁,W₂}batch{W₂,W₃} no idle between sim and FM each batch composition depends on who submits within 50ms → throughput limited by per-worker speed, not the slowest one
Top — sync lockstep: every phase waits on the slowest episode, so fast ones idle (hatched) — the straggler effect. Bottom — per-module contract: workers proceed independently and the model batches whoever submits within ~50 ms (batch{…}), so throughput tracks per-worker speed, not the slowest module.
05 — observability

Typed logs that render themselves

AgentCanvas logs every node firing — its typed input and output ports, tagged with step and firing index — alongside the internal breadcrumbs a node chooses to write: the planner's thought, its prompt, the parsed action, each tool call. So a candidate edit connects to the exact firings and decisions it caused.

Because the ports are typed, the log renders itself: RGB, depth, and the 36-view panorama come back as inline thumbnails, actions and metrics as structured chips and tables — not opaque blobs. Heavy values are offloaded to sidecar assets and referenced by path, so the record stays light.

Access to the evidence is necessary but not sufficient: the logs are there, but an optimizer still has to decide which to inspect and how to turn it into the next edit — credit assignment does not come for free.

episode.logone firing · OUTPUTS / NODE LOG / INPUTS
One firing in the Detail log — typed OUTPUTS, NODE LOG and INPUTS — beside the value renderers that turn each typed port into inline thumbnails, chips, and tables MapGPT: Planner LLM step 4 · firing #1 OUTPUTS response · TEXT “The lobby opens to the right — I'll head toward the far doorway and re-observe.” NODE LOG model=gpt-4o-mini · 1.8s · 2,413 tok · image_budget 12/12 INPUTS rgb · LIST[IMAGE] +30 plan · TEXT prompt · 3.1k chars ▸ VALUE RENDERERS typed port → how it renders LIST[IMAGE] ACTION go → vp3 METRICS SR 1.00 · SPL 0.82 TEXT heavy values → sidecar assets · log stays light
One firing in the Detail log: typed OUTPUTS · NODE LOG · INPUTS. Because ports are typed, the 36-view panorama comes back as inline tiles and actions / metrics render structurally — heavy values offloaded to sidecar assets.
logs.detailrecorded live · 36-view panorama
AgentCanvas Logs Detail view: the MapGPT MP3D 'Observe (panorama)' firing with its 36-view RGB panorama rendered inline as tiles, beside the typed view metadata.
The same thing live in the editor — MapGPT's Observe (panorama) firing, its 36-view RGB panorama rendered inline as tiles beside the typed view metadata, in the Logs Detail tab.
06 — usage

What you can do with it

From building one agent to letting a coding agent search thousands — the same typed-graph substrate underneath.

Build an embodied agent

Drag nodes from the nodesets, wire their typed ports, press Play, and watch it run live in the simulator.

build
Reproduce a published method

Re-implement MapGPT, NavGPT, Explore-EQA, or VoxPoser as a typed graph and hit its reported numbers.

reproduce
Run it across domains

Swap only the env nodeset to take the same agent from navigation (R2R) to EQA (HM-EQA) to manipulation (LIBERO).

cross-domain
Evaluate at scale

Fan a candidate out across episodes and workers, then read SR / SPL / success on a public split.

evaluate
Debug a rollout

Scroll the typed episode log — the panorama, the planner's thought, the action — firing by firing, to see why it failed.

debug
Search architectures with a coding agent

Drive builds and evals over HTTP / MCP so a coding-agent optimizer proposes edits and verifies them in simulation.

automate
07 — get started

Build, run, and search agent architectures

Build and run embodied agents as typed graphs, evaluate them in simulation at scale, and — when you want it — let a coding agent search architectures on the same substrate. The code, developer guide, tutorials, and NodeSet references are all online; AgentCanvas is also the runtime behind the paper Automating the Design of Embodied Agent Architectures.

Start building → Documentation Code Read the paper arXiv