CC
Claude Code
v2.1.88
Claude CodeBridge Module

Bridge Module

12 files · ~13K lines

The SDK Bridge — Claude Code as a Library. The same QueryEngine that powers the terminal REPL can run headlessly as a programmatic API. This is how subagents spawn, and how Claude Code scales to remote workers.

🔀

One Engine, Two Faces

The core insight: the entire 7-phase query loop is identical in both terminal and SDK modes. The Bridge is not a separate runtime — it's just a different output adapter on top of the exact same engine.

Terminal Mode vs SDK Mode

The same core loop runs in both modes. The Bridge is the diff — it swaps output and permissions handling.

Terminal Mode
entrypoints/cli.tsx
QueryEngine (shared)shared
Ink REPL.tsx UI
Terminal permission dialog
ANSI → stdout
SDK / Headless Mode
entrypoints/sdk/ → Bridge
QueryEngine (shared)shared
No UI
Programmatic callback
SDKMessage async iterator
QueryEngine + 7-phase loop — identical in both modes

This is the core architectural fact about Bridge. It's adapters all the way down.

AspectTerminalSDK / Headless
Entry pointentrypoints/cli.tsx → main.tsxentrypoints/sdk/ → Bridge
QueryEngineSame QueryEngine classSame QueryEngine class
query() loopIdentical 7-phase loopIdentical 7-phase loop
OutputANSI escape codes → terminal stdoutSDKMessage objects → async iterator
UIInk component tree (REPL.tsx)No UI — caller processes messages
PermissionsUser dialog in terminalProgrammatic approval callback

SDK Usage — 3 Entry Points

Real code showing how to use Claude Code as a library. Three patterns for three use cases.

runClaude() — One-shot async iterator
runClaude.ts
import { runClaude } from "@anthropic-ai/claude-code";

// Minimal SDK usage — async iterator of events
for await (const message of runClaude({
  messages: [{ role: "user", content: "List the files in /tmp" }],
  tools: ["BashTool", "FileReadTool"],
})) {
  if (message.type === "text") process.stdout.write(message.text);
  if (message.type === "tool_result") console.log(message.tool, message.output);
}
createSession() — Stateful conversation
createSession.ts
import { createSession } from "@anthropic-ai/claude-code";

// Stateful session — continue a conversation
const session = await createSession({
  tools: ["BashTool", "FileReadTool", "FileEditTool"],
  cwd: process.cwd(),
});

// First turn
await session.send("Read package.json and summarize the project");

// Follow-up in same context
await session.send("Now update the description field");
Subagent spawning — how AgentTool works
subagent.ts
// AgentTool internally does this:
import { streamQuery } from "@anthropic-ai/claude-code/internal";

// Fork parent state for subagent
const subagentEngine = new QueryEngine({
  ...parentEngine.getForkedState(),
  messages: [],  // fresh history
});

// Run headlessly — same 7-phase loop, no terminal output
for await (const event of subagentEngine.query(subagentTask)) {
  results.push(event);
}
// Results injected back as tool_result in parent conversation

How AgentTool Uses the Bridge — Subagent Spawning

When Claude decides to spawn a subagent, the Bridge is the mechanism. The subagent is a full Claude Code instance running headlessly.

1
LLM calls AgentTool
Claude decides to spawn a subagent via AgentTool — generates a tool_use block with the task description.
2
AgentTool calls Bridge
AgentTool invokes the SDK Bridge directly, not the terminal entry point. This creates a headless execution context.
3
New QueryEngine instance
The Bridge creates a fresh QueryEngine with forked state from the parent: inherited tools, separate message history, same permissions.
4
Subagent runs headlessly
The subagent's query() loop runs identically to the parent — 7 phases, tools, permissions — but outputs SDKMessages instead of terminal text.
5
Results returned to parent
When the subagent finishes, its output SDKMessages are formatted as a tool_result and injected into the parent's conversation.
Claude Code is its own subagent runtimeThe same code that powers your interactive terminal also powers every subagent it spawns. There is no separate subagent engine.

SDK API Surface — Key Entry Points

The three functions external callers use to drive Claude Code programmatically.

runClaude()

Main SDK entry point. Takes messages and options, returns an async iterator of SDKMessage objects. Same interface whether running local or remote.

createSession()

Creates a new QueryEngine instance with the given config. The session is stateful — call .send() repeatedly to continue a conversation.

streamQuery()

Low-level function. Wraps query() and yields SDKMessage events as they arrive. Used internally by runClaude() and createSession().

Key Files

entrypoints/sdk/~400 lines

Headless SDK entrypoint — exposes QueryEngine as a programmatic API without terminal UI

bridge/~20KB

Remote session bridge — polls for work, spawns sessions, manages remote capacity

remote/~30KB

WebSocket adapters and remote session manager for distributed execution

coordinator/~15KB

Multi-worker orchestration — coordinates parallel subagent execution