v0.36.2

Infrastructure

How cast's processes and surfaces fit together: the single-writer daemon, the TUI and web clients, lifecycles, and auth.

For the agent engine itself (how runAgentLoop streams, parallel tools, compaction), see Architecture. For the stable daemon integration contract, see API v1.

Overview

cast has two interactive surfaces and one engine. The engine (runAgentLoop, in src/core/loop.ts) is owned by exactly one process — the cast server daemon — which is the single writer to the SQLite session store. Both surfaces are thin clients of it over HTTP + SSE:

┌─────────────┐   HTTP + SSE    ┌──────────────────────────┐   runAgentLoop   ┌──────────┐
│   TUI       │ ───────────────▶│                          │ ────────────────▶│  LLM /   │
│ (thin       │                 │   cast server daemon        │                  │  tools   │
│  client)    │                 │  ─ owns runAgentLoop     │                  │  (MCP,   │
└─────────────┘                 │  ─ only writer to SQLite │                  │  bash…)  │
┌─────────────┐   HTTP + SSE    │  ─ streams WebEvent via  │                  └──────────┘
│   Web UI    │ ───────────────▶│    SSE to every client   │
│ (browser)   │                 └──────────────────────────┘
└─────────────┘

Before this model (pre-0.12.29) the TUI ran runAgentLoop locally and the web daemon re-implemented it. Two writers racing on the same session store meant a session opened in both surfaces only shared a periodic DB snapshot — no live cross-surface streaming, no shared abort. The single-writer daemon removes that split.

The daemon is the engine

cast server is not a second implementation of the loop — it is the loop. One long-lived daemon process:

TUI as a thin client

The TUI (cast, no subcommand) no longer runs the loop locally. On launch, src/index.ts calls ensureDaemon():

The TUI then:

With CAST_NO_DAEMON=1, the TUI uses its local runAgentLoop fallback. cast run and cast run --interactive instead require the daemon so their sessions share the same store and event stream.

Web UI (browser)

The original client. Connects over HTTP + SSE, logs in with the auto-generated password (cast / printed on first cast web start, saved in settings.json), and renders the same WebEvent stream the TUI does. Because both surfaces read the same SSE stream from the same daemon, opening one session in both shows live tokens, tool calls, and status in both, and an abort from either stops the turn for both.

Lifecycle

For development, npm run dev:web starts the browser surface in the foreground; append server options after --.

Auth

Why single-writer

A single writer removes dual-writer races on the session store and makes one session observable from both surfaces at once. The cost is a daemon process that now also appears when you only wanted the TUI — that is the deliberate trade for live cross-surface streaming.