Architecture

Soma separates execution, presentation, and the data exchanged between them.

Runtime layers

soma-launcher → soma-cli → soma-core → soma-protocol
LayerResponsibility
LauncherProvide the Rust executable and supply the browser asset directory
CLIHost the local server, serve browser assets, and own terminal output
CoreManage conversations, run model steps, and execute tools
ProtocolDefine serializable snapshots and events

Core performs no terminal output. Browser requests carry explicit thread IDs, so switching the selected conversation never redirects an in-flight request. The packages/cli launcher owns the executable and locates the browser assets through its npm workspace dependency. The crates/cli library owns command routing and the local HTTP server.

Ownership

ThreadManager → Project → SomaThread
                             ├─ Session → Thread → Turns → Steps
                             ├─ StepRunner
                             └─ Inbox and pending input

The manager registers projects and conversation handles. Each SomaThread owns its session and runner behind an execution lock. One turn runs per thread; different threads can run concurrently.

Main and workers are independent roots. Their role-specific system prompts and captured developer context agree: main delegates through create_thread and ends its turn for automatic reports; workers coordinate their child-agent trees. Configured permissions determine available tools.

History and presentation

Core retains execution history and model context. Session::snapshot() projects that state into the browser's Chat and Trajectory views. Provider-private replay data stays in core. Reload recovers the resident conversation; server restart loses it.

Soma follows Codex's manager, thread, session, and tool boundaries. The retained ADRs explain approved differences and inspected upstream revisions.

Implementation: thread_manager.rs.