The Startup Pipeline
What happens from typing claude to the first user interaction. The startup sequence is heavily optimized for latency — fast-path routing avoids loading the 785KB main bundle for simple commands, and parallel subprocess spawning overlaps with import loading to shave ~200ms off startup.
Phase 1: Fast-path routing (microseconds)
src/entrypoints/cli.tsx is the true first code to run. Before loading the heavy main bundle, it checks process.argv for commands that can exit immediately:
| Command | What happens | Cost |
|---|---|---|
--version |
Prints MACRO.VERSION (build-time inlined), exits |
Zero module loading |
--dump-system-prompt |
Internal Anthropic path | Minimal loading |
remote-control / rc |
Bridge mode | Separate code path |
daemon |
Daemon supervisor | Separate code path |
ps / logs / attach / kill |
Session management | Separate code path |
Only commands that need the full agent system fall through to main.tsx.
Phase 2: Parallel prefetch (during imports, ~135ms)
While the main bundle's imports are still loading, main.tsx fires parallel subprocesses:
startMdmRawRead()— spawns MDM subprocesses (plutilon macOS,reg queryon Windows) to load managed enterprise settingsstartKeychainPrefetch()— fires macOS keychain reads for OAuth tokens and legacy API keys (~65ms saved by parallelizing)
These run concurrently with the ~135ms of import resolution, so their latency is mostly hidden.
Phase 3: Initialization (init.ts, memoized — runs once)
The init() function configures external integrations in a specific order. The ordering is critical: network must be configured before API calls, config before feature flags, TLS certs before first handshake.
1. enableConfigs() — load and validate settings.json files
2. applySafeConfigEnvironmentVariables() — env vars before trust dialog
3. applyExtraCACertsFromConfig() — TLS certs (Bun caches TLS store at boot)
4. setupGracefulShutdown() — register cleanup handlers
5. [parallel async]:
- initialize1PEventLogging() — fire-and-forget
- populateOAuthAccountInfoIfNeeded() — fire-and-forget
- initJetBrainsDetection() — cache population
- detectCurrentRepository() — git repo detection
6. initializeRemoteManagedSettingsLoadingPromise() — non-blocking
7. initializePolicyLimitsLoadingPromise() — non-blocking
8. preconnectAnthropicApi() — TCP+TLS handshake warmup (~100-200ms saved)
9. configureGlobalMTLS() — mutual TLS
10. configureGlobalAgents() — proxy config
11. setShellIfWindows() — git-bash setup
Telemetry initialization is deferred to a separate function (initializeTelemetryAfterTrust()) that lazy-loads ~400KB of OpenTelemetry + protobuf, with gRPC exporters (~700KB) further deferred. Total: ~1.1MB of code kept out of the startup path.
Phase 4: Commander.js preAction hook
Before any command action, a preAction hook runs:
ensureMdmSettingsLoaded()— await the parallel MDM subprocess from Phase 2ensureKeychainPrefetchCompleted()— await keychain reads from Phase 2init()— the memoized init from Phase 3initSinks()— analytics sink attachmentsetInlinePlugins()— if--plugin-dirprovidedrunMigrations()— 12 migration steps, current version 11loadRemoteManagedSettings()+loadPolicyLimits()— non-blocking fire-and-forget
Phase 5: Config schema loading
Settings are loaded from 5 scopes with defined precedence:
userSettings → projectSettings → localSettings → flagSettings → policySettings
Each scope's settings.json is validated against SettingsSchema (Zod v4). Invalid fields are preserved in file but not applied (graceful degradation). Managed settings follow systemd drop-in convention: base file + managed-settings.d/*.json.
Phase 6: Setup (setup.ts, per-session)
- Set working directory (
setCwd(cwd)) — must happen before hooks - Capture hooks configuration snapshot
- Initialize FileChanged hook watcher
- Worktree creation (if
--worktreeflag) - Background jobs (unless
--bare): - Session memory initialization
- Context collapse (feature-gated)
- Version locking
- Command loading, plugin hooks, attribution hooks
- Team memory watcher, release notes check
- Permission mode validation
- Telemetry event:
tengu_started
Phase 7: Mode divergence
The main action handler determines the operating mode and diverges:
| Mode | Condition | Handler |
|---|---|---|
| Interactive REPL | No -p, TTY available |
launchRepl() — full Ink/React TUI |
| Headless/print | -p flag or no TTY |
runHeadless() — single-shot execution |
| MCP server | mcp serve subcommand |
startMCPServer() — tool exposure via MCP |
| SDK | --sdk-url with stream-json |
Non-interactive, WebSocket control |
The --bare flag
--bare sets CLAUDE_CODE_SIMPLE=1 and skips: hooks, LSP, plugins, attribution, auto-memory, background prefetches, keychain reads, CLAUDE.md auto-discovery. Only 3 tools available (Bash, FileRead, FileEdit). The fastest path to first interaction.
System prompt assembly
Before the first API call, the system prompt is assembled from: - Base prompt (model-specific) - CLAUDE.md files (project instructions, auto-discovered) - Memory files (auto-memory) - Git status snapshot - Tool descriptions (sorted for cache stability) - System reminders - Feature-specific additions (coordinator mode, kairos, etc.)
The DANGEROUS_ prefix convention marks prompt sections that are security-sensitive and should never be cached in a way that could be shared across sessions.
Timeline summary
t=0ms cli.tsx: fast-path check (--version exits here)
t=0ms Start MDM subprocess + keychain prefetch (parallel)
t=0-135ms main.tsx imports loading (parallel with prefetch)
t=135ms init(): config → TLS → graceful shutdown → parallel async
t=135ms preconnectAnthropicApi(): TCP+TLS warmup (parallel)
t=200ms Commander.js: await prefetch results, run migrations
t=250ms Setup: CWD, hooks, background jobs
t=300ms Mode divergence: REPL / headless / MCP / SDK
t=350ms+ System prompt assembly, first API call
Actual time varies by platform and whether enterprise settings (MDM, remote managed) are involved.
Related entities
- entrypoint-system — the four entrypoints
- config-schemas — settings validation
- hooks-system — lifecycle events fired during startup
- service-layer — services initialized in Phase 3
- system-prompt-assembly — prompt construction
- tool-system — tool registration during startup