Skip to content

Architecture

McNabsys edited this page Mar 16, 2026 · 2 revisions

Architecture

Elisa is a kid-friendly IDE that orchestrates AI agent teams to build real software and hardware. Kids compose specs using visual blocks (Blockly); the backend decomposes specs into task DAGs, executes them via the Claude Agent SDK, and streams results back in real-time.

System Topology

Electron main process (electron/main.ts)
  |→ Loads API key from encrypted store (OS keychain via safeStorage)
  |→ Picks a free port
  |→ Starts Express server in-process
  |→ Opens BrowserWindow → http://localhost:{port}

frontend/ (React 19 + Vite)         backend/ (Express 5 + TypeScript)
+-----------------------+           +---------------------------+
| Blockly Editor        |  REST     | Express Server            |
| (BlockCanvas)         |---------->| POST /api/sessions/:id/*  |
|                       |           |                           |
| MissionControl        |  WS      | Orchestrator              |
| (TaskDAG, CommsFeed,  |<---------| → MetaPlanner (Claude)    |
|  Metrics, Deploy)     |  events  | → AgentRunner (SDK)       |
|                       |           | → TestRunner (pytest)     |
| BottomBar             |           | → GitService (simple-git) |
| (Trace, Board, Learn, |           | → HardwareService         |
|  Progress, Health)    |           | → TeachingEngine          |
+-----------------------+           +---------------------------+
                                             |
                                   runs agents via SDK query() API
                                   per task (async streaming)

In production, Express serves everything: /api/* (REST), /ws/* (WebSocket), and /* (built frontend static files). CORS is unnecessary (same-origin). In dev mode, the frontend runs on Vite (port 5173) with proxy to backend (port 8000), and CORS is enabled.

Monorepo Layout

elisa/
  package.json       Root package: Electron deps, build/dev/dist scripts
  electron/          Electron main process, preload, settings dialog
  frontend/          React SPA — visual block editor + real-time dashboard
  backend/           Express server — orchestration, agents, hardware
  scripts/           Build tooling (esbuild backend bundler)
  devices/           ESP32 templates and shared MicroPython library
  docs/              Documentation (manual, API reference, PRD)

Root package.json manages Electron and build tooling. Frontend and backend remain independent Node.js projects with their own package.json.

Data Flow: Build Session Lifecycle

1. User arranges blocks in Blockly editor
2. Click GO → blockInterpreter converts workspace to NuggetSpec JSON
3. POST /api/sessions (create) → POST /api/sessions/:id/start (with spec)
4. Backend Orchestrator.run():
   a. PLAN:    MetaPlanner calls Claude API to decompose spec into task DAG
   b. EXECUTE: Streaming-parallel pool (Promise.race, up to 3 concurrent tasks)
               Each agent gets: role prompt + task description + context from prior tasks
               Agent output streams via SDK → WebSocket events to frontend
               Git commit after each completed task (serialized via mutex)
               Token budget tracked per agent; warning at 80%, halt on exceed
   c. TEST:    TestRunner executes pytest, parses results + coverage
   d. REVIEW:  Optional reviewer agent pass
   e. DEPLOY:  Surface before_deploy rules as deploy_checklist event
               If web: build → find serve dir → start local HTTP server → open browser
               If ESP32: compile → flash → serial monitor
               If CLI portals: execute via CliPortalAdapter (no shell)
5. session_complete event with summary

Human gates can pause execution at any point, requiring user approval via REST endpoint.

Communication Protocol

Channel Direction Purpose
REST client → server Commands: create session, start build, gate responses, question answers
WebSocket server → client Events: task progress, agent output, test results, teaching moments, errors

WebSocket path: /ws/session/:sessionId

Core Abstractions

NuggetSpec

JSON schema produced by blockInterpreter from the Blockly workspace. Drives the entire pipeline. Contains: goal, requirements, style, agents, hardware config, deployment target, workflow flags, skills, rules. Validated server-side via Zod schema.

Task DAG

Directed acyclic graph of tasks with dependencies. Generated by MetaPlanner. Executed in topological order by Orchestrator. Uses Kahn's algorithm (backend/src/utils/dag.ts).

Build Session

In-memory state for one execution run. Tracks: session ID, phase, tasks, agents, commits, events, teaching moments, test results, token usage. No database — everything lives in memory with optional JSON persistence for crash recovery.

Agent Roles

  • Builder — Writes source code
  • Tester — Writes and runs tests
  • Reviewer — Reviews code quality
  • Custom — User-defined persona

Each agent runs via the Claude Agent SDK's query() API with role-specific system prompts injected from backend/src/prompts/.

State Machine

idle → planning → executing → testing → reviewing → deploying → done
                     ^                                             |
                 human gates (pause/resume via REST)         keep working
                                                                   |
                                                                   v
                                                                design

Key Patterns

  • Event-driven UI: All frontend state updates flow through WebSocket event handlers. No polling.
  • Agent isolation: Each agent task runs as a separate SDK query() call. No shared state between agents except via context summaries.
  • Context chain: After each task, a summary is written to .elisa/context/nugget_context.md. Subsequent agents receive this as input.
  • Graceful degradation: Missing tools (git, pytest, mpremote, serialport) cause warnings, not crashes.
  • Bearer token auth: Server generates a random auth token on startup. All /api/* routes (except /api/health) require Authorization: Bearer <token>. WebSocket upgrades require ?token=<token>.
  • Content safety: All agent prompts include a Content Safety section enforcing age-appropriate output (ages 8–14). User-controlled placeholder values are sanitized before prompt interpolation.
  • Abort propagation: Orchestrator's AbortController signal is forwarded to each agent's SDK query() call.
  • API key management: In dev, read from ANTHROPIC_API_KEY env var. In Electron, encrypted via OS keychain (safeStorage). Child processes receive sanitized env without the API key.

Storage

  • Session state: In-memory Map<sessionId, Session> with optional JSON persistence for crash recovery
  • Workspace: Temp directory per session or user-chosen directory. Contains generated code, tests, git repo, .elisa/ metadata.
  • localStorage: Workspace JSON, skills, and rules auto-saved in browser. Restored on page load.
  • Nugget files: .elisa zip format for export/import (workspace + skills + rules + generated code)
  • No database

Electron Packaging

  1. npm run build:frontend — Vite builds React SPA into frontend/dist/
  2. npm run build:backend — esbuild bundles Express server into backend/dist/server-entry.js
  3. npm run build:electron — tsc compiles electron/main.ts and preload.ts
  4. npm run dist — electron-builder packages into installer (NSIS on Windows, DMG on macOS)

Module-Level Documentation

Deeper context for each subsystem lives in CLAUDE.md files within each directory:

  • frontend/CLAUDE.md — Frontend architecture, component tree, state management
  • backend/CLAUDE.md — Backend architecture, services, API surface
  • backend/src/services/CLAUDE.md — Service responsibilities and interactions
  • frontend/src/components/CLAUDE.md — Component hierarchy and patterns

Clone this wiki locally