Agent SDK
- Entity ID:
ent-20260410-5f02e900dfbd - Type:
service - Scope:
shared - Status:
active - Aliases: SDK, programmatic API, Claude Code SDK
Description
The programmatic API for embedding Claude Code as a library rather than a CLI. Located at src/entrypoints/sdk/ with the public surface exported from src/entrypoints/agentSdkTypes.ts. The SDK exposes the same QueryEngine, tool system, and MCP integration as the CLI, but communicates via typed AsyncGenerator<SDKMessage> streams instead of a terminal UI. A control protocol enables out-of-band operations (permission decisions, MCP management, configuration changes) without blocking the message stream.
Public API
One-shot convenience
unstable_v2_prompt(message: string, options: SDKSessionOptions): Promise<SDKResultMessage>
Send a single prompt and get the result. The simplest way to use Claude Code programmatically.
Persistent sessions
unstable_v2_createSession(options: SDKSessionOptions): SDKSession
unstable_v2_resumeSession(sessionId: string, options: SDKSessionOptions): SDKSession
Create or resume multi-turn sessions with full state persistence. The session object exposes the message stream as an async generator.
Session management
listSessions(options?): Promise<SDKSessionInfo[]>
getSessionInfo(sessionId, options?): Promise<SDKSessionInfo | undefined>
getSessionMessages(sessionId, options?): Promise<SessionMessage[]>
renameSession(sessionId, title, options?): Promise<void>
tagSession(sessionId, tag, options?): Promise<void>
forkSession(sessionId, options?): Promise<ForkSessionResult>
Read, rename, tag, and fork existing sessions. getSessionMessages reads the JSONL transcript directly with pagination support.
Tool registration
tool<Schema>(name, description, inputSchema, handler, extras?): SdkMcpToolDefinition<Schema>
createSdkMcpServer(options: { name, version?, tools? }): McpSdkServerConfigWithInstance
Register custom tools using Zod schemas for input validation. Tools run as in-process MCP servers — no subprocess overhead. The alwaysLoad flag ensures a tool is always available; searchHint aids tool discovery.
Legacy query API
query(params: { prompt, options? }): Query | InternalQuery
Lower-level access to the QueryEngine. Returns a query object with the message stream.
Internal APIs (daemon/scheduler)
watchScheduledTasks(opts): ScheduledTasksHandle // @internal
connectRemoteControl(opts): Promise<RemoteControlHandle | null> // @internal
Used by the daemon and Claude Code Remote (CCR) for scheduled task execution and remote control.
Session options
SDKSessionOptions configures everything for a session:
| Option | Purpose |
|---|---|
model |
Model identifier (required) |
cwd |
Working directory |
customSystemPrompt / appendSystemPrompt |
System prompt customization |
tools |
Array of tool names to enable |
agents |
Record of agent definitions |
maxTurns / maxBudgetUsd |
Execution limits |
jsonSchema |
Structured output constraint |
thinkingConfig |
adaptive / enabled (with budget) / disabled |
permissionMode |
default / acceptEdits / bypassPermissions / plan / dontAsk |
hooks |
Record of hook event → callback matchers |
sdkMcpServers |
MCP server configurations |
outputStyle |
Output formatting preference |
Message types
The SDK communicates via a stream of typed SDKMessage objects (sdk/coreSchemas.ts:1854). The major categories:
Conversation:
- SDKUserMessage — user input
- SDKAssistantMessage — API response (may include error field)
- SDKSystemMessage (subtype 'init') — initialization with tools, models, agents
Streaming:
- SDKPartialAssistantMessage — raw streaming events from the API
- SDKStreamlinedTextMessage — thinking/tool blocks removed for display
Tool execution:
- SDKToolProgressMessage — elapsed time, task ID tracking
- SDKToolUseSummaryMessage — cumulative tool call summary
Status and control:
- SDKStatusMessage — compaction/status updates
- SDKCompactBoundaryMessage — history compaction markers
- SDKAPIRetryMessage — retry events with attempt count
- SDKSessionStateChangedMessage — idle/running/requires_action
- SDKRateLimitEventSchema — rate limit info with utilization
Results:
- SDKResultMessage — terminal message, union of:
- Success: duration, usage, cost, model usage breakdown, structured output
- Error subtypes: error_during_execution, error_max_turns, error_max_budget_usd, error_max_structured_output_retries
Hooks:
- SDKHookStartedMessage, SDKHookProgressMessage, SDKHookResponseMessage
Tasks:
- SDKTaskNotificationMessage, SDKTaskStartedMessage, SDKTaskProgressMessage
Control protocol
The control protocol (sdk/controlSchemas.ts) enables out-of-band communication between the SDK consumer and the CLI process:
SDK Consumer → CLI: { type: 'control_request', request_id, request }
CLI → SDK Consumer: { type: 'control_response', response: { subtype, request_id, response? } }
23 control request types:
| Category | Requests |
|---|---|
| Lifecycle | initialize, interrupt |
| Permissions | can_use_tool, set_permission_mode |
| Model | set_model, set_max_thinking_tokens |
| MCP | mcp_status, mcp_message, mcp_set_servers, mcp_reconnect, mcp_toggle |
| Context | get_context_usage, rewind_files, cancel_async_message, seed_read_state |
| Hooks | hook_callback |
| Config | apply_flag_settings, get_settings, reload_plugins |
| Tasks | stop_task |
| MCP auth | elicitation |
The initialize request configures hooks, MCP servers, agents, schemas, and prompts. The response returns available commands, agents, models, account info, output styles, and PID.
Hook system
The SDK supports 27 hook events:
PreToolUse, PostToolUse, PostToolUseFailure, Notification,
UserPromptSubmit, SessionStart, SessionEnd, Stop, StopFailure,
SubagentStart, SubagentStop, PreCompact, PostCompact,
PermissionRequest, PermissionDenied, Setup, TeammateIdle,
TaskCreated, TaskCompleted, Elicitation, ElicitationResult,
ConfigChange, WorktreeCreate, WorktreeRemove,
InstructionsLoaded, CwdChanged, FileChanged
Hooks fire with structured input (containing session_id, transcript_path, cwd, tool_name, tool_input) and return event-specific output. In the SDK, hooks execute as in-process callbacks routed via the control protocol — no subprocess spawning like in the CLI.
How it differs from the CLI
| Aspect | CLI | SDK |
|---|---|---|
| Communication | Terminal UI (Ink/React) | AsyncGenerator<SDKMessage> stream |
| Initialization | Auto-load config, trust dialog, plugin loading | Explicit SDKSessionOptions + control protocol initialize |
| Permissions | Interactive Ink prompts | Control protocol can_use_tool or hook-based |
| Tool registration | From settings.json + MCP config | tool() + createSdkMcpServer() (in-process) |
| Session management | JSONL files + interactive browser | Programmatic listSessions / getSessionMessages |
| Configuration | Multi-layer (user/project/local/policy) from disk | Passed explicitly in session options |
| Output | Rendered terminal UI | Typed message stream |
| Telemetry | Eager initialization | Deferred until explicit initializeTelemetryAfterTrust() |
Available in SDK but not CLI:
- Programmatic hook registration via control protocol
- In-process tool execution (MCP SDK servers, no subprocess)
- Explicit session/message/config management functions
- Remote daemon integration (connectRemoteControl)
- Task scheduling (watchScheduledTasks)
Available in CLI but not SDK:
- Interactive UI, file diff visualization, progress bars
- Auto-interactive permission prompts
- Command palette / slash commands
- Plugin loading from --plugin-dir
- Session browser UI
- LSP/editor integration
Agent definitions
The SDK supports custom agent definitions:
{
description: string, // When to use this agent
tools?: string[], // Inherit from parent if omitted
disallowedTools?: string[],
prompt: string, // System prompt
model?: string, // 'sonnet' | 'opus' | model ID | 'inherit'
mcpServers?: (string | record<string, McpServerConfig>)[],
skills?: string[],
initialPrompt?: string, // Auto-submitted first turn
maxTurns?: number,
background?: boolean, // Fire-and-forget
memory?: 'user' | 'project' | 'local',
effort?: 'low' | 'medium' | 'high' | 'max',
permissionMode?: PermissionMode
}
What depends on it
- QueryEngine — the SDK wraps QueryEngine the same way the CLI does
- Tool system — SDK-registered tools become MCP SDK servers internally
- MCP subsystem — SDK manages MCP connections via control protocol
- Agent lifecycle — SDK sessions spawn agents through the same AgentTool
- Daemon/remote — uses SDK internally for scheduled tasks and remote control
Design trade-offs
| Decision | Trade-off |
|---|---|
| AsyncGenerator for messages | Natural streaming, but consumers must handle all message types (27+) |
| Control protocol for out-of-band ops | Clean separation from message stream, but adds roundtrip latency for permission decisions |
| In-process MCP servers for tools | Zero subprocess overhead, but tools share the process — a crash affects everything |
unstable_v2_* prefix |
Signals API instability, but may deter adoption |
| Explicit config (no auto-loading) | Full control for embedders, but more boilerplate than CLI's auto-discovery |
| Zod schemas for type safety | Strong validation, but 1890-line schema file is a maintenance burden |
Key claims
- Same QueryEngine and tool system as CLI, different communication layer
- In-process MCP SDK servers eliminate subprocess overhead for custom tools
- Control protocol enables 23 out-of-band operations without blocking the message stream
- 27 hook events provide fine-grained lifecycle control
- Session persistence uses the same JSONL format as CLI sessions
Relations
rel-sdk-entrypoint: entrypoint-system --[provides]--> agent-sdkrel-sdk-query: agent-sdk --[wraps]--> QueryEnginerel-sdk-tools: agent-sdk --[registers]--> tool-system (via MCP SDK servers)rel-sdk-control: agent-sdk --[exposes]--> control protocol
Sources
Source code at src/entrypoints/agentSdkTypes.ts, src/entrypoints/sdk/coreSchemas.ts, src/entrypoints/sdk/controlSchemas.ts