Claude Agent SDK
When to Use This Skill
Use this skill when:
- You're building with the Agent SDK in Python (one-off queries, persistent agents, multi-turn conversations)
- You need to decide between API patterns (e.g.,
query()vsClaudeSDKClient, streaming vs buffered) - You're implementing features like custom tools, session management, permissions, or hooks
- You're architecting agent applications (error handling, permissions, cost control, session branching)
- You want working code examples from real SDK code
- You need to troubleshoot Agent SDK issues or understand API behavior
How to Answer SDK Questions
The SDK evolves frequently. The patterns below capture stable concepts, but field names and exact APIs may have moved. Verify concrete API details against the live source before quoting them:
- Refresh the doc index when fetching docs. If you need to consult the official docs to answer (i.e. you'll hit step 1 below), run
bash ~/.claude/skills/claude-agent-sdk/scripts/fetch-agent-sdk-urls.shfirst to rewritereferences/agent-sdk-urls.mdfrom Anthropic's currentllms.txt. Skip the refresh for purely conceptual answers or when the existing snapshot is sufficient. - Check official docs for conceptual explanations: fetch from the URLs listed in agent-sdk-urls.md.
- Search the indexed repo for the feature in question:
mcp__claude-context__search_code( path="~/.claude/skills-references/claude-agent-sdk/claude-agent-sdk-python", query="<feature name or concept>" ) - Browse examples for working usage patterns:
Glob(~/.claude/skills-references/claude-agent-sdk/claude-agent-sdk-python/examples/*.py) - Read specific example files when you find a relevant match — these are the source of truth.
Core Concepts
These concepts are architecturally stable — the names and roles don't change, even if exact field names evolve.
ClaudeAgentOptions — The Central Configuration Object
Almost everything in the SDK is configured through ClaudeAgentOptions. Commonly used fields (verify exact names against the source before quoting in answers):
system_prompt— str or preset dict for customizing Claude's behaviorallowed_tools— tool whitelist (e.g.,["Read", "Write", "Bash"])max_turns— limit agent turnsmax_budget_usd— cost cappermission_mode—"default"|"acceptEdits"|"bypassPermissions"model— model overridecan_use_tool— permission callback for dynamic allow/denyhooks— lifecycle hooks dict (PreToolUse,PostToolUse, etc.)mcp_servers— MCP server configuration dictagents— subagent definitions dictcwd— working directory
To verify current fields: search for ClaudeAgentOptions in the SDK source.
Message Types — Processing SDK Responses
The SDK yields typed messages: AssistantMessage, ResultMessage, UserMessage, SystemMessage. Content blocks include TextBlock, ToolUseBlock, ToolResultBlock.
To see the exact types and fields: search the SDK source for these type names, or read examples/quick_start.py and examples/streaming_mode.py for handling patterns.
Implementation Patterns
Each pattern below describes when and why to use an approach. For exact, up-to-date code, follow the "look up" pointer to the corresponding SDK example file.
Pattern 1: One-Off Task — query()
When: Single task, no follow-up needed, fire-and-forget Why: Simplest API — async generator that yields messages, no session management
Key shape:
async for message in query(prompt="...", options=ClaudeAgentOptions(...)):- Yields
AssistantMessage(withTextBlockcontent) andResultMessage(with cost/status) - Without options, Claude has no tools and uses an empty system prompt
Look up: read examples/quick_start.py for basic, options, and tools usage.
Pattern 2: Multi-Turn Conversation — ClaudeSDKClient
When: Multi-turn workflows, context preservation, interactive sessions, interrupts Why: Maintains conversation history, supports streaming, session management
Key shape:
async with ClaudeSDKClient(options=...) as client:- Two-step per turn:
await client.query("...")thenasync for msg in client.receive_response(): - Context is preserved across turns automatically
Look up: read examples/streaming_mode.py for multi-turn, concurrent, interrupt, and error handling patterns.
Pattern 3: Streaming Partial Messages (Real-Time UI)
When: Chat UI, progress display, long-running tasks Why: See tokens and tool calls as they happen, build real-time experiences
Key shape:
- Set
include_partial_messages=TrueinClaudeAgentOptions StreamEventmessages arrive interspersed with regular messages- Known limitations with extended thinking and structured output
Look up: read examples/include_partial_messages.py.
Pattern 4: Custom Tools via MCP (Extend Claude)
When: Claude needs domain-specific capabilities (APIs, business logic)
Why: Type-safe in-process MCP tools with the @tool decorator
Key shape:
@tool(name, description, schema)decorator defines individual toolscreate_sdk_mcp_server(name, version, tools=[...])bundles them into a server- Register via
ClaudeAgentOptions(mcp_servers={"name": server}) - Tool names follow
mcp__<server>__<tool>pattern forallowed_tools
Look up: read examples/mcp_calculator.py for a complete custom tools example.
Pattern 5: Permission Controls (Security)
When: Production agents, untrusted input, approval workflows Why: Prevent unintended tool use with typed allow/deny responses
Key shape:
ClaudeAgentOptions(can_use_tool=callback)with typed returns (PermissionResultAllow/PermissionResultDeny)- Callback signature:
(tool_name, input_data, context) -> Allow | Deny PermissionResultAllow(updated_input=...)can modify tool inputsPermissionResultDeny(message="...")blocks with explanation
Options (most restrictive to most permissive):
allowed_tools=["Read", "Grep"]— Whitelist specific tools onlycan_use_tool=callback— Dynamic allow/deny/modify per tool callpermission_mode="acceptEdits"— Auto-accept file editspermission_mode="bypassPermissions"— Allow everything (dev only)
Look up: read examples/tool_permission_callback.py.
Pattern 6: Hooks (Lifecycle Interception)
When: Logging, validation, security gates, error recovery Why: Intercept agent behavior at key lifecycle points without changing the task prompt
Key shape:
ClaudeAgentOptions(hooks={"PreToolUse": [HookMatcher(matcher="Bash", hooks=[callback])]})- Callback signature:
(input_data: HookInput, tool_use_id, context: HookContext) -> HookJSONOutput - Return
hookSpecificOutputwithpermissionDecision: "allow"/"deny"to control execution
Available hook events:
PreToolUse— Before Claude calls a tool (can allow/deny/modify)PostToolUse— After tool execution (can add context, stop execution)UserPromptSubmit/SessionStart/SessionEnd— Session lifecycleStop— Before agent stops (can add context to continue)
Look up: read examples/hooks.py for PreToolUse, PostToolUse, permission decisions, and stop control.
Pattern 7: Subagents (Task Delegation)
When: Parallel tasks, isolated contexts, specialized domain agents Why: Delegate to focused agents with their own tools, prompts, and models
Key shape:
- Define via
AgentDefinition(description, prompt, tools, model) - Register in
ClaudeAgentOptions(agents={"name": definition}) - Invoke by asking the main agent to "use the agent to..."
Look up: read examples/agents.py for single and multi-agent patterns.
Pattern 8: Cost Control
When: Production budgets, dev experimentation limits Why: Hard-stop agent execution when cost exceeds threshold
Key shape:
ClaudeAgentOptions(max_budget_usd=0.10)ResultMessage.subtype == "error_max_budget_usd"when exceeded- Cost checked after each API call, so final cost may slightly exceed budget
Look up: read examples/max_budget_usd.py.
Pattern 9: System Prompt Customization
When: Custom personas, project-specific instructions, domain assistants Why: Control Claude's behavior and knowledge base
Four methods:
- String — Full replacement:
system_prompt="You are a pirate." - Preset — Use built-in:
system_prompt={"type": "preset", "preset": "claude_code"} - Preset + append — Extend built-in:
system_prompt={"type": "preset", "preset": "claude_code", "append": "Extra instructions."} - Empty (default) — No system prompt, vanilla Claude
Look up: read examples/system_prompt.py.
Decision Guide
Q: Should I use query() or ClaudeSDKClient?
query()if: Single task, no follow-up, simple pipelineClaudeSDKClientif: Multi-turn, conversation history, streaming UI, interrupts, session management
Q: How do I handle approvals and permissions?
- Whitelist (
allowed_tools) — Fast, predictable, best for production - Permission callback (
can_use_tool) — Dynamic logic, can modify inputs - Hooks (
PreToolUse) — Lifecycle-level control, chainable - Permission mode — Global setting for dev vs production
- Combination — Whitelist + callback for defense in depth
Learning Resources
- Official docs: agent-sdk-urls.md lists every Agent SDK (Python) page on code.claude.com with one-line descriptions;
WebFetchany URL for the live content. Regenerate the list viascripts/fetch-agent-sdk-urls.shwhen you need the latest set of pages. - Semantic search — Use
mcp__claude-context__search_codeon the indexed repo for any concept - Browse examples:
Glob(~/.claude/skills-references/claude-agent-sdk/claude-agent-sdk-python/examples/*.py)