How Claude Code boots from zero to interactive REPL in milliseconds
import { feature } from 'bun:bundle';// Bugfix for corepack auto-pinning, which adds yarnpkg to peoples' package.jsons
// eslint-disable-next-line custom-rules/no-top-level-side-effects
process.env.COREPACK_ENABLE_AUTO_PIN = '0';
// Set max heap size for child processes in CCR environments (containers have 16GB)
// eslint-disable-next-line custom-rules/no-top-level-side-effects, custom-rules/no-process-env-top-level, custom-rules/safe-env-boolean-check
if (process.env.CLAUDE_CODE_REMOTE === 'true') {// eslint-disable-next-line custom-rules/no-top-level-side-effects, custom-rules/no-process-env-top-level
const existing = process.env.NODE_OPTIONS || '';
// eslint-disable-next-line custom-rules/no-top-level-side-effects, custom-rules/no-process-env-top-level
process.env.NODE_OPTIONS = existing ? `${existing} --max-old-space-size=8192` : '--max-old-space-size=8192';}
// Harness-science L0 ablation baseline. Inlined here (not init.ts) because
// BashTool/AgentTool/PowerShellTool capture DISABLE_BACKGROUND_TASKS into
// module-level consts at import time — init() runs too late. feature() gate
// DCEs this entire block from external builds.
// eslint-disable-next-line custom-rules/no-top-level-side-effects, custom-rules/no-process-env-top-level
if (feature('ABLATION_BASELINE') && process.env.CLAUDE_CODE_ABLATION_BASELINE) { for (const k of ['CLAUDE_CODE_SIMPLE', 'CLAUDE_CODE_DISABLE_THINKING', 'DISABLE_INTERLEAVED_THINKING', 'DISABLE_COMPACT', 'DISABLE_AUTO_COMPACT', 'CLAUDE_CODE_DISABLE_AUTO_MEMORY', 'CLAUDE_CODE_DISABLE_BACKGROUND_TASKS']) {// eslint-disable-next-line custom-rules/no-top-level-side-effects, custom-rules/no-process-env-top-level
process.env[k] ??= '1';
}
}
/**
* Bootstrap entrypoint - checks for special flags before loading the full CLI.
* All imports are dynamic to minimize module evaluation for fast paths.
* Fast-path for --version has zero imports beyond this file.
*/
async function main(): Promise<void> {const args = process.argv.slice(2);
// Fast-path for --version/-v: zero module loading needed
if (args.length === 1 && (args[0] === '--version' || args[0] === '-v' || args[0] === '-V')) {// MACRO.VERSION is inlined at build time
// biome-ignore lint/suspicious/noConsole:: intentional console output
console.log(`${MACRO.VERSION} (Claude Code)`);return;
}
// For all other paths, load the startup profiler
const {profileCheckpoint
} = await import('../utils/startupProfiler.js'); profileCheckpoint('cli_entry');// Fast-path for --dump-system-prompt: output the rendered system prompt and exit.
// Used by prompt sensitivity evals to extract the system prompt at a specific commit.
// Ant-only: eliminated from external builds via feature flag.
if (feature('DUMP_SYSTEM_PROMPT') && args[0] === '--dump-system-prompt') { profileCheckpoint('cli_dump_system_prompt_path'); const {enableConfigs
} = await import('../utils/config.js');enableConfigs();
const {getMainLoopModel
} = await import('../utils/model/model.js'); const modelIdx = args.indexOf('--model');const model = modelIdx !== -1 && args[modelIdx + 1] || getMainLoopModel();
const {getSystemPrompt
} = await import('../constants/prompts.js');const prompt = await getSystemPrompt([], model);
// biome-ignore lint/suspicious/noConsole:: intentional console output
console.log(prompt.join('\n'));return;
Every time you run claude, execution begins here at src/entrypoints/cli.tsx. The first goal is brutal simplicity: handle common flags without loading any modules.
The `--version` flag path loads zero modules. `MACRO.VERSION` is a build-time constant inlined by the bundler, making version checks essentially instant.
For everything else, the startup profiler is loaded first. This records exact timestamps at each profileCheckpoint() call, allowing the team to track startup regression down to the millisecond.
Notice every import after line 44 is a dynamic `await import()` — this is intentional. Dynamic imports are only evaluated when that code path runs, so unused flags cost zero startup time.
The top-level heap size setting (lines 9–14) is a deliberate side effect. In container environments (CLAUDE_CODE_REMOTE=true), Node.js needs --max-old-space-size=8192 set *before* any memory-intensive modules load.
Ask anything about Entry Points & CLI Bootstrap
Powered by Groq · Enter to send, Shift+Enter for newline