Skip to main content

Headless Query Engine & SDK Protocol

The REPL is only one runtime for Claude Code. The same core loop can also run headlessly through QueryEngine, stream structured SDK messages, and expose tools over an MCP server entrypoint.

The Headless Path

🧑‍💻
SDK host / headless caller
📨
Structured stdin or in-process API
⚙️
QueryEngine.submitMessage()
Shared Core
🧠
Prompt assembly
🔧
Tool execution
📡
Streaming model responses
📤
SDKMessage stream

What QueryEngine Owns

QueryEngine is not just a helper around query.ts. It owns the conversation lifecycle for headless and SDK-style sessions:

ResponsibilityWhat Persists Across Turns
Conversation stateMutable messages for the session
Usage accountingTotal usage and API duration tracking
Tool contextRead-file cache, permission denials, orphaned permission handling
Context assemblyMemory prompt loading, plugin cache loading, system prompt parts
Session behaviorModel selection, thinking config, max turns, budgets, replay behavior

One QueryEngine instance corresponds to one conversation. Each submitMessage() call starts another turn inside that same session.

The SDK Transport Is a Control Protocol

When Claude Code runs headlessly over stdio, it does not exchange plain terminal text. StructuredIO reads and writes newline-delimited JSON messages and carries both conversation events and control messages:

Message TypePurpose
initializeBootstraps commands, agents, models, hooks, MCP servers, and output styles
can_use_toolForwards permission requests to the SDK host
interruptCancels the current turn
set_permission_modeChanges how permission checks are handled
set_model / set_max_thinking_tokensAdjusts runtime behavior mid-session
mcp_status / get_context_usageFetches live runtime metadata from the CLI

This is the protocol layer that remote sessions, direct-connect flows, and SDK hosts all build on top of.

Public SDK Surface vs Runtime Implementation

src/entrypoints/agentSdkTypes.ts exports the typed public SDK surface, but it is intentionally a facade. The actual runtime behavior lives deeper in the CLI:

LayerRole
src/entrypoints/agentSdkTypes.tsPublic types and placeholder SDK entrypoints
src/entrypoints/sdk/controlSchemas.tsZod schemas for the control protocol
src/cli/structuredIO.tsNDJSON transport, permission forwarding, session state notifications
src/QueryEngine.tsPersistent conversation engine for headless sessions
src/query.tsShared prompt assembly, streaming, tool loop, and message normalization

Claude Code as an MCP Server

Claude Code also exposes its built-in tools through src/entrypoints/mcp.ts:

🧩
External MCP client
🖧
stdio transport
🔌
Claude Code MCP server
List tools from the built-in registry
Call tools through the normal permission + validation path

The MCP entrypoint reuses the same built-in tool registry, validation, and permission checks. It is not a separate tool implementation stack.

How Other Frameworks Compare

Claude Code's headless path is unusual because it combines a persistent conversation engine with a bidirectional control protocol. The other frameworks expose similar execution primitives, but usually as library APIs first rather than a CLI-native wire protocol.

ConcernClaude CodeOpenAI AgentsGoogle ADKLangChain / LangGraph
Conversation ownerQueryEngine instance per sessionRunner + RunStateRunner + session serviceCompiled graph + optional checkpointer
Primary streaming shapeAsyncGenerator<SDKMessage> over stdio or in-processRunResultStreaming with background loop taskrunner.run_async() events or run_live() live queue/eventsGraph stream/invoke APIs
Resume modelSame QueryEngine continues turns; SDK host can interrupt mid-sessionRunState.to_json() / from_json() resume serialized runsResume via invocation_id and persisted session stateResume from checkpoint/thread state
Host control channelExplicit control messages: initialize, can_use_tool, interrupt, config updatesPython callbacks and state objects; no separate protocol layer in sourceRunner API + RunConfig; live mode uses a separate request queueGraph API parameters such as interrupt_before
Key difference

Claude Code is the most protocol-oriented of the group. OpenAI Agents, ADK, and LangGraph all expose resumable execution, but they primarily hand you library objects and callbacks. Claude Code additionally standardizes the host/runtime conversation as structured messages on the wire.

Key Source Files

FilePurpose
src/QueryEngine.tsPersistent headless conversation engine
src/query.tsShared main query loop and prompt assembly
src/cli/structuredIO.tsStructured stdio transport and control-request handling
src/entrypoints/sdk/controlSchemas.tsZod schemas for the SDK control protocol
src/entrypoints/agentSdkTypes.tsPublic SDK types and facade entrypoints
src/entrypoints/mcp.tsMCP server entrypoint for built-in tools