File: /sessions/cool-friendly-einstein/mnt/claude-code/src/main.tsx
Size: 4,683 lines
Analysis Date: 2026-04-02
Focus: Complete bootstrap sequence, security, state initialization, conditional paths
CRITICAL: Three side-effect imports fire BEFORE all other code:
1. profileCheckpoint('main_tsx_entry') [Line 12]
2. startMdmRawRead() [Line 16]
→ Spawns MDM reader subprocesses (plutil/reg query)
→ Runs in PARALLEL with remaining imports (~135ms)
3. startKeychainPrefetch() [Line 20]
→ Fires macOS keychain reads (OAuth + legacy API key) IN PARALLEL
→ Prevents sequential sync reads in isRemoteManagedSettingsEligible() (~65ms each)
Rationale: These run before heavy module evaluation so their subprocesses execute in parallel with imports, reducing critical path latency.
Then: ~135ms of TypeScript imports loaded (148+ imports)
Checkpoint: main_tsx_imports_loaded [Line 209]
Debug Mode Detection (isBeingDebugged)
- Checks
process.execArgvfor--inspect,--inspect-brk,--debug,--debug-brk - Checks
NODE_OPTIONSenvironment variable for same flags - Calls
inspector.url()to detect active debugging session - If detected AND build is NOT 'ant':
process.exit(1)with NO gracefulShutdown - Bun-specific handling: skips legacy
--debugcheck (Bun doesn't support it)
Security: Prevents Node debugger from executing in non-'ant' builds
Feature-gated: feature('LODESTONE')
Two paths:
-
--handle-uri <uri>flag (command line)- Calls
enableConfigs()(file I/O bypass trigger) - Calls
handleDeepLinkUri(uri) - Exits immediately with returned exit code
- Calls
-
macOS URL scheme launch
- Detects
process.env.__CFBundleIdentifier === 'com.anthropic.claude-code-url-handler' - Calls
enableConfigs()+handleUrlSchemeLaunch() - Exits immediately with returned exit code
- Detects
Note: Both return before main() returns (async context, so not blocking execution)
Feature-gated: feature('DIRECT_CONNECT')
Pattern: cc:// or cc+unix:// URLs in argv
Behavior:
- Extracts URL via
parseConnectUrl(ccUrl) - Sets
_pendingConnect.urland_pendingConnect.authToken - Sets
_pendingConnect.dangerouslySkipPermissionsif flag present - Rewrites
process.argv:- Headless (
-p): becomes['node', 'script', 'open', ccUrl, ...flags] - Interactive: strips
cc://URL entirely, runs normal command
- Headless (
- Extracted flags removed from argv
Feature-gated: feature('KAIROS')
Pattern: claude assistant [sessionId] OR claude assistant (discover mode)
Behavior:
- Must be position-0 arg (not
--root-flag assistantfallthrough) - If
sessionIdprovided: sets_pendingAssistantChat.sessionId, strips from argv - If no args: sets
_pendingAssistantChat.discover = true, strips argv[0] - If
--flagfollows: doesn't rewrite (falls through to stub help)
Feature-gated: feature('SSH_REMOTE')
Pattern: claude ssh [flags] <host> [cwd] [flags]
Flag Extraction (before host check):
--local: sets_pendingSSH.local, splices out--dangerously-skip-permissions: sets_pendingSSH.dangerouslySkipPermissions--permission-mode <value>or--permission-mode=value: extracted-c/--continue,--resume,--model: extracted & stored in_pendingSSH.extraCliArgs
Host Validation:
- After flag stripping, argv[1] must be non-dash (host)
- argv[2] (if non-dash) is cwd
- Remaining args replace entire argv
Error Case:
-p/--printwith SSH:gracefulShutdownSync(1)+ return (no process.exit)
hasPrintFlag = includes('-p') || includes('--print')
hasInitOnlyFlag = includes('--init-only')
hasSdkUrl = some arg.startsWith('--sdk-url')
isNonInteractive = hasPrintFlag || hasInitOnlyFlag || hasSdkUrl || !process.stdout.isTTYSide Effect: stopCapturingEarlyInput() if non-interactive
State: setIsInteractive(!isNonInteractive)
CLAUDE_CODE_ENTRYPOINT detection order:
1. If env var already set → return (skip, allow SDK to override)
2. If "mcp serve" in argv → 'mcp'
3. If CLAUDE_CODE_ACTION env var → 'claude-code-github-action'
4. Based on isNonInteractive → 'sdk-cli' or 'cli'
CLIENT_TYPE detection order:
1. GITHUB_ACTIONS env var → 'github-action'
2. CLAUDE_CODE_ENTRYPOINT === 'sdk-ts' → 'sdk-typescript'
3. CLAUDE_CODE_ENTRYPOINT === 'sdk-py' → 'sdk-python'
4. ... etc for all SDK + desktop variants
5. Has session ingress token → 'remote'
6. CLAUDE_CODE_ENTRYPOINT === 'remote' → 'remote'
7. Default → 'cli'
QUESTION_PREVIEW_FORMAT:
- From env CLAUDE_CODE_QUESTION_PREVIEW_FORMAT if 'markdown' or 'html'
- Else auto-set to 'markdown' for CLI (not desktop/local-agent/remote)
SESSION_SOURCE:
- Set to 'remote-control' if CLAUDE_CODE_ENVIRONMENT_KIND === 'bridge'State Mutations:
setClientType(clientType)setQuestionPreviewFormat(previewFormat)setSessionSource('remote-control')
Function: eagerLoadSettings()
--settings flag → loadSettingsFromFlag() → setFlagSettingsPath() + resetSettingsCache()
--setting-sources flag → loadSettingSourcesFromFlag() → setAllowedSettingSources() + resetSettingsCache()Error Handling: Validates settings JSON early, process.exit(1) on error
Checkpoint: main_before_run [Line 853]
await run() // Commander.js setup + preAction hookCheckpoint: main_after_run [Line 855]
| Env Var | Line | Effect | Security Implication |
|---|---|---|---|
NoDefaultCurrentDirectoryInExePath |
591 | Set to '1' unconditionally | Windows PATH hijacking prevention (must precede all commands) |
NODE_OPTIONS |
250 | Checked for --inspect flags |
Debug mode detection |
NODE_EXTRA_CA_CERTS |
293 | Telemetry if present | Certificate pinning telemetry |
CLAUDE_CODE_CLIENT_CERT |
296 | Telemetry if present | Client cert telemetry |
| Env Var | Line | Effect |
|---|---|---|
CLAUDE_CODE_ENTRYPOINT |
519 | Early return if pre-set by SDK/launcher |
CLAUDE_CODE_ACTION |
530 | GitHub Actions detection |
GITHUB_ACTIONS |
819 | Client type = 'github-action' |
CLAUDE_CODE_SESSION_ACCESS_TOKEN |
828 | Remote session detection |
CLAUDE_CODE_WEBSOCKET_AUTH_FILE_DESCRIPTOR |
828 | Remote session detection |
CLAUDE_CODE_ENVIRONMENT_KIND |
846 | If 'bridge' → setSessionSource('remote-control') |
| Env Var | Line | Effect |
|---|---|---|
CLAUDE_CODE_ENTRYPOINT |
539 | Set to 'sdk-cli' or 'cli' |
CLAUDE_CODE_QUESTION_PREVIEW_FORMAT |
835 | Override preview format (markdown/html) |
CLAUDE_CODE_SIMPLE |
1015 | Set to '1' if --bare flag (triggers all gates) |
CLAUDE_CODE_AGENT |
1117 | Set if --agent <name> provided (BG_SESSIONS gated) |
CLAUDE_CODE_TASK_LIST_ID |
1142 | Set if --tasks <id> provided (ant-only) |
CLAUDE_CODE_INCLUDE_PARTIAL_MESSAGES |
1226 | Enable SDK partial message output |
CLAUDE_CODE_REMOTE |
1231 | Enable all hook events |
CLAUDE_CODE_REMOTE_SESSION_ID |
1317 | Used for file downloads |
ANTHROPIC_BASE_URL |
1323 | File API base URL |
| Env Var | Line | Effect |
|---|---|---|
CLAUDE_CODE_EXIT_AFTER_FIRST_RENDER |
393 | Skip deferred prefetches |
CLAUDE_CODE_USE_BEDROCK |
408 | Enable Bedrock prefetch |
CLAUDE_CODE_SKIP_BEDROCK_AUTH |
408 | Disable Bedrock auth prefetch |
CLAUDE_CODE_USE_VERTEX |
411 | Enable Vertex (GCP) prefetch |
CLAUDE_CODE_SKIP_VERTEX_AUTH |
411 | Disable Vertex auth prefetch |
CLAUDE_CODE_DISABLE_TERMINAL_TITLE |
922 | Skip process.title = 'claude' |
CLAUDE_CODE_PROACTIVE |
2199 | Enable proactive mode (append system prompt) |
MAX_THINKING_TOKENS |
2473 | Override max thinking tokens |
CLAUDE_CODE_COORDINATOR_MODE |
1872 | Enable coordinator mode (gated) |
ANTHROPIC_MODEL |
2012 | Explicit model override (triggers GrowthBook init if ant) |
| Env Var | Line | Effect |
|---|---|---|
__CFBundleIdentifier |
666 | If 'com.anthropic.claude-code-url-handler' → handle deep link |
COORDINATOR_MODE [Line 76]
→ require('./coordinator/coordinatorMode.js') if enabled, else null
→ Dead code if feature('COORDINATOR_MODE') === false
KAIROS [Lines 80-81]
→ require('./assistant/index.js') + gate if enabled
→ All assistant/teammate code gated
SSH_REMOTE [Line 577]
→ _pendingSSH object + SSH parsing logic
→ Unreachable if feature('SSH_REMOTE') === false
DIRECT_CONNECT [Line 548]
→ _pendingConnect parsing logic
→ Unreachable if feature('DIRECT_CONNECT') === false
TRANSCRIPT_CLASSIFIER [Line 171]
→ autoModeStateModule conditional import
→ Unreachable if disabled
CHICAGO_MCP [Line 1477]
→ Computer Use MCP server checks
→ Unreachable if disabled| Feature | Lines | Behavior |
|---|---|---|
| KAIROS | 1050-1089 | Assistant mode activation (checks settings, gates, forces brief mode) |
| KAIROS | 2206-2209 | Assistant system prompt addendum |
| KAIROS | 3259+ | Assistant session discovery & viewer mode |
| TRANSCRIPT_CLASSIFIER | 337-341, 1399-1410 | Auto mode opt-in, migration |
| TRANSCRIPT_CLASSIFIER | 2663, 4285 | Telemetry |
| TRANSCRIPT_CLASSIFIER | 1769 | Permission UI for dangerous tools |
| COORDINATOR_MODE | 1872, 2197-2199 | Blocks proactive mode |
| COORDINATOR_MODE | 3770, 4593 | Coordinator mode detection |
| UPLOAD_USER_SETTINGS | 963 | Settings sync upload |
| BRIDGE_MODE | 2246, 3866, 4322 | Remote control entitlement check |
| BRIDGE_MODE | 2246-2255 | getDridgeDisabledReason() → sets remoteControl flag |
| CHICAGO_MCP | 1477, 1608 | Computer Use MCP + macOS setup |
| CHICAGO_MCP | 1627 | Computer Use MCP error handling |
| AGENT_MEMORY_SNAPSHOT | 2258-2273 | Agent snapshot merge dialog |
| WEB_BROWSER_TOOL | 1571 | Claude in Chrome skill hint variant |
| BG_SESSIONS | 1116 | Background session agent setting |
| UDS_INBOX | 1910, 1945 | Unix domain socket inbox messaging |
| PROACTIVE | 2197-2204 | Proactive mode prompt |
| KAIROS_BRIEF / KAIROS_BRIEF | 2184, 2201, 4623 | Brief mode feature variants |
| LODESTONE | 647-677 | Deep link URI handling |
Trust Dialog Acceptance [Line 1067, 2302]
if (!checkHasTrustDialogAccepted()) {
→ Assistant mode disabled with warning
}Permission Mode [Lines 1390-1410]
initialPermissionModeFromCLI({
permissionModeCli,
dangerouslySkipPermissions
})
→ Sets setSessionBypassPermissionsMode()
→ TRANSCRIPT_CLASSIFIER: checks auto mode gateSystem Prompt Building [Lines 1342-2209]
Base systemPrompt (CLI --system-prompt or file)
→ appendSystemPrompt (--append-system-prompt or file)
→ Teammate prompt addendum (isAgentSwarmsEnabled)
→ Brief activation prompt (KAIROS)
→ Default view chat opt-in (KAIROS_BRIEF entitlement)
→ Proactive prompt (PROACTIVE feature + not coordinator mode)
→ Assistant addendum (KAIROS + kairosEnabled)
→ Proactive system prompt again (Deprecated duplicate path)
// Line 595-596
process.on('exit', () => {
resetCursor() // Restore terminal cursor
})
// Line 598-605
process.on('SIGINT', () => {
if (process.argv.includes('-p') || process.argv.includes('--print')) {
return // Let print.ts handle via gracefulShutdown
}
process.exit(0) // Interactive mode: exit immediately
})Note: No SIGTERM handler — process relies on gracefulShutdown() in business logic
| Location | Condition | Exit | Message |
|---|---|---|---|
| 266-271 | Debug mode detected (non-ant) | process.exit(1) | None (silent) |
| 442 | Invalid JSON in --settings | process.exit(1) | "Invalid JSON provided to --settings" |
| 467 | Settings file not found | process.exit(1) | "Settings file not found: " |
| 481 | Error processing --settings | process.exit(1) | "Error processing settings: " |
| 1172 | --tmux without --worktree | process.exit(1) | "Error: --tmux requires --worktree" |
| 1176 | --tmux on Windows | process.exit(1) | "Error: --tmux is not supported on Windows" |
| 1180 | tmux not installed | process.exit(1) | "Error: tmux is not installed" |
| 1198 | Missing teammate CLI args | process.exit(1) | "--agent-id, --agent-name, --team-name must all be provided together" |
| 1283 | --session-id conflicts | process.exit(1) | "--session-id can only be used with --continue/--resume if --fork-session provided" |
| 1293 | Invalid session ID format | process.exit(1) | "Invalid session ID. Must be a valid UUID" |
| 1299 | Session ID already exists | process.exit(1) | "Session ID is already in use" |
| 1313 | --file without session token | process.exit(1) | "Session token required for file downloads" |
| 1339 | Fallback model same as main | process.exit(1) | "Fallback model cannot be the same as the main model" |
| Location | Operation | Error Handling | Recovery |
|---|---|---|---|
| 253-259 | isBeingDebugged() inspector call | Catch any → return false | Falls back to execArgv/NODE_OPTIONS check |
| 352-361 | loadSettingsFromFlag JSON parse | Catch → safeParseJSON | None (returns early) |
| 465-469 | Settings file read | Catch ENOENT → process.exit(1) | None |
| 476-481 | Settings parsing | Catch → logError + exit | None |
| 1352-1360 | System prompt file read | Catch ENOENT → process.exit(1) | None |
| 1373-1380 | Append system prompt file read | Catch ENOENT → process.exit(1) | None |
| 1425-1451 | MCP config JSON parse | Try JSON, fallback to file | Collect allErrors |
| 1462-1468 | MCP config validation | Catch → logForDebugging + exit | None |
| 2035-2043 | --agents JSON parse | Catch → logError | Continue with empty cliAgents |
| 2041-2042 | Command + agent loading | Catch → logError | None |
| 3104-3154 | Continue conversation | Catch → logEvent + exit(1) | None |
| 3160-3173 | Direct Connect session | Catch → exitWithError | gracefulShutdown(1) |
| 3205-3239 | SSH session creation | Catch → exitWithError | gracefulShutdown(1) |
| 3272-3275 | Assistant discovery | Catch → exitWithError | gracefulShutdown(1) |
Function: gracefulShutdown(code) / gracefulShutdownSync(code)
Locations:
- SSH headless error [Line 788]
- DirectConnect error [Line 3173]
- SSH error [Line 3239]
- Assistant discovery error [Line 3275]
- Trust validation error [Line 3304]
- Trust/OAuth/onboarding failures in showSetupScreens() → internal exitWithError → gracefulShutdown
// Line 2219-2229 (interactive only)
ctx = getRenderContext(false)
→ getFpsMetrics = ctx.getFpsMetrics
→ stats = ctx.stats
→ renderOptions = ctx.renderOptions
root = await createRoot(renderOptions) // Ink root creation
→ Patches console
→ Mounts React tree<root> (Ink)
↓ (pre-showSetupScreens)
<SetupScreens>
├─ Trust Dialog
├─ OAuth Login (if needed)
├─ Onboarding Flows (if needed)
└─ Resume Picker (if --resume)
↓ (post-showSetupScreens, if interactive)
<REPL> (launchRepl)
├─ Message History
├─ Tool Execution
├─ Streaming Output
└─ Input Prompt
No Ink root created [Line 2218 gate]
isNonInteractiveSession → skip:
- Ink.createRoot()
- showSetupScreens() (replaced with trust check in SDK path)
- Interactive dialogsInstead: Direct to print.ts headless execution
| State | Line | Type | Mutation Points | Mutability |
|---|---|---|---|---|
process.env.NoDefaultCurrentDirectoryInExePath |
591 | String | Set once | Immutable after |
process.env.CLAUDE_CODE_ENTRYPOINT |
539 | String | Set once | Immutable after |
process.env.CLAUDE_CODE_QUESTION_PREVIEW_FORMAT |
836 | String | Set once (via setQuestionPreviewFormat) | Immutable after |
process.env.CLAUDE_CODE_SIMPLE |
1015 | String | Set once if --bare | Immutable after |
process.env.CLAUDE_CODE_AGENT |
1117 | String | Set once if --agent | Immutable after |
process.env.CLAUDE_CODE_TASK_LIST_ID |
1142 | String | Set once if --tasks | Immutable after |
Functions called before setup():
- setIsInteractive(bool)
- setClientType(string)
- setQuestionPreviewFormat(string)
- setSessionSource(string)
- setInlinePlugins(string[])
Functions called after setup() / trust:
- setOriginalCwd(string)
- setCwdState(string)
- setAdditionalDirectoriesForClaudeMd(string[])
- setDirectConnectServerUrl(string)
- setMainLoopModelOverride(ParsedModel)
- setInitialMainLoopModel(ParsedModel | null)
- setMainThreadAgentType(string | undefined)
- setKairosActive(bool)
- setUserMsgOptIn(bool)
- setIsRemoteMode(bool)
- setSessionBypassPermissionsMode(bool)
- setSessionPersistenceDisabled(bool)
- setTeleportedSessionInfo(object)
- setChromeFlagOverride(bool)
- setFlagSettingsPath(string)
- setAllowedSettingSources(string[])
- setSdkBetas(string[])
- setAllowedChannels(string[])
- switchSession(sessionId)initialState: AppState {
// Conversation state
messages: [],
abortSignal: null,
completionError: null,
isFocused: true,
isPaused: true, // Starts paused in interactive, fired by REPL
// Tool state
tools: initialTools,
toolConfigs: {},
// UI state
activePrompt: prompt || null,
isSending: false,
isProcessingTools: false,
selectedFile: null,
scrollProgress: undefined,
// Agent state
mainThreadAgentName: mainThreadAgentDefinition?.agentType,
mainThreadAgentColor: mainThreadAgentDefinition?.color,
// Model state
modelCost: null,
modelContextUsed: null,
// Prompt suggestion state
promptSuggestion: {
text: null,
promptId: null,
shownAt: 0,
acceptedAt: 0,
generationRequestId: null
},
// Agent swarm state (KAIROS)
teamContext: assistantTeamContext ?? computeInitialTeamContext?.()
}sessionConfig {
debug: bool,
commands: Command[],
initialTools: Tool[],
mcpClients: MCP[],
autoConnectIdeFlag: bool,
mainThreadAgentDefinition: AgentDef | undefined,
disableSlashCommands: bool,
dynamicMcpConfig: Record<string>,
strictMcpConfig: bool,
systemPrompt: string | undefined,
appendSystemPrompt: string | undefined,
taskListId: string | undefined,
thinkingConfig: ThinkingConfig,
onTurnComplete?: (messages) => void
}program = new CommanderCommand()
.configureHelp(sortedHelpConfig)
.enablePositionalOptions()
.name('claude')
.description('Claude Code - ...')
.argument('[prompt]', 'Your prompt', String)
.helpOption('-h, --help', ...)| Flag | Type | Line | Effect |
|---|---|---|---|
-d, --debug [filter] |
String | 971 | Enables debug mode, sets process.argv |
-d2e, --debug-to-stderr |
Bool | 976 | Debug to stderr only (hidden) |
--debug-file <path> |
String | 980 | Write debug to file |
--verbose |
Bool | 981 | Override verbose setting |
-p, --print |
Bool | 982 | Non-interactive mode |
--bare |
Bool | 983 | Minimal mode (SIMPLE=1) |
--init |
Bool | 992 | Run Setup hooks, continue |
--init-only |
Bool | 993 | Run Setup/SessionStart, exit |
--maintenance |
Bool | 994 | Run Setup with maintenance trigger |
--output-format |
Enum | 1001 | text / json / stream-json |
--json-schema |
String | 1003 | JSON Schema validation |
--include-hook-events |
Bool | 1005 | Include all hook events in stream |
--include-partial-messages |
Bool | 1007 | Emit partial messages |
--input-format |
Enum | 1009 | text / stream-json |
--mcp-debug |
Bool | 1011 | MCP debug (deprecated) |
--dangerously-skip-permissions |
Bool | 1013 | Bypass permission checks |
--allow-dangerously-skip-permissions |
Bool | 1015 | Enable bypass option |
--thinking |
Enum | 1017 | enabled / adaptive / disabled |
--max-thinking-tokens |
Number | 1020 | Max thinking tokens (deprecated) |
--max-turns |
Number | 1023 | Max agentic turns (headless) |
--max-budget-usd |
Number | 1024 | Max $ spend on API |
--task-budget |
Number | 1030 | API-side task budget tokens |
--replay-user-messages |
Bool | 1035 | Re-emit user messages on stdout |
--enable-auth-status |
Bool | 1036 | Auth status messages (SDK) |
--allowedTools |
String | 1037 | Allowed tools (comma/space sep) |
--tools |
String | 1038 | Available tools (Bash,Edit,Read) |
--disallowedTools |
String | 1039 | Denied tools |
--mcp-config |
String[] | 1040 | MCP servers (JSON/file, space sep) |
--permission-prompt-tool |
String | 1041 | MCP tool for permission prompts |
--system-prompt |
String | 1043 | Custom system prompt |
--system-prompt-file |
String | 1044 | System prompt from file |
--append-system-prompt |
String | 1046 | Append to system prompt |
--append-system-prompt-file |
String | 1048 | Append system prompt from file |
--permission-mode |
Enum | 1049 | Permission mode (auto/eval/etc) |
-c, --continue |
Bool | 1051 | Continue recent conversation |
-r, --resume [value] |
String/Bool | 1052 | Resume by ID or search term |
--fork-session |
Bool | 1053 | Create new session on resume |
--prefill |
String | 1054 | Pre-fill prompt input |
--deep-link-origin |
Bool | 1056 | From deep link |
--deep-link-repo |
String | 1057 | Repo slug resolved by deep link |
--deep-link-last-fetch |
Number | 1058 | FETCH_HEAD mtime (epoch ms) |
--from-pr |
String/Bool | 1060 | Resume PR-linked session |
--no-session-persistence |
Bool | 1061 | Disable session save |
--resume-session-at |
String | 1062 | Resume to specific message |
--rewind-files |
String | 1064 | Restore files to state at message |
--model |
String | 1066 | Model (sonnet, opus, etc) |
--effort |
Enum | 1067 | low / medium / high / max |
--agent |
String | 1071 | Agent name |
--betas |
String[] | 1072 | Beta headers (API key users) |
--fallback-model |
String | 1073 | Fallback if default overloaded |
--workload |
String | 1074 | Workload tag for billing |
--settings |
String | 1076 | Settings JSON/file |
--add-dir |
String[] | 1077 | Additional directories |
--ide |
Bool | 1078 | Auto-connect IDE |
--strict-mcp-config |
Bool | 1079 | Only use --mcp-config |
--session-id |
String | 1080 | Specific session UUID |
-n, --name |
String | 1081 | Session display name |
--agents |
String | 1082 | Custom agents JSON |
--setting-sources |
String | 1083 | Setting sources (user/project/local) |
--plugin-dir |
String[] | 1084 | Plugin directories (repeatable) |
--disable-slash-commands |
Bool | 1086 | Disable all skills |
--chrome |
Bool | 1087 | Enable Claude in Chrome |
--no-chrome |
Bool | 1088 | Disable Claude in Chrome |
--file |
String[] | 1089 | File resources (file_id:path) |
Delegated to getCommands(cwd) → loaded dynamically
Common subcommands:
auth(login/logout)mcp(add/serve)plugin(install/list)doctor(diagnostics)clear(cache/history)
Currently Installed (Line 595-605):
process.on('exit', () => {
resetCursor() // Terminal cleanup
})
process.on('SIGINT', () => {
if (isBareMode) return // Let print.ts handle
process.exit(0)
})NOT Installed:
- SIGTERM (no handler → default kill)
- SIGHUP (no handler)
- SIGUSR1/SIGUSR2 (no handler)
Function: gracefulShutdown(code) from ./utils/gracefulShutdown.js
Callers:
| Location | Trigger | Code |
|---|---|---|
| 788 | SSH with -p flag | 1 |
| 3173 | DirectConnect error | 1 |
| 3239 | SSH session error | 1 |
| 3275 | Assistant discovery error | 1 |
| 3304 | Org validation failed | 1 |
| 3331 | Settings errors dialog exit | 1 |
| 3285 | Assistant install cancelled | 0 |
| 3292 | Assistant install success | 0 |
Behavior (expected):
- Sets
process.exitCode = code - Flushes pending async work
- Closes file handles
- Then process.exit() if not already set
Lines 2308-2314:
if (process.exitCode !== undefined) {
logForDebugging('Graceful shutdown initiated, skipping further initialization')
return // Skips REPL launch, API calls, hooks
}Safety: Trust dialog rejection → gracefulShutdown → skip API setup
Line 2241: onboardingShown = await showSetupScreens(root, ...)
Pre-requisites:
- Ink root created (interactive only)
- Commands loaded
- Plugins loaded
Blocks:
- MCP connection (prefetch runs parallel, not blocking render)
- Hooks execution
- Bootstrap data fetch
- Git operations (prefetchSystemContextIfSafe)
Post-success Actions [Lines 2279-2296]:
- Skip
/loginif just completed onboarding - Refresh remote-managed settings
- Refresh policy limits
- Clear user data cache
- Refresh GrowthBook
- Clear trusted device token
- Enroll trusted device
Rejection: Sets process.exitCode → skips to graceful exit
Pre-init: startKeychainPrefetch() [Line 20]
- Fires macOS keychain reads IN PARALLEL
- Prevents sequential reads in isRemoteManagedSettingsEligible() later
Post-trust: Keychain reads safe (trust confirmed)
Token Types:
- OAuth token (Claude.ai subscriber)
- API key (Anthropic account)
- AWS credentials (Bedrock)
- GCP credentials (Vertex)
- Session ingress token (remote sessions)
No credentials hardcoded — all loaded from:
- Keychain (macOS)
- Credential manager (Windows)
- Environment variables
- Settings files
- File descriptor (remote session)
Line 2302: const orgValidation = await validateForceLoginOrg()
Effect: If forceLoginOrgUUID set in managed settings and active token's org doesn't match → exitWithError
Gating: Managed settings only (requires org policy)
main()
├─ isBeingDebugged() ─YES─> process.exit(1) [non-ant only]
│
├─ feature('LODESTONE')
│ ├─ --handle-uri <uri> ────> handleDeepLinkUri() ─> exit
│ ├─ __CFBundleIdentifier === 'com.anthropic.claude-code-url-handler'
│ │ ─────> handleUrlSchemeLaunch() ─> exit
│ └─ [else fall through]
│
├─ feature('DIRECT_CONNECT')
│ ├─ cc:// or cc+unix:// in argv ──> parseConnectUrl()
│ │ ├─ if -p: rewrite to 'open' subcommand
│ │ └─ else: set _pendingConnect, strip argv
│ └─ [else fall through]
│
├─ feature('KAIROS')
│ ├─ `claude assistant [sessionId]`
│ │ ├─ if sessionId: set _pendingAssistantChat.sessionId
│ │ ├─ if discover: set _pendingAssistantChat.discover
│ │ └─ strip from argv
│ └─ [else fall through]
│
├─ feature('SSH_REMOTE')
│ ├─ `claude ssh [flags] <host> [cwd]`
│ │ ├─ extract flags into _pendingSSH
│ │ ├─ extract host + cwd
│ │ ├─ if -p: error + gracefulShutdownSync(1)
│ │ └─ rewrite argv
│ └─ [else fall through]
│
├─ Detect isNonInteractive (no TTY, -p, --init-only, --sdk-url)
│ ├─ [if non-interactive] stopCapturingEarlyInput()
│ └─ setIsInteractive(bool)
│
├─ Initialize entrypoint based on env + mode
│ └─ setClientType(clientType)
│
├─ eagerLoadSettings() [--settings, --setting-sources]
│ └─ validate JSON, create temp file if needed
│
└─ await run()
│
├─ Commander.js setup + preAction hook
│ │
│ └─ preAction fires when command executes (not for --help):
│ ├─ await ensureMdmSettingsLoaded()
│ ├─ await init() [full initialization]
│ ├─ process.title = 'claude'
│ ├─ initSinks() [analytics]
│ ├─ setInlinePlugins(--plugin-dir)
│ ├─ runMigrations()
│ ├─ void loadRemoteManagedSettings()
│ ├─ void loadPolicyLimits()
│ └─ void uploadUserSettingsInBackground() [UPLOAD_USER_SETTINGS]
│
└─ .action(async (prompt, options) => {
│
├─ if --bare: set CLAUDE_CODE_SIMPLE=1
│
├─ Extract options into typed vars
│
├─ Validate system prompts [can't use both --system-prompt + --system-prompt-file]
│
├─ Parse MCP configs [--mcp-config, validate, merge]
│
├─ Setup Claude in Chrome [feature('CHICAGO_MCP')]
│
├─ Initialize permission mode [--permission-mode, --dangerously-skip-permissions]
│ └─ Auto mode gate (TRANSCRIPT_CLASSIFIER)
│
├─ isNonInteractiveSession?
│ ├─ YES: skip Ink root creation
│ │ skip showSetupScreens()
│ │ skip dialogs
│ │
│ └─ NO:
│ ├─ getRenderContext() + createRoot()
│ ├─ installAsciicastRecorder() [ant-only]
│ ├─ await showSetupScreens() [trust + OAuth + onboarding]
│ │ └─ if BRIDGE_MODE: check remoteControl entitlement
│ ├─ check agent memory snapshot [AGENT_MEMORY_SNAPSHOT]
│ ├─ if onboardingShown: refresh auth + GrowthBook
│ ├─ validateForceLoginOrg()
│ └─ [skip if process.exitCode set]
│
├─ initializeLspServerManager() [after trust]
│
├─ Show settings validation errors [interactive only]
│
├─ Check quota + bootstrap data [non-bare only]
│
├─ Start prefetches (async, non-blocking):
│ ├─ initUser()
│ ├─ getUserContext()
│ ├─ getRelevantTips()
│ ├─ prefetchAwsCredentialsAndBedRockInfoIfSafe()
│ ├─ prefetchGcpCredentialsIfSafe()
│ ├─ countFilesRoundedRg()
│ ├─ initializeAnalyticsGates()
│ ├─ settingsChangeDetector.initialize()
│ └─ skillChangeDetector.initialize() [non-bare]
│
├─ Load commands + agents
│
├─ Parse --agents JSON flag
│
├─ Merge CLI + disk agents
│
├─ Load & validate main thread agent [--agent]
│
├─ Build effective system prompt:
│ ├─ Base (--system-prompt or file)
│ ├─ Append section (--append-system-prompt or file)
│ ├─ Teammate prompt [isAgentSwarmsEnabled]
│ ├─ Brief activation [KAIROS]
│ ├─ Default view chat [KAIROS_BRIEF]
│ └─ Proactive mode [PROACTIVE + not coordinator]
│
├─ Load MCP configs [--mcp-config merged with file-based]
│
├─ Prefetch MCP resources [interactive only]
│
├─ Start hooks (async) [unless --continue/--resume/--init/--init-only]
│
├─ Initialize thinking config [--thinking, --max-thinking-tokens]
│
├─ Increment numStartups + log telemetry
│
├─ Create initialState (AppState)
│
└─ Branch on resume/continue/special modes:
│
├─ options.continue?
│ ├─ loadConversationForResume()
│ ├─ processResumedConversation()
│ └─ launchRepl() with loaded state
│
├─ _pendingConnect?.url? [DIRECT_CONNECT]
│ ├─ createDirectConnectSession()
│ └─ launchRepl() with directConnectConfig
│
├─ _pendingSSH?.host? [SSH_REMOTE]
│ ├─ createSSHSession() or createLocalSSHSession()
│ └─ launchRepl() with sshSession
│
├─ _pendingAssistantChat? [KAIROS]
│ ├─ discoverAssistantSessions() or use sessionId
│ ├─ launchAssistantInstallWizard() [if no sessions]
│ └─ launchRepl() with assistant config
│
├─ options.resume? [--resume or --from-pr]
│ ├─ loadConversationForResume(sessionId or search)
│ ├─ processResumedConversation()
│ └─ launchRepl() with loaded state
│
├─ feature('COORDINATOR_MODE') && COORDINATOR_MODE env?
│ ├─ coordinatorModeModule.setupCoordinatorMode()
│ └─ launchRepl() with coordinator config
│
├─ Teleport mode? [--teleport flag]
│ ├─ teleportWithProgress()
│ └─ launchRepl() with teleported state
│
├─ Remote mode? [--remote, --remote-control]
│ ├─ createRemoteSessionConfig()
│ ├─ fetchSession() if resuming remote
│ ├─ createRemoteSession() / fetchSession()
│ └─ launchRepl() with remote config
│
└─ Default: interactive with initial prompt
└─ launchRepl(root, initialState, sessionConfig, renderAndRun)
├─ mounts <REPL> component
├─ fires up renderAndRun loop
└─ [awaits user input, executes turns]
| Line | Comment | Severity |
|---|---|---|
| 2355 | TODO: Consolidate other prefetches into a single bootstrap request | Medium |
| 323 | @[MODEL LAUNCH]: Consider migrations for model strings | Maintenance |
| 139 | Plugin startup checks now handled non-blockingly in REPL.tsx | Informational |
| 68 | Lazy require to avoid circular dependency | Architecture |
| Line | Issue | Status |
|---|---|---|
| 239-240 | Bun single-file executable leaks app args into process.execArgv | Workaround in place |
| 606-604 | Print mode's own SIGINT handler in print.ts may preempt main's handler | Design: intentional |
| 2012-2014 | Ant model aliases require GrowthBook init on cold cache | Workaround: await init() |
| 2333 | Settings validation errors don't block (MCP errors excluded from display) | Acceptable risk |
| Macro | Value | Effect |
|---|---|---|
"external" === 'ant' |
false in external builds | Ant-only code paths gated |
"external" === 'ant' |
true in ant builds | Enables session data upload, event loop stall detector, assistant mode |
MACRO.VERSION |
Build constant | Inserted into telemetry |
// Eliminated at bundle time if feature('FLAG') === false:
feature('COORDINATOR_MODE'):
└─ require('./coordinator/coordinatorMode.js')
└─ All coordinator mode branching
feature('KAIROS'):
└─ require('./assistant/index.js')
└─ require('./assistant/gate.js')
└─ All assistant/teammate code
feature('SSH_REMOTE'):
└─ require('./ssh/createSSHSession.js')
└─ All SSH session code
feature('DIRECT_CONNECT'):
└─ require('./server/parseConnectUrl.js')
└─ All direct connect branching
feature('TRANSCRIPT_CLASSIFIER'):
└─ require('./utils/permissions/autoModeState.js')
└─ All auto mode gating
feature('CHICAGO_MCP'):
└─ require('./utils/computerUse/common.js')
└─ All computer use MCP code
feature('LODESTONE'):
└─ require('./utils/deepLink/...')
└─ All deep link handlingNone found — codebase is clean (no // const x = ... patterns)
None — all exit points properly analyzed
| Import | Purpose | Security |
|---|---|---|
./utils/startupProfiler.js |
Performance measurement | Low risk |
./utils/settings/mdm/rawRead.js |
MDM subprocess spawning | Subprocess control |
./utils/secureStorage/keychainPrefetch.js |
Keychain async reads | Sensitive data |
./entrypoints/init.js |
Full initialization | Trust handling |
@commander-js/extra-typings |
CLI parsing | Input validation |
chalk |
Terminal colors | Low risk |
bun:bundle |
Feature flag gating | Build-time |
| Import | Purpose |
|---|---|
./utils/auth.js |
Credentials, subscriptions |
./utils/config.js |
Trust dialog, global config |
./utils/secureStorage/keychainPrefetch.js |
Keychain reads |
./utils/sessionIngressAuth.js |
Remote session tokens |
| Import | Purpose |
|---|---|
./services/api/bootstrap.js |
API bootstrap data |
./services/mcp/client.js |
MCP connections |
./services/policyLimits/index.js |
Enterprise policy |
./services/remoteManagedSettings/index.js |
Org settings sync |
./tools.js |
Built-in tools |
./commands.js |
CLI subcommands |
| Import | Purpose |
|---|---|
./ink.js |
React/Ink renderer |
./replLauncher.js |
REPL component |
./interactiveHelpers.js |
Setup dialogs |
./dialogLaunchers.js |
Trust, OAuth, onboarding |
process.on('exit', () => {
resetCursor() // Restore terminal
})Called before: process.exit() completes
Expected behavior:
- Set
process.exitCode = code - Close open file handles
- Flush pending async operations
- Close database connections (if any)
- Let process exit naturally (exit event fires)
Actual implementation: Not defined in main.tsx (imported but not shown)
Line 2493:
registerCleanup(async () => {
logForDiagnosticsNoPII('info', 'exited')
})Purpose: Fire diagnostics log at exit
Timing: Likely fires during gracefulShutdown()
Line 3064:
sessionUploaderPromise = "external" === 'ant' ?
import('./utils/sessionDataUploader.js') : nullCleanup: Likely flushed by gracefulShutdown() awaiting pending promises
Scan results:
- No API keys in source
- No tokens in source
- No passwords in source
- No private keys in source
| URL | Context | Security |
|---|---|---|
'com.anthropic.claude-code-url-handler' |
macOS bundle ID detection | Safe (public ID) |
getOauthConfig().BASE_API_URL |
Files API base | Dynamic (not hardcoded) |
process.env.ANTHROPIC_BASE_URL |
Override for Files API | Environment-driven |
| Path | Purpose | Platform |
|---|---|---|
| None detected | — | — |
Note: All config paths are environment-driven or user-specified
Line 454:
settingsPath = generateTempFilePath('claude-settings', '.json', {
contentHash: trimmedSettings
})Purpose: Create content-addressable temp file to avoid cache invalidation
Security: Hash-based naming (deterministic, not random)
| Location | Operation | Behavior |
|---|---|---|
| 226-228 | logManagedSettings() errors | Silently ignored |
| 349-351 | migrateChangelogFromConfig() errors | Silently ignored |
| 1556-1560 | Claude in Chrome setup errors | Logged but continues |
| 1574-1575 | Claude in Chrome auto-enable errors | Silently skipped |
| 1932-1933 | Deferred prefetch errors | Caught but not handled |
| 2041-2042 | --agents JSON parse errors | Logged, empty array used |
| 3453 | MCP prefetch transient rejection | Suppressed |
| Platform | Behavior |
|---|---|
| macOS | Keychain reads, URL scheme launch, mdm plutil query |
| Windows | Registry query for MDM, NoDefaultCurrentDirectoryInExePath |
| Linux | No platform-specific behavior |
Critical: These assume init() has completed:
getGlobalConfig()— reads ~/.claude/config.jsongetInitialSettings()— reads ~/.claude/settings.jsongetSystemContext()— runs git commandsgetUserContext()— spawns subprocesses
Enforcement: All called after await init() in preAction hook
High Priority:
-
Command-line argument parsing — complex rewriting (cc://, ssh, assistant)
- Mitigation: Early, explicit parsing with bounds checks
-
Settings file loading — JSON injection possible
- Mitigation:
safeParseJSON()wrapper - Risk: Temp file created at deterministic path (but content-hashed)
- Mitigation:
-
MCP server loading — arbitrary code execution
- Mitigation: Feature-gated, policy-enforced, user-approved
- Risk: Runs after trust dialog, before permission checks
-
Trust dialog bypass — many prefetches run before trust check
- Mitigation: Non-sensitive operations only (git, keychain reads safe)
- Risk: Git hooks can execute code (documented, prefetch guarded)
-
Directory traversal — --add-dir paths
- No explicit path canonicalization in main.tsx
- Risk: Handled by called functions (assumptionin permissions layer)
| Mechanism | Implementation | Effectiveness |
|---|---|---|
| Trust dialog | showSetupScreens() blocks setup | Strong |
| Permission modes | initialPermissionModeFromCLI() | Strong (gated) |
| MDM management | Applied via init() → applyConfigEnvironmentVariables() | Strong |
| Windows PATH | NoDefaultCurrentDirectoryInExePath=1 | Strong |
| Debug prevention | isBeingDebugged() exit | Strong (non-ant only) |
| Git security | prefetchSystemContextIfSafe() | Strong (trust gated) |
Low Risk:
- Process title set from env → information disclosure (non-sensitive)
- Terminal title visible to parent process (expected)
- Telemetry includes public info (source, version, platform)
Medium Risk:
- SSH session spans lifecycle without explicit cleanup (relies on gracefulShutdown)
- Keychain reads prefetched without trust (mitigated: non-sensitive until auth)
- Feature flags may not remove code entirely (rely on bundle tree-shaking)
Not Found:
- Command injection
- Path traversal
- Credential leakage
- Privilege escalation
Claude Code main.tsx is a sophisticated bootstrapping layer with:
-
Multi-stage initialization starting with async subprocess launches, followed by module evaluation, explicit state setup, and trust establishment.
-
Complex argument rewriting for special modes (cc://, ssh, assistant) with careful argv manipulation to support both interactive and headless execution.
-
Feature-gated dead code elimination for multiple experimental modes (KAIROS, COORDINATOR_MODE, CHICAGO_MCP, SSH_REMOTE, DIRECT_CONNECT).
-
Robust error handling with early validation, graceful shutdown triggers, and careful sequencing of trust-sensitive operations.
-
Security boundaries around trust dialog, permission modes, MDM/policy enforcement, and git operations.
-
No hardcoded credentials — all secrets loaded from keychains, environment variables, or files.
-
Deferred prefetches to reduce critical path while warming caches for first-turn responsiveness.
-
Profile checkpoints throughout for performance measurement and startup optimization.
The file is production-quality with minimal technical debt and thoughtful architecture decisions.