One turn in the system
The main path is a streaming loop. Terminal input becomes a normalized message, the REPL builds context and tool availability, the model streams assistant blocks, and any tool_use block becomes a local or MCP tool call. Tool results are appended as user messages and the loop repeats until the assistant stops or a recovery path takes over.
Bootstrap is a selective importer
The CLI entrypoint starts by handling paths that do not need the full application: --version, system prompt dump, MCP native hosts, daemon modes, background sessions, worktree helpers, and bare mode. Only after those checks does it import ../main.js and call cliMain().
node starts cli.tsx
if cheap flag or special mode: execute fast path and exit
else:
start early input capture
import ../main.js
await cliMain(process.argv)
Main builds the session contract
src/main.tsx defines the Commander program and uses a preAction phase for cross-cutting setup: MDM settings, keychain migration, init, title, telemetry sinks, plugin directories, user migrations, policy, settings sync, and remote config.
The default command then collects options such as prompt, print mode, model, permission mode, MCP config, allowed tools, denied tools, plugin directories, and input/output formats.
The interactive app is loaded late
The REPL is not imported by the entrypoint. replLauncher.tsx dynamically imports App and REPL, then renderAndRun creates the Ink root, starts deferred prefetch work, and waits until the terminal UI exits.
Input is queued before it is queried
PromptInput performs local UI checks, accepts suggestions, routes direct member messages, and then calls the submitted handler. handlePromptSubmit turns the input into a queued command, enforces active-query rules, handles immediate local JSX commands, reserves the query guard, and runs processUserInput.
Input processing decides if the model is needed
processUserInput normalizes strings and content blocks, loads attachments, handles bash shortcuts and slash commands, and returns a result that includes shouldQuery. Text prompts produce a user message and set shouldQuery: true; some slash commands are local and do not call the model.
The query loop is the runtime coordinator
query() delegates to queryLoop(). Each iteration prepares system and user context, calls the streaming model adapter, yields assistant chunks, hands completed tool_use blocks to a streaming executor, appends tool results, refreshes available tools, and loops with the new state.
Tools are normal objects plus permission policy
A tool has a name, schema, prompt-facing description, concurrency metadata, permission behavior, and a call method. MCP tools are adapted into the same shape, so the query loop can execute built-in and server-provided tools through the same orchestration path.
App state is an external store
The UI uses a small external store with getState, setState, and subscribe. React components read it through useSyncExternalStore. REPL code deliberately grabs current store values when constructing tool context, so MCP clients, permission state, and resources stay fresh during a long session.
Main data objects
| Object | Role | Where it appears |
|---|---|---|
AppState |
Terminal UI and runtime state: permissions, MCP state, notifications, prompt suggestions, plugin state, bridge state, and thinking state. | AppStateStore.ts |
QueuedCommand |
A normalized unit of user input waiting for processing or model execution. | handlePromptSubmit.ts |
ProcessUserInputResult |
The decision from input processing: local command only, model query needed, attachments, allowed tools, and command permissions. | processUserInput.ts |
ToolUseContext |
Runtime services passed into tools: abort controller, permission callbacks, state accessors, MCP clients, resources, UI hooks, and file read state. | Tool.ts |
Tool |
The common interface for built-in tools and MCP tools. | Tool.ts |
QueryParams |
The query-loop contract: messages, prompt, tools, MCP data, callbacks, model, abort signal, and runtime options. | query.ts |
Component pages
- CLI Startup: entrypoint, Commander setup, app launch.
- REPL Input: prompt submission, queues, slash commands, attachments.
- Query Loop: streaming turn loop and recovery paths.
- Model API: Anthropic request creation and stream event parsing.
- Tools and Permissions: local tools, hooks, approval flow, execution.
- MCP: server connections and MCP tool adaptation.
- State and Rendering: Ink, AppState, and UI updates.