State management
State is managed through a custom store + React context pattern. TheAppState object is the single source of truth for all mutable session state.
AppStateStore
src/state/AppStateStore.ts defines the shape of AppState — a large plain object covering:
- Conversation messages and history
- Active tool permission context (
ToolPermissionContext) - MCP server connections and resources
- Session metadata (model, effort, theme, cost tracking)
- Background task states
- Plugin and skill state
- Attribution, file history, and speculation state
setAppState in sub-agents is a no-op for session-scoped infrastructure. Use setAppStateForTasks (when available) to reach the root store from a nested agent context.Store
src/state/store.ts exports the Store<T> type — a lightweight observable wrapper around AppState:
Context providers
src/context/ contains React context providers that expose slices of state or derived values to the component tree:
| Provider | File | Purpose |
|---|---|---|
| Notifications | notifications.tsx | Rate limits, deprecation warnings, permission alerts |
| Stats | stats.tsx | Session statistics (token counts, turn counts) |
| FPS metrics | fpsMetrics.tsx | Terminal render frame rate tracking |
| Modal | modalContext.tsx | Full-screen modal overlay management |
| Overlay | overlayContext.tsx | Layered overlay state |
| Queued messages | QueuedMessageContext.tsx | Buffered messages awaiting render |
| Voice | voice.tsx | Voice input/output state (feature-gated) |
Selectors and change observers
src/state/selectors.ts— pure functions that derive computed values fromAppStatesrc/state/onChangeAppState.ts— registers side-effects that fire when specific state keys change (e.g., persisting settings to disk when they are updated)
UI components (~140)
Components live insrc/components/ and are built from:
- Ink primitives —
Box(flexbox layout),Text(styled text),useInput()(keyboard events) - Chalk — terminal color and style strings
- React Compiler — enabled for optimized re-renders, reducing unnecessary updates in the message stream
- Design system primitives — shared atoms in
src/components/design-system/
Notable component groups
Message rendering
Message rendering
Components for rendering the conversation stream — assistant text, tool-use blocks, tool results, progress indicators, and code blocks with syntax highlighting.
Input
Input
The REPL input line with typeahead, vim mode, paste handling, and slash command autocomplete. Backed by hooks in
src/hooks/ (useTextInput, useVimInput, usePasteHandler, useInputBuffer).Permission dialogs
Permission dialogs
Inline permission prompts that pause tool execution and ask the user to approve, deny, or set a persistent rule. These integrate with
src/hooks/toolPermission/.Design system
Design system
src/components/design-system/ — primitive layout and typography components used across the rest of the UI to enforce visual consistency.Screens
Full-screen UI modes live insrc/screens/:
| Screen | File | Purpose |
|---|---|---|
| REPL | REPL.tsx | Main interactive REPL — the default screen |
| Doctor | Doctor.tsx | Environment diagnostics launched by /doctor |
| Resume conversation | ResumeConversation.tsx | Session restore picker launched by /resume |
REPL.tsx is the root of the interactive session — it renders the message stream, input line, status bar, and any active overlays.
Hooks (~80)
src/hooks/ contains React hooks following standard patterns. Categories:
Permission hooks
Permission hooks
useCanUseTool— evaluates whether a tool call should be allowed given the current permission mode and rulessrc/hooks/toolPermission/— the full permission evaluation pipeline, including ML classifier integration, wildcard rule matching, and user prompt rendering
IDE integration hooks
IDE integration hooks
useIDEIntegration— detects and manages the active IDE bridge connectionuseIdeConnectionStatus— reactive connection status for the IDE extensionuseDiffInIDE— opens file diffs in the connected IDE
Input handling hooks
Input handling hooks
useTextInput— controlled text input with cursor managementuseVimInput— vim-mode input state machineusePasteHandler— multi-line paste detection and handlinguseInputBuffer— raw keyboard buffer management
Session management hooks
Session management hooks
useSessionBackgrounding— handles the session going to the background (e.g.,Ctrl+Z)useRemoteSession— manages remote session state for the bridge/teleport featuresuseAssistantHistory— up-arrow history for the input line
Plugin and skill hooks
Plugin and skill hooks
useManagePlugins— plugin installation, removal, and reloaduseSkillsChange— reacts to skill directory changes and reloads the command list
Notification hooks
Notification hooks
src/hooks/notifs/ — reactive hooks for displaying rate limit warnings, deprecation notices, and other transient notifications in the status bar.Configuration schemas
Zod schemas (src/schemas/)
All configuration is validated with Zod schemas (using the zod/v4 API):
| Schema | Purpose |
|---|---|
| User settings | Per-user preferences (model, theme, keybindings, etc.) |
| Project settings | Per-project configuration (CLAUDE.md, allowed tools, etc.) |
| Organization policies | Enterprise MDM policy enforcement |
| Permission rules | alwaysAllow, alwaysDeny, alwaysAsk rule sets |
Migrations (src/migrations/)
When the config schema changes between versions, migration functions in src/migrations/ read the old format and transform it to the current schema. This runs automatically at startup when an outdated config file is detected.
See also
- Architecture overview — How the UI and state layers fit into the full pipeline
- Query Engine — How
getAppState/setAppStateare threaded through tool execution - Tool System — How tools access and mutate
AppStateviaToolUseContext