Studio Notebook

Claude Code Atlas

Startup And Boot Sequence

Understand how the process starts, loads configuration, and prepares the session.

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.

Global Bootstrap setup() For This Workspace Trust And Setup Screens Live REPL Session

How this part breaks down

  1. init-entrypoint-and-global-bootstrap Start with the global bootstrap that enables configs, safe environment variables, telemetry plumbing, and early async warmups.
  2. setup-function-and-project-root-preparation Follow the setup() function as it sets cwd, handles worktrees, captures hooks, and starts the jobs needed before first render.
  3. trust-dialogs-and-first-render-handoff See 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.