3. Entry Points and Execution Flow
3.1 The fast-path dispatcher (entrypoints/cli.tsx)
entrypoints/cli.tsx exists to keep the claude --version path at zero extra module loads. The file begins with a minimal inline block (no heavy imports) and only pulls in bigger modules after detecting what mode we're in. Every if that dispatches to a special path uses feature(...) from bun:bundle so the build can delete the whole branch in external builds.
Sequence (entrypoints/cli.tsx):
| Line | Condition | What happens |
|---|---|---|
36-41 |
--version / -v / -V |
Prints MACRO.VERSION (inlined at build) and returns. No profiler, no config. |
47-48 |
Any other path | profileCheckpoint('cli_entry') via a lazy-imported startup profiler. |
53-70 |
--dump-system-prompt (ant-only, feature('DUMP_SYSTEM_PROMPT')) |
Dynamically imports enableConfigs, getMainLoopModel, getSystemPrompt and emits the rendered prompt. Used by prompt-sensitivity evals. |
72-85 |
--claude-in-chrome-mcp / --chrome-native-host |
Route to the Chrome integration MCP server / native host. |
86-93 |
--computer-use-mcp (feature('CHICAGO_MCP')) |
Launches the computer-use MCP server. |
100-106 |
--daemon-worker=<kind> (feature('DAEMON')) |
Spawned per-worker by the supervisor. Deliberately lean — no enableConfigs(), no analytics. |
112-162 |
claude remote-control / remote / sync / bridge (feature('BRIDGE_MODE')) |
Full bridge path: auth check → GrowthBook gate → policy-limits check → bridgeMain(). The comment at 132-135 notes auth must come before the gate check, otherwise GrowthBook has no user context and returns a stale default. |
165-179 |
claude daemon |
Invokes daemonMain with remaining args. |
185-209 |
claude ps|logs|attach|kill or --bg / --background (feature('BG_SESSIONS')) |
Session-registry management under ~/.claude/sessions/. |
212-222 |
`claude new | list |
226-233 |
claude environment-runner (feature('BYOC_ENVIRONMENT_RUNNER')) |
Headless BYOC (Bring Your Own Cloud) runner. |
238-245 |
claude self-hosted-runner (feature('SELF_HOSTED_RUNNER')) |
Register + poll against SelfHostedRunnerWorkerService. |
247-274 |
--worktree --tmux |
Re-exec into tmux inside a fresh worktree before the main CLI loads. |
277-279 |
--update / --upgrade |
Rewrites process.argv to route to the update subcommand. |
283-285 |
--bare |
Sets CLAUDE_CODE_SIMPLE=1 early so feature gates fire at module-eval time. |
287-298 |
Default | startCapturingEarlyInput() (buffer keystrokes before the TUI mounts), then await import('../main.js') and call cliMain(). |
This file is small (~302 lines) and could be studied as a template for any CLI whose startup latency matters.
3.2 entrypoints/init.ts — one-time, trust-aware init
Memoized (init.ts:57):
enableConfigs()— validate + enable config system.- Apply safe env vars before the trust dialog; apply
NODE_EXTRA_CA_CERTSbefore first TLS handshake (Bun caches the cert store at boot). setupGracefulShutdown().- Lazy-init 1P event logging (OpenTelemetry
sdk-logsdeferred to avoid startup bloat). - Populate OAuth account info, detect JetBrains IDE, detect GitHub repo, kick off managed-settings and policy-limits loading.
- Configure global mTLS and HTTP agents; preconnect to Anthropic API (TCP+TLS warm-up overlapping other work).
- If
CLAUDE_CODE_REMOTE=true, start the upstream proxy relay (gated, fail-open). - Register session-team cleanup, scratchpad init, telemetry init after trust.
3.3 main.tsx — the grand orchestrator
A single 4,683-line file. Broadly:
- Runs
init(). - Loads commands, agent definitions, hooks, plugins, merges MCP servers.
- Builds the initial permission context from settings.
- Logs a session-start telemetry beacon (skills, plugins, model).
- Branches to
renderAndRun()(Ink TUI) orrunHeadless()(SDK / print).
Its sheer size is a pragmatic sink for per-entrypoint wiring; it is not where the interesting algorithmic logic lives.
3.4 setup.ts — invoked inside the TUI path
setup.ts:56-477 runs before the first render:
- Node check (
70-79): require 18+. - UDS messaging server (
89-102, gate:UDS_INBOX): unix socket for teammate snapshot injection via$CLAUDE_CODE_MESSAGING_SOCKET. - Teammate mode snapshot capture if swarms enabled.
- Terminal backup restore (
115-158): iTerm2 + Terminal.app. setCwd(cwd)— must precede any code that reads cwd (161).- Hooks config snapshot read from post-setCwd directory.
- Worktree creation (
174-285) if--worktree: resolve canonical git root, switch cwd, save worktree state, re-read settings/hooks from inside the worktree. Supports--tmuxand--worktree-pr-number. - Prefetch and background jobs: session memory init, context collapse, version lock, commands load, plugin hooks, session hooks, team memory watcher.
- Permission bypass safety (
395-442): not root / not in sandbox, validate--dangerously-skip-permissionsguard. - Previous-session metrics logging: cost, duration, lines changed, token usage.
3.5 Bridge / Remote / Daemon
Bridge (bridge/bridgeMain.ts): claude remote-control turns this CLI into a long-lived environment server that:
- Registers with CCR and polls for work assignments.
- Spawns isolated sessions —
single-session,worktree, orsame-dirspawn modes. - Multiplexes work under one authenticated process.
Types live in bridge/types.ts: WorkData, WorkSecret (encrypted bundle containing session_ingress_token, api_base_url, git info, auth tokens, env vars, MCP config), SessionDoneStatus, SpawnMode, BridgeConfig.
Remote sessions (remote/RemoteSessionManager.ts): the other end. When a user opens a session on claude.ai/code/session_…, the browser streams messages over a WebSocket to RemoteSessionManager, which forwards them into a local QueryEngine, and streams SDKMessage / permission requests back out. Callbacks: onMessage, onPermissionRequest, onPermissionCancelled, onConnected, onDisconnected, onReconnecting, onError.
Daemon (daemon/ — referenced from cli.tsx:165-179): long-running supervisor that can host and route multiple worker kinds (--daemon-worker=<kind>).
3.6 Turn lifecycle at the call site
Inside QueryEngine.submitMessage (QueryEngine.ts:209+), each turn:
- Clear turn-scoped
discoveredSkillNames; set cwd; start timer. - Wrap
canUseToolto track denials for SDK reporting (QueryEngine.ts:244-271). - Compute initial main-loop model + thinking config.
fetchSystemPromptParts({ tools, mainLoopModel, additionalWorkingDirectories, mcpClients, customSystemPrompt })→ default prompt, userContext, systemContext.- Prepend a memory-mechanics block when a custom prompt +
CLAUDE_COWORK_MEMORY_PATH_OVERRIDEare both set (QueryEngine.ts:310-318). - Register structured-output enforcement hook if a
jsonSchema+SyntheticOutputToolis present. - Build a
ProcessUserInputContext(messages, setMessages, options, AppState getters, abortController, readFileState, trigger sets). - If an orphaned permission exists (a user approved/denied before the renderer mounted), replay it first (
QueryEngine.ts:398-408). processUserInput({ input, mode:'prompt', context, messages, uuid, isMeta, querySource:'sdk' })→messagesFromUserInput,shouldQuery,allowedTools, optional model override,resultTextfor local commands.- Persist the new user messages into
mutableMessagesand transcript before entering the query loop, so--resumecan recover even if the process is killed mid-API-call. - Yield
buildSystemInitMessage(tools, mcpClients, model, permissionMode, commands, agents, skills, plugins, fastMode) — this is the first SDK event seen by callers. - If
!shouldQuery(a purely local slash command), emit local-command stdout/stderr and aresultmessage, persist, return. - Otherwise enter the
for await (const message of query(...))loop — everything beyond is described in doc 04.
3.7 Plan / Fast / Auto modes
- Plan mode is a permission mode, not an entirely separate flow:
toolPermissionContext.mode = 'plan'disables writes;prePlanModeremembers the mode to restore onExitPlanMode. Entering is viaEnterPlanModeTool; exiting viaExitPlanModeV2Tool. A plan session can also chain to an implementation session viaparentSessionIdinbootstrap/state.ts. - Fast mode is a model-output-speed mode (
utils/fastMode.ts:38+): toggled in the UI or via/fast; validated against subscription tier + GrowthBook gate; latched in bootstrap state so mid-session flips don't bust prompt cache (services/api/claude.ts:1405-1442). - Auto mode is a permission mode —
toolPermissionContext.mode = 'auto'— skip prompts where a Bash classifier allows, prompt otherwise; afterDENIAL_LIMITSconsecutive denials fall back to prompting (utils/permissions/permissions.ts).