AgentCanvas / Pages / Developer Guide / Core / Decisions / Canvas / ADR-canvas-002
2026-03-28
Date
2026-03-28
Status
accepted
Field
canvas
Old ID
ADR-010

Context

Despite ADR-canvas-001 declaring a flat workspace, the frontend still had two separate worlds: an outer editor (FlowCanvas with 7 node types, nodeTypes.ts, nodeCatalog.ts) and an inner editor (InnerGraphEditor with 18+ node types, innerNodeTypes.ts, innerNodeCatalog.ts). Each used different node registries, different catalogs, and different editor components. Users editing a composite subgraph saw a completely different node palette than the root canvas. The two-layer split was a code-level artifact, not just a UX pattern.

Decision

(1) Unified node registry (unifiedNodeTypes.ts): single map of ~25 node types used at every graph level — root canvas and any subgraph depth. Merges all inner types (envStep, llmCall, etc.) + outer types (compositeNode, output viewers). (2) Unified catalog (unifiedCatalog.ts): single sidebar catalog with categories (Environment, LLM, Prompt, Loop Control, Output, Composite, Agent Presets, etc.). Old presets become compositeNode entries with preset subgraphs. (3) Unified editor (UnifiedGraphEditor.tsx): dual-mode component — root mode reads from Zustand store, subgraph mode uses local state with save-back. Both modes use the same unifiedNodeTypes and share drag-drop/connection logic. (4) Execution toolbar (ExecutionToolbar.tsx): Play/Pause/Stop controls extracted from AgentLoopCanvasNode into standalone toolbar. Root canvas graph serialized directly via getGraphForExecution(). (5) Graph save/load sidebar: Frontend API client gains graph CRUD methods (listGraphs, saveGraph, etc.). NodeLibrary sidebar shows "Saved Graphs" section — entries are draggable (drop as compositeNode), loadable as root, and deletable. SaveGraphDialog modal for naming/saving. (6) Flat templates: Default templates migrated from outer-layer format (habitatEnv → agentLoop → outputs) to flat format (preset inner nodes + output viewers directly on root canvas). (7) Canonical types (canvas/types.ts): GraphDefinition, NodeDef, EdgeDef, CatalogEntry moved to a single canonical location.

Alternatives

(a) Keep two editors, just share the same node registry. (b) Remove composites entirely and go fully flat (no nesting). (c) Make the inner editor the only editor and wrap the root in a virtual composite.

Rationale

One editor, one registry, one catalog is the simplest mental model — researchers don't need to know they're "inside an inner graph" vs. "on the root canvas." The dual-mode UnifiedGraphEditor preserves the save-back pattern for composites (which needs local state + dirty tracking) while keeping root-level editing simple (direct Zustand). The backend needed zero changes — GraphExecutor already accepted any GraphDefinition. Graph save/load to sidebar completes the workflow: design → save → reuse. Old files are deprecated with re-export shims, not deleted, for gradual migration.

Affected docs

architecture.md, blueprint.md, glossary.md, roadmap.md, canvas-system.md, graph-system.md, capabilities/real-time-observability.md