Why this matters
Claude Code starts in three stages. First, init() performs the global
bootstrap that loads config, safe environment variables, and network plumbing.
Then setup() makes the session specific to the current cwd and worktree.
Finally, the trust and setup screens finish their work before the long-lived
REPL is fully live.
Startup in three stages
Global bootstrap runs first, setup makes the current workspace concrete, and trust/setup screens hand off into the live REPL.
How this part breaks down
init-entrypoint-and-global-bootstrapStart with the global bootstrap that enables configs, safe environment variables, telemetry plumbing, and early async warmups.setup-function-and-project-root-preparationFollow thesetup()function as it sets cwd, handles worktrees, captures hooks, and starts the jobs needed before first render.trust-dialogs-and-first-render-handoffSee how interactive startup passes through onboarding, trust, environment application, and the handoff into the first rendered REPL session.
From init() To First Render
init() is global bootstrap, not repo-specific boot. It runs once to prepare
shared process state before the current workspace is even in view.
export const init = memoize(async (): Promise<void> => {
profileCheckpoint('init_function_start')
enableConfigs()
profileCheckpoint('init_configs_enabled')
await initMainBranchCache()
applySafeConfigEnvironmentVariables()
applyExtraCACertsFromConfig()
setupGracefulShutdown()
// This needs to happen after Configs are enabled and loaded.
initK8sConfig()
profileCheckpoint('init_k8s_config_loaded')
await import('../services/bugsnag.ts')
initBacktrace()
profileCheckpoint('init_bug_reporting_ready')
configureGlobalMTLS()
configureGlobalAgents()
profileCheckpoint('init_network_configured')
preconnectAnthropicApi()
})
setup() is where the process becomes concrete for the current cwd and
worktree. It captures hooks before local state can change, resolves the project
root, and primes the per-session collections the REPL will need.
export async function setup(
cwd: string,
permissionMode: PermissionModeArg,
allowDangerouslySkipPermissions: boolean,
worktreeEnabled: boolean,
worktreeName?: string,
sessionId?: string,
worktreePRNumber?: number,
messagingSocketPath?: string,
) {
setCwd(cwd)
// Capture hooks before a .claude directory could appear later in setup.
captureHooksConfigSnapshot()
initializeFileChangedWatcher(cwd)
const isOutsideRoot = getCwd().startsWith('/tmp/') || getCwd().startsWith('/var/')
if (isGit() && !isOutsideRoot) {
const rootDir = await getGitRootIfInRepository()
if (rootDir) {
setProjectRoot(rootDir)
}
}
setProjectRoot(getCwd())
initSessionMemory()
void getTools()
void getCommands(getProjectRoot())
void getSlashCommands()
void getAgents(getProjectRoot())
initSinks()
logEvent('tengu_started', {})
}
The trust and setup screens happen before the long-lived REPL is fully live.
main.tsx measures that handoff explicitly, then awaits the setup screen flow
before continuing into the interactive session.
logForDebugging('[STARTUP] Running showSetupScreens()...');
const setupScreensStart = Date.now();
const onboardingShown = await showSetupScreens(root, permissionMode, allowDangerouslySkipPermissions, commands, enableClaudeInChrome, devChannels);
logForDebugging(`[STARTUP] showSetupScreens() completed in ${Date.now() - setupScreensStart}ms`);
export async function showSetupScreens(
root: Root,
permissionMode: PermissionModeArg,
allowDangerouslySkipPermissions: boolean,
commands: Command[],
enableClaudeInChrome: boolean,
devChannels: DevChannels,
) {
if (!hasCompletedOnboarding()) {
await maybeShowOnboarding(root)
}
if (!checkHasTrustDialogAccepted()) {
await showTrustDialog(
root,
permissionMode,
allowDangerouslySkipPermissions,
commands,
enableClaudeInChrome,
)
setSessionTrustAccepted(true)
}
void getSystemContext()
applyConfigEnvironmentVariables()
}
That sequence explains the startup boundary: init() prepares the process,
setup() binds it to the current workspace, and the setup screens resolve the
last interactive gates before the REPL becomes the durable session surface.