Skip to content

CLI main paths in the extracted cli.js

Scope

This page is a full-analysis reverse-engineering pass over the extracted Claude Code CLI bundle:

  • Artifact: claude-code-pkg/src/entrypoints/cli.js
  • Package version: @anthropic-ai/claude-code@2.1.143
  • Native package: @anthropic-ai/claude-code-linux-x64@2.1.143
  • Extracted file identity: 14,548,665 bytes, approximately 19,592 source lines, SHA-256 7ee77e22cde2618030c26182d43d8be82f68cbb2ed063f72778c1a5986d0943a
  • Bun graph entrypoint: /$bunfs/root/src/entrypoints/cli.js

The bundle is minified and bundled, but it still contains readable JavaScript and user-facing strings. Source locations below use approximate line numbers and byte offsets plus exact symbols or strings.

Source anchors

Semantic aliasSource fileApproximate locationAnchorMeaning
FinalEntrypointMirrorscripts/extract-claude-code-final-artifacts.mjsrepository scriptFINAL_ROOT_FILES, src/entrypoints/cli.jsMirrors the Bun graph entrypoint into the retained claude-code-pkg/src/entrypoints/cli.js path.
BunGraphEntrypointclaude-code-pkg/src/entrypoints/cli.jsline ~1, byte 0x3// @bun @bytecode @bun-cjsConfirms the retained file is the Bun standalone graph entrypoint.
OuterBootstrapcli.jsline ~19590, byte 0xddd998async function J9AOuter process bootstrap and fast-path command handling.
BootstrapLazyMainImportcli.jsline ~19592, byte 0xddfe32let{main:f}=await Promise.resolve().then(() => (p08(),zo6))Lazy load of the bundled CLI module, then main().
MainModuleInitializercli.jsline ~19551, byte 0xdce054var p08=T(()=>Bundled module initializer for the main CLI module.
MainBundleExportscli.jsline ~19523, byte 0xdbda2fvar zo6={}; j$(zo6,{startDeferredPrefetches:()=>B08,main:()=>O4A})Export surface for main and deferred prefetches.
TopLevelMaincli.jsline ~19524, byte 0xdbe79fasync function O4A()Top-level CLI main.
DeepLinkTrampolinecli.jsline ~19524, byte 0xdbe820process.argv.indexOf("--handle-uri")Early deep-link URI trampoline branch.
HeadlessInitialPredicatecli.jsline ~19524, byte 0xdbe925`let $=process.argv.slice(2),q=$.includes(“-p”)
EntrypointEnvNormalizercli.jsline ~129, byte 0xe4cdbfunction pzq(H)Sets or normalizes CLAUDE_CODE_ENTRYPOINT based on CLI mode.
SessionStartClassifiercli.jsline ~129, byte 0xe4e95function Uzq(H)Classifies the session start type from argv, including resume/from-PR style starts.
AiAgentEnvBootstrapcli.jsline ~11, byte 0x1025function cV$()Environment bootstrap that sets AI_AGENT to a Claude Code/version string when appropriate.
CommanderRootcli.jsline ~19525, byte 0xdbf0e0async function w4A()Commander root command construction and runtime branch routing.
ClaudeRootCommandcli.jsline ~19525, byte 0xdbf678H.name("claude")Root CLI command and user-facing description.
RootActionBodycli.jsline ~19525, byte 0xdc2372.action(async(A,z)=>Root command action body; most CLI mode decisions happen inside this action.
PrintFastParsePathcli.jsline ~19550, byte 0xdcb906if($&&!q)return ... H.parseAsync(process.argv)Fast parse path for --print that skips subcommand registration unless a cc:///cc+unix:// argument is present.
McpHeadlessCoordinatorcli.jsline ~19294, byte 0xd917c8function fH9(H)MCP connection coordinator used by headless setup.
HeadlessMcpSetupcli.jsline ~19543, byte 0xdc73falet o4=fH9({regularMcpConfigs:WwHeadless branch creates the MCP coordinator.
HeadlessRunnerLazyImportcli.jsline ~19543, byte 0xdc75cflet{runHeadless:u7}=await Promise.resolve().then(() => (M89(),O89))Lazy import of the print/headless runner.
HeadlessRunnercli.jsline ~19324, byte 0xda31bbasync function T7AImplementation of runHeadless.
HeadlessControlLoopcli.jsline ~19349, byte 0xda50d0function H89Headless streaming/control loop.
InteractiveBranchSetupcli.jsline ~19540, byte 0xdc5b9dif(!ZH){let W8=ua4(!1)Interactive UI branch initialization.
InteractiveSessionLoopcli.jsline ~19543, byte 0xdc8bf0await pT$(Y7Interactive TUI/session loop entry.
InteractiveResumePickercli.jsline ~19550, byte 0xdca950await aa4(Y7Interactive resume/search picker fallback.
ContinueRecentSessionBranchcli.jsline ~19543, byte 0xdc89e9if(z.continue)Continue-most-recent-session branch.
ResumeRemoteSessionBranchcli.jsline ~19543, byte 0xdc8dc5`else if(z.resume
McpCommandRegistrarcli.jsline ~9173, byte 0xbf3c40function rR4(H)mcp subcommand registrar.
PluginCommandRegistrarcli.jsline ~9297, byte 0xbfca96function fC4(H)plugin/plugins subcommand registrar.
UtilitySubcommandRegistrycli.jsline ~19550, bytes 0xdcb973-0xdcd31bH.command("auth"), H.command("project"), H.command("agents"), H.command("install [target]")Top-level utility subcommands registered after the root command.
StartupProfilingEventscli.jsline ~64, byte 0x33865XA9={import_timeStartup profiling event groups such as cli_entry, main_tsx_imports_loaded, and cli_before_main_import.

High-level call graph

flowchart TD
A[ELF Bun standalone entrypoint] --> B[Outer bootstrap]
B --> C{fast path?}
C -->|--version/-v/-V| V[print VERSION and exit]
C -->|background/daemon helpers| D[daemon/background handlers]
C -->|normal CLI| E[main module init + exported main]
E --> F[Top-level main]
F --> G{--handle-uri?}
G -->|yes| H[handleDeepLinkUri and process.exit]
G -->|no| I[Commander root]
I --> J{root action mode}
J -->|print/sdk/init/non-TTY| K[headless branch]
K --> L[MCP runtime coordinator]
L --> M[Headless runner]
M --> N[Headless streaming and control loop]
J -->|interactive TTY| O[interactive branch]
O --> P{resume/continue/remote?}
P -->|continue/resume/teleport/remote| Q[session restore or remote attach]
P -->|picker needed| R[Interactive resume picker]
P -->|fresh session| S[Interactive TUI/session loop]

Bootstrap path

OuterBootstrap is not just a trivial wrapper: it contains fast paths before the full main bundle is loaded.

  1. It reads process.argv.slice(2).
  2. If the arguments are only --version, -v, or -V with an optional --verbose, it prints the embedded product version without importing the full main path.
  3. It checks background/daemon helper flags before normal CLI dispatch.
  4. For normal CLI startup, it records startup profiling events, starts early input capture, lazily initializes the main module, reads the exported main, and awaits it.

The BootstrapLazyMainImport anchor means the exported TopLevelMain path is reached only after the bundled module initializer runs.

Top-level main path

TopLevelMain is the first full CLI main function.

  1. It initializes warning/exit handling and checks --handle-uri before normal command parsing.
  2. The initial mode predicate is:
    • -p or --print
    • --init-only
    • any --sdk-url... argument
    • !process.stdout.isTTY
  3. If that predicate is true, it enables non-interactive setup (JfH() in the minified bundle).
  4. It calls startup classifiers and environment setup:
    • jv8(!A) — records whether this is an interactive-style run.
    • pzq(A) — normalizes CLAUDE_CODE_ENTRYPOINT; when no entrypoint exists, headless-like runs become sdk-cli and interactive runs become cli.
    • Nv8(Uzq($)) — records session start type from argv.
    • cV$() — sets AI_AGENT to a Claude Code/version string when it is absent or already Claude Code-owned.
  5. It derives a client type from constants such as GITHUB_ACTIONS, CLAUDE_CODE_ENTRYPOINT, CLAUDE_CODE_SESSION_ACCESS_TOKEN, and CLAUDE_CODE_WEBSOCKET_AUTH_FILE_DESCRIPTOR.
  6. It eagerly loads settings and then awaits CommanderRoot.

The important split is that TopLevelMain decides process-level mode and environment identity, while CommanderRoot owns Commander setup and the deeper headless/interactive path split.

Commander root setup

CommanderRoot constructs a Commander-like instance with configured help and positional options. The root command is named claude and has the user-facing description:

Claude Code - starts an interactive session by default, use -p/--print for non-interactive output

The root command accepts an optional [prompt], many options, and a large root action. The preAction hook performs shared initialization before subcommands or root action handlers run:

  • device/MDM and startup initialization;
  • terminal title setup;
  • sink/log initialization;
  • inline plugin directory/URL collection;
  • settings migrations;
  • remote/gateway settings refresh;
  • settings cache invalidation subscriptions.

There is one performance-sensitive special case: if the process includes -p or --print and the argv does not include a cc:// or cc+unix:// URI, CommanderRoot parses immediately after root options are built. In that fast path, it returns before registering heavier subcommands such as mcp, plugin, auth, and agents.

Main mode decision table

Runtime pathTriggerKey semantic anchorsDownstream path
Version fast path--version, -v, or -V as the only command, optional --verboseOuterBootstrap, product constant VERSION:"2.1.143"Print version and exit before full main import.
Deep link trampoline--handle-uri <uri>process.argv.indexOf("--handle-uri"), handleDeepLinkUriEnable config, parse URI, launch terminal/session, then process.exit(D).
Print/headless-p, --print, --init-only, --sdk-url..., or stdout not TTYHeadlessInitialPredicate, headless branch, HeadlessRunner, HeadlessControlLoopBuild headless app state, connect MCP, run the headless runner, drain the streaming/control loop.
SDK transport--sdk-url plus stream JSON formats--sdk-url <url>, --input-format=stream-json, --output-format=stream-json checksUses remote WebSocket/SSE transport and headless control protocol.
Interactive fresh sessionTTY output, no print/sdk/init-only branch, no resume/remote branchInteractiveBranchSetup, InteractiveSessionLoopCreate UI root, run setup screens, load tools/agents/MCP, enter TUI loop.
Continue last session-c or --continueContinueRecentSessionBranch, SessionDiscovery, SessionRestore, InteractiveSessionLoopLoad most recent transcript, restore runtime state, enter TUI.
Resume/search picker-r, --resume, --from-prResumeRemoteSessionBranch, InteractiveResumePickerResolve session ID/title/PR, restore if exact, otherwise open picker.
Teleporthidden --teleport [session]AH=z.teleport??null, teleportWithProgressValidate remote session/repo state, hydrate messages, enter TUI.
Remote sessionhidden `—remote [descriptionsession_idurl]`
Remote Controlhidden --remote-control [name] / --rc or remote-control subcommandremote-control, rc, bridgeMain, initReplBridgeExposes local sessions to claude.ai/code or mobile control channels.

ZH is a minified local variable in the root action. The branch it guards is identified semantically as the non-interactive/headless branch because it validates print-only options, sets JSON output handling, creates headless app state, connects MCP, imports runHeadless, and returns without creating the interactive UI root.

Headless/print path

The headless branch is the path used by claude -p, SDK-style transports, init-only runs, and non-TTY stdout.

Confirmed steps:

  1. Validate output/input format combinations:
    • --output-format supports text, json, and stream-json.
    • --input-format=stream-json requires --output-format=stream-json.
    • --sdk-url requires both stream JSON input and output.
    • --include-partial-messages requires print mode and stream-json output.
  2. Read prompt/stdin through M4A(...), including a 10 MiB piped-stdin limit.
  3. Run setup and load command/tool/agent definitions.
  4. Build a headless state store with model, MCP, permission, effort, fast-mode, and advisor fields.
  5. Construct an MCP coordinator and call connect().
  6. Start deferred background prefetch work unless disabled by simple/exit flags.
  7. Lazy import runHeadless and call it with prompt, state accessors, tools, SDK MCP configs, active agents, resume options, output format, thinking config, and session hooks.

Inside HeadlessRunner:

  • validates resume-only flags such as --resume-session-at and --rewind-files;
  • sets up SDK/stream JSON output guards;
  • initializes sandboxing when enabled;
  • loads initial messages through A89 for --continue, --resume, teleport, or session-start hooks;
  • checks that print mode has input unless a resumed deferred-tool marker or SDK transport supplies it;
  • prepares permission prompt behavior through K89/q89;
  • drains the streaming/control loop through HeadlessControlLoop;
  • writes final output as plain text, JSON result, or stream JSON frames.

HeadlessControlLoop is the main headless event loop. It handles stream JSON input, control requests, MCP status and calls, permission responses, remote-control requests, background task controls, bash command messages, user prompts, session state, and result emission. The presence of many control_request subtypes in this function makes it the headless equivalent of the interactive UI dispatcher.

Interactive path

The interactive branch begins when the root action does not take the headless branch.

Confirmed steps:

  1. Create render options through ua4(false) and an interactive root via createRoot.
  2. Run setup/login/trust screens via ba4(...) and related policy checks.
  3. Load settings, tools, commands, MCP configs, plugin state, custom agents, and model configuration.
  4. Emit startup telemetry and notifications.
  5. Resolve the session path:
    • --continue loads the most recent transcript through SessionDiscovery, restores it through SessionRestore, and enters InteractiveSessionLoop.
    • --resume resolves an explicit UUID/title/file, restores through SessionRestore, and enters InteractiveSessionLoop if exact.
    • --from-pr or ambiguous resume search falls back to InteractiveResumePicker.
    • --remote creates or attaches to a remote session and enters InteractiveSessionLoop with remoteSessionConfig.
    • --teleport validates and hydrates remote session logs, then enters InteractiveSessionLoop.
    • a fresh session enters InteractiveSessionLoop with optional deep-link/prefill warnings and startup hook messages.

The stable semantic entrypoints are therefore InteractiveSessionLoop for the main interactive TUI/session loop and InteractiveResumePicker for the picker/search-style resume path.

MCP path

There are two important MCP surfaces in this file:

  1. The mcp user-facing subcommand tree is registered by McpCommandRegistrar. It includes surfaces such as serve, add, remove, list, get, add-json, add-from-claude-desktop, reset-project-choices, and, when enabled, xaa management.
  2. Runtime MCP connection for headless mode is coordinated by McpRuntimeCoordinator. It splits regular configs into alwaysLoad and non-alwaysLoad sets, handles MCP_CONNECTION_NONBLOCKING, connects regular servers, connects claude.ai connectors, deduplicates plugin servers that duplicate claude.ai connectors, and retries transient remote failures.

In the root action, MCP configs are assembled from CLI flags, settings, project config, enterprise policy, claude.ai connectors, Chrome/computer-use integration, and agent frontmatter. The headless branch then passes regularMcpConfigs and a claudeaiConfigPromise into McpRuntimeCoordinator; the interactive branch resolves MCP client/tool/command promises before entering the TUI.

Top-level commands

The root command registers these main command families outside the print fast path:

CommandAnchorHandler shape
mcpMcpCommandRegistrarConfigures and manages MCP servers; also has serve and optional xaa subcommands.
plugin / pluginsPluginCommandRegistrarManages plugins and marketplaces; validates, lists, installs, updates, disables, and removes plugin surfaces.
authH.command("auth")login, status, and logout subcommands import auth handlers lazily.
project purge [path]H.command("project")...command("purge [path]")Deletes project-scoped Claude Code state such as transcripts, tasks, file history, and config entries.
setup-tokenH.command("setup-token")Sets up a long-lived authentication token for Claude subscription users.
agentsH.command("agents")Opens/manages background agents; in TTY mode can mount the fleet view.
ultrareview [target]H.command("ultrareview [target]")Launches cloud-hosted multi-agent code review and prints findings.
auto-modeH.command("auto-mode")Inspects auto-mode classifier defaults/config and can run an AI critique of custom rules.
remote-control / rcH.command("remote-control", {hidden: true}).alias("rc")Hidden command for local-session control from claude.ai/code or mobile.
doctorH.command("doctor")Checks auto-updater health and related environment state.
update / upgradeH.command("update").alias("upgrade")Checks for updates and installs if available.
install [target]H.command("install [target]")Installs the native Claude Code build for stable, latest, or a specific version.

Root flag families

The root action consumes a large option surface. The most important groups are:

FamilyRepresentative flagsRuntime implication
Debug/diagnostics--debug, --debug-file, --verbose, --mcp-debugEnables debug logging, stderr/file logs, or verbose output.
Headless/output-p, --print, --output-format, --input-format, --json-schema, --include-partial-messages, --replay-user-messages, --sdk-urlSelects print/SDK paths and result framing.
Minimal startup--bare, --init, --init-only, --maintenanceReduces or changes setup hook behavior; --bare sets CLAUDE_CODE_SIMPLE=1.
Permissions/tools--dangerously-skip-permissions, --allow-dangerously-skip-permissions, --permission-mode, --allowedTools, --tools, --disallowedTools, --permission-prompt-toolShapes tool availability and permission prompts.
Prompt/system--system-prompt, --system-prompt-file, --append-system-prompt, --append-system-prompt-file, --plan-mode-instructions, --exclude-dynamic-system-prompt-sectionsOverrides or appends system prompt content and cache-sensitive sections.
Sessions--continue, --resume, --fork-session, --from-pr, --session-id, --no-session-persistence, --resume-session-at, --rewind-files, --nameControls local transcript/session restore, forking, persistence, and display naming.
Model/thinking--model, --fallback-model, --effort, --thinking, --thinking-display, --max-thinking-tokens, --max-turns, --max-budget-usd, --task-budget, --betasSelects model, thinking mode, budget, and beta headers.
MCP/plugins/settings--mcp-config, --strict-mcp-config, --settings, --managed-settings, --setting-sources, --plugin-dir, --plugin-url, --agentsAdds dynamic MCP/plugin/agent/settings inputs.
Workspace/integrations--add-dir, --ide, --chrome, --no-chrome, --fileAdds tool-access directories and optional IDE/Chrome/file-resource integration.
Deep link/remote hidden flags--prefill, --deep-link-origin, --prefill-b64, --deep-link-cwd-b64, --teleport, --remote, --remote-control, --rcUsed by deep-link launching, remote sessions, and Remote Control.

High-signal constants and environment variables

Constant/stringAnchorMeaning
VERSION:"2.1.143"line ~11, byte 0xdc5Embedded product version used by version output, update checks, and telemetry.
BUILD_TIME:"2026-05-15T17:39:39Z"adjacent to VERSIONEmbedded build time.
GIT_SHA:"cfb8132e4c3551e2773f41a1900efd1cc93637db"adjacent to VERSIONEmbedded source revision identifier.
CLAUDE_CODE_ENTRYPOINTline ~129, byte 0xe4be7Runtime entrypoint classifier; examples include cli, sdk-cli, sdk-ts, sdk-py, remote, claude-vscode, and claude-desktop.
CLAUDE_CODE_SIMPLEline ~11, byte 0xe572Minimal/bare mode switch; --bare sets this env var.
CLAUDE_CONFIG_DIRline ~11, byte 0xe9a0Overrides the default ~/.claude configuration directory.
ANTHROPIC_API_KEYline ~43, byte 0x264c0API key source in the embedded Anthropic SDK/runtime path.
ANTHROPIC_AUTH_TOKENadjacent to ANTHROPIC_API_KEYOAuth/token source in SDK credential handling.
GITHUB_ACTIONSin TopLevelMain client-type selectionClassifies the runtime as github-action.
CLAUDE_CODE_SESSION_ACCESS_TOKENin TopLevelMain and remote I/O codeRemote/session ingress token signal.
CLAUDE_CODE_WEBSOCKET_AUTH_FILE_DESCRIPTORin TopLevelMain client-type selectionRemote/WebSocket auth signal.
CLAUDE_CODE_ENVIRONMENT_KINDin TopLevelMain, headless/remote pathsIdentifies bridge/remote-control runtime kind.
MCP_CONNECTION_NONBLOCKINGin McpRuntimeCoordinatorControls whether MCP connection proceeds asynchronously/non-blocking.
CLAUDE_CODE_USE_BEDROCK, CLAUDE_CODE_USE_VERTEX, CLAUDE_CODE_USE_MANTLE, CLAUDE_CODE_USE_ANTHROPIC_AWSin deferred prefetch workProvider-specific background credential/auth prefetch gates.

Path summary

The main paths identified from cli.js are:

  1. Outer Bun/bootstrap pathOuterBootstrap handles version and daemon/background shortcuts, then lazy-loads the main module export.
  2. Deep-link pathTopLevelMain handles --handle-uri before Commander setup.
  3. Commander root pathCommanderRoot builds root flags, preAction setup, root action, and subcommands.
  4. Headless/print path — selected by -p, --print, --init-only, --sdk-url, or non-TTY stdout; connects MCP and runs HeadlessRunner/HeadlessControlLoop.
  5. Interactive fresh-session path — creates the UI root, runs setup screens, and enters InteractiveSessionLoop.
  6. Resume/continue path — loads transcripts through SessionDiscovery, restores state through SessionRestore, then enters InteractiveSessionLoop or InteractiveResumePicker.
  7. Remote/teleport/Remote Control path — creates or attaches to hosted/remote sessions and bridges control messages into the same interactive/headless dispatch surfaces.
  8. MCP path — user-facing mcp commands are registered by McpCommandRegistrar; runtime connection is coordinated by McpRuntimeCoordinator and related reconnect/dedup logic.
  9. Utility subcommandsauth, project purge, setup-token, agents, ultrareview, auto-mode, doctor, update, and install lazy-load their specialized handlers.

Caveats

  • The analyzed file is bundled/minified output. Exact anchors behind aliases such as TopLevelMain, CommanderRoot, HeadlessRunner, and InteractiveSessionLoop are stable only for this extracted build and should be paired with exact strings or byte offsets.
  • Several early helpers live on very long lines; line numbers are approximate and less stable than byte offsets plus exact symbols.
  • No sourcemaps were found during temporary Bun module graph inspection, so this analysis does not recover the original TypeScript source tree.
  • JavaScriptCore bytecode can corroborate compiled code existence through optional dumps, but it is not retained here or used as recovered source.
  • Deeper helper-level analysis can continue from the focused module docs rather than this path-summary page.

Created and maintained by Yingting Huang.