Python SDK for Claude Code enabling developers to build AI-powered applications and agents with support for custom tools, hooks, and bidirectional interactive conversations
Python SDK for interacting with Claude Code, enabling AI-powered applications and agents with custom tools, bidirectional conversations, and comprehensive control mechanisms.
claude-agent-sdkpip install claude-agent-sdkimport anyio
from claude_agent_sdk import query, ClaudeAgentOptions
async def main():
options = ClaudeAgentOptions(
allowed_tools=["Read", "Write", "Bash"],
permission_mode="acceptEdits",
cwd="/path/to/project"
)
async for message in query(prompt="What files are here?", options=options):
print(message)
anyio.run(main)For interactive conversations: Use ClaudeSDKClient for multi-turn dialogs with context.
| Interface | Use Case | State | Follow-ups |
|---|---|---|---|
query() | One-shot tasks, automation | Stateless | No |
ClaudeSDKClient | Chat, interactive sessions | Stateful | Yes |
# Core interfaces
from claude_agent_sdk import query, ClaudeSDKClient, ClaudeAgentOptions
# Message handling
from claude_agent_sdk import AssistantMessage, UserMessage, TextBlock, ResultMessage
# Error handling
from claude_agent_sdk import ClaudeSDKErrorClaudeAgentOptions(
# Tools
allowed_tools=["Read", "Write", "Bash", "Edit"], # Tools Claude can use
disallowed_tools=[], # Explicitly blocked tools
# Permissions
permission_mode="acceptEdits", # "default" | "acceptEdits" | "plan" | "bypassPermissions"
# Model
model="sonnet", # "haiku" (fast/cheap) | "sonnet" (balanced) | "opus" (powerful)
max_turns=10, # Limit conversation length
max_budget_usd=1.0, # Cost limit
# Environment
cwd="/path/to/project", # Working directory
# MCP Servers (custom tools)
mcp_servers={...}, # Custom tool servers
)Note: MCP tools use format mcp__<server>__<tool> (e.g., "mcp__calculator__add")
# Receiving messages
async for message in query(prompt="..."):
if isinstance(message, AssistantMessage): # Claude's response
for block in message.content:
if isinstance(block, TextBlock): # Text content
print(block.text)
elif isinstance(block, ToolUseBlock): # Tool invocation
print(f"Using {block.name}")
elif isinstance(message, ResultMessage): # Final result with metrics
print(f"Cost: ${message.total_cost_usd}")
print(f"Duration: {message.duration_ms}ms")┌─────────────────────────────────────────────────────────┐
│ Application Code │
├─────────────────────────────────────────────────────────┤
│ Interface Layer │
│ ┌──────────────┐ ┌───────────────────────────┐ │
│ │ query() │ │ ClaudeSDKClient │ │
│ │ (stateless) │ │ (stateful, interactive) │ │
│ └──────────────┘ └───────────────────────────┘ │
├─────────────────────────────────────────────────────────┤
│ Message System (UserMessage, AssistantMessage, etc.) │
├─────────────────────────────────────────────────────────┤
│ Control Mechanisms │
│ • Permissions • Hooks • MCP Servers • Sandbox │
├─────────────────────────────────────────────────────────┤
│ Transport Layer (SubprocessCLITransport) │
├─────────────────────────────────────────────────────────┤
│ Claude Code CLI (bundled) │
└─────────────────────────────────────────────────────────┘options = ClaudeAgentOptions(
allowed_tools=["Read", "Write", "Edit"],
permission_mode="acceptEdits",
cwd="/project"
)
async for msg in query("Refactor the auth module", options=options):
print(msg)options = ClaudeAgentOptions(
allowed_tools=["Read", "Grep", "Glob"],
model="sonnet"
)
async for msg in query("Find security issues", options=options):
print(msg)async with ClaudeSDKClient(options=options) as client:
await client.query("What files are here?")
async for msg in client.receive_response():
print(msg)
await client.query("Tell me about main.py") # Has context
async for msg in client.receive_response():
print(msg)| Category | Tools | Use Case |
|---|---|---|
| File I/O | Read, Write, Edit, MultiEdit | File operations |
| Search | Grep, Glob | Finding files and patterns |
| Execution | Bash | Running commands |
| Web | WebFetch, WebSearch | Internet access |
| Interaction | AskUserQuestion, TodoWrite | User communication |
| Agents | Task | Sub-agent delegation |
| Custom | mcp__<server>__<tool> | MCP server tools |
| Mode | Behavior | Use Case |
|---|---|---|
default | Prompts for dangerous tools | Interactive, human oversight |
acceptEdits | Auto-approve file edits | Automation with file changes |
plan | Planning mode | Design/architecture phase |
bypassPermissions | Allow all tools | Controlled environments only |
| Model | Speed | Cost | Capability | Best For |
|---|---|---|---|---|
haiku | Fast | Low | Basic | Simple tasks, batch processing |
sonnet | Medium | Medium | Balanced | General purpose (default) |
opus | Slow | High | Advanced | Complex reasoning, difficult tasks |
async def get_text(prompt: str) -> str:
texts = []
async for msg in query(prompt=prompt):
if isinstance(msg, AssistantMessage):
for block in msg.content:
if isinstance(block, TextBlock):
texts.append(block.text)
return " ".join(texts)from claude_agent_sdk import ClaudeSDKError, CLINotFoundError
try:
async for msg in query(prompt="..."):
print(msg)
except CLINotFoundError:
print("Install: pip install claude-code-cli")
except ClaudeSDKError as e:
print(f"Error: {e}")async def permission_callback(tool_name, tool_input, context):
if tool_name == "Bash" and "rm -rf" in tool_input.get("command", ""):
return PermissionResultDeny(behavior="deny", message="Blocked", interrupt=True)
return PermissionResultAllow(behavior="allow")
options = ClaudeAgentOptions(can_use_tool=permission_callback)async for msg in query(prompt="...", options=ClaudeAgentOptions(max_budget_usd=1.0)):
if isinstance(msg, ResultMessage):
print(f"Cost: ${msg.total_cost_usd:.4f}")
print(f"Tokens: {msg.usage}")| Issue | Cause | Solution |
|---|---|---|
| "Claude Code not found" | CLI not installed | Install SDK or specify cli_path |
| "Tool not allowed" | Not in allowed_tools | Add tool name to list |
| Permission prompts | permission_mode="default" | Use "acceptEdits" or callback |
| High costs | No limits set | Set max_budget_usd and max_turns |
| Query hangs | Long operation | Add max_turns or use timeout |
| Context not preserved | Using query() | Use ClaudeSDKClient for multi-turn |
from claude_agent_sdk import __version__, __cli_version__
print(f"SDK version: {__version__}") # 0.1.29
print(f"CLI version: {__cli_version__}") # 2.1.31For comprehensive API documentation and detailed examples, explore the guides, examples, and reference sections linked above.
Install with Tessl CLI
npx tessl i tessl/pypi-claude-agent-sdk