Canvas, Codebase & Design Patterns
Canvas UI, codebase structure, and key design patterns.
Part of the Comprehensive Technical Documentation. Definitive reference based on a non-invasive scan of the molecule-core repository.
15. Canvas UI
Tech Stack
| Layer | Technology |
|---|---|
| Framework | Next.js 15 (App Router) |
| Graph | React Flow v12 (@xyflow/react) |
| State | Zustand |
| Styling | TailwindCSS v4 |
| Real-time | Native WebSocket API |
Core Interactions
- Drag-to-Nest: Drag workspace over another → overlap detection → highlight → drop → update
parent_id - Right-Click Menu: Open Details/Chat/Terminal, Restart, Duplicate, Export Bundle, Expand/Collapse Team, Extract from Team, Delete
- Template Palette: Empty state shows up to 6 templates + "Create blank workspace"
- Onboarding Wizard: 4-step guided setup tracked in localStorage
10-Tab Operations Panel
| # | Tab | Function |
|---|---|---|
| 1 | Chat | A2A conversational interface with session history (last 20 messages) |
| 2 | Activity | Rich operation log — A2A messages, task updates, logs, skill promotions (filterable) |
| 3 | Details | Workspace metadata, runtime summary, status, Agent Card, restart/pause controls, peer list |
| 4 | Skills | Live skill display from Agent Card — metadata, tags, examples |
| 5 | Terminal | WebSocket shell into workspace container |
| 6 | Config | Structured YAML editor — runtime, skills, tools, A2A, delegation, sandbox settings |
| 7 | Files | File browser + editor for /configs, /workspace, /home, /plugins |
| 8 | Memory | Scoped memory view (LOCAL/TEAM/GLOBAL) + key/value workspace memory with TTL |
| 9 | Traces | Langfuse trace viewer — every LLM call with input/output/tokens/cost |
| 10 | Events | Structure event stream — real-time workspace change log |
Real-Time Architecture
| Phase | Mechanism |
|---|---|
| Initial load | GET /workspaces → Zustand store hydration |
| Live updates | WebSocket events → applyEvent() → instant Canvas re-render |
| Position persistence | onNodeDragStop → PATCH /workspaces/:id with x, y |
| Error recovery | Error boundary with reload button + hydration retry banner |
18. Codebase Structure
Python Runtime (95 files)
workspace/
├── main.py # Entry point (startup sequence)
├── config.py # Config parsing → dataclasses (120+ lines)
├── heartbeat.py # 30s heartbeat loop
├── preflight.py # Startup validation
├── plugins.py # Plugin rule/skill injection
├── coordinator.py # Team lead routing
├── prompt.py # System prompt builder
├── adapter_base.py # BaseAdapter + AdapterConfig contract
├── adapters/
│ ├── __init__.py # Adapter registry shim (resolves ADAPTER_MODULE)
│ ├── base.py # Re-exports the BaseAdapter interface
│ └── shared_runtime.py # Shared execution logic
│ # Per-runtime adapters live in standalone
│ # molecule-ai-workspace-template-* repos
├── tools/ # 14 tool files
├── skills/
│ ├── loader.py # SKILL.md parser + tool loader
│ └── watcher.py # Hot-reload file watcher
└── tests/ # 148 pytest testsGo Platform (94 files)
workspace-server/
├── cmd/
│ ├── server/main.go # Entry point + dependency injection
│ └── cli/ # molecli TUI dashboard
├── internal/
│ ├── handlers/ # 26 HTTP handler files (26k+ lines)
│ ├── registry/ # 6 files — workspace registry + access control
│ ├── provisioner/ # 8 files — Docker provisioning + tier enforcement
│ ├── ws/ # 4 files — WebSocket hub + fanout
│ ├── events/ # 3 files — event broadcasting + Postgres persistence
│ ├── router/ # 2 files — route definitions + middleware
│ ├── db/ # 6 files — Postgres + Redis drivers, migrations
│ └── crypto/ # 2 files — AES-256-GCM secrets encryption
└── migrations/ # 11 SQL migration filesCanvas Frontend (62 TypeScript files)
canvas/
├── src/
│ ├── store/ # Zustand store (workspaces, viewport, chat, activity)
│ ├── components/ # React Flow nodes, side panel tabs, context menus, modals
│ ├── hooks/ # Custom hooks (WebSocket, resize, etc.)
│ └── lib/ # API client, utilities
└── tests/ # 188 Vitest tests19. Key Design Patterns
1. Import Cycle Prevention (Go)
Function injection avoids circular imports between packages:
hub := ws.NewHub(registry.CanCommunicate)
broadcaster := events.NewBroadcaster(hub)
registry.StartLivenessMonitor(ctx, onWorkspaceOffline)2. JSONB Handling
Go []byte must convert to string() before JSONB insert with ::jsonb cast. lib/pq treats []byte as bytea, not JSONB.
3. Event Sourcing
structure_events table is append-only — never UPDATE, never DELETE. Provides complete audit trail and event replay capability.
4. Template Resolution
On workspace create: (1) check template folder → (2) try {runtime}-default → (3) generate minimal config via ensureDefaultConfig().
5. Hierarchy-Driven Everything
CanCommunicate() is the single source of truth. All operational concerns (communication, memory, access, approvals, event visibility) derive from the same hierarchy.