ADR-0007: Frontend and local-server stack¶
- Status: Accepted
- Date: 2026-09-03
- Deciders: Jian (product owner)
- Amended by: ADR-0028 (a durable state store for runtime state; the spec and layout stay files)
Context¶
ADR-0005 already decided the canvas ships as a local web app served by the CLI, but left the
actual UI framework, canvas/graph rendering library, local server framework, and YAML parsing
library undecided. These are real, load-bearing choices — they determine package.json
dependencies and package boundaries, and are expensive to reverse once the canvas (SLICES.md
V1) is underway.
The canvas is fundamentally a node-graph editor (blocks, connections, a property inspector), not a generic web app. That framing narrows the real decision considerably: the question isn't "React vs. Svelte" in the abstract, it's "which ecosystem has a mature, production-grade node-graph library."
Decision¶
- UI framework: React + Vite, for
apps/canvas. - Canvas rendering:
@xyflow/react(formerly React Flow), MIT-licensed, free for commercial use. It ships MiniMap/Controls/Background out of the box and is the same library Langflow (a direct competitor solving the same "visual agent workflow" problem) is built on — a well-trodden, de-risked choice rather than a novel bet. - Local server (what
kampong devstarts): Fastify. Serves the built canvas static assets, a REST API for spec CRUD, and a Server-Sent-Events endpoint streaming the step-by-step run trace (PLAN.md Shape S3's test-run panel). Approve/reject actions are a plain POST — SSE covers the overwhelmingly server→client data flow without the complexity of a full-duplex socket. - YAML parsing: the
yamlpackage (eemeli/yaml), notjs-yaml. ItsDocument/CST API preserves comments and formatting across a parse→mutate→stringify round trip. - Database: none in v1 (files only, per Q17 — restated here since it belongs with the rest of the stack answer). For the hosted roadmap slice (V5), Postgres is the working default assumption, not a decision made now.
Alternatives considered¶
| Option | Why not |
|---|---|
| Svelte + SvelteFlow | No comparably mature node-graph library in the Svelte ecosystem for this specific use case; would mean building graph-editing primitives from scratch instead of the editor itself. |
| WebSocket instead of SSE | Full duplex isn't needed yet — the run-progress stream is one-directional and the one action (approve/reject) is a simple POST. Revisit if hosted mode (V5) needs multi-user presence/awareness, which does need bidirectional messaging. |
js-yaml for parsing |
Strips comments and reformats on stringify, which would silently violate R1's "zero data loss" the first time the canvas saves a hand-annotated spec. |
Consequences¶
apps/canvasdepends onreact,react-dom,@xyflow/react,vite;packages/clidepends onfastify;packages/specdepends onyaml.- Real-time multi-user collaboration (explicitly deferred, Q24) would likely require revisiting SSE for WebSocket once it's actually in scope — flagged here so it isn't a surprise later, not a problem to solve now.
- Postgres-for-hosted-mode is a placeholder assumption, not an ADR-grade decision — it should be revisited with its own ADR when V5 is actually being built, once real workspace/multi-tenant data shape is known.