270 lines
9.6 KiB
Markdown
270 lines
9.6 KiB
Markdown
|
|
# Agent SDK — Python
|
||
|
|
|
||
|
|
The Claude Agent SDK provides a higher-level interface for building AI agents with built-in tools, safety features, and agentic capabilities.
|
||
|
|
|
||
|
|
## Installation
|
||
|
|
|
||
|
|
```bash
|
||
|
|
pip install claude-agent-sdk
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Quick Start
|
||
|
|
|
||
|
|
```python
|
||
|
|
import anyio
|
||
|
|
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
|
||
|
|
|
||
|
|
async def main():
|
||
|
|
async for message in query(
|
||
|
|
prompt="Explain this codebase",
|
||
|
|
options=ClaudeAgentOptions(allowed_tools=["Read", "Glob", "Grep"])
|
||
|
|
):
|
||
|
|
if isinstance(message, ResultMessage):
|
||
|
|
print(message.result)
|
||
|
|
|
||
|
|
anyio.run(main)
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Built-in Tools
|
||
|
|
|
||
|
|
| Tool | Description |
|
||
|
|
| --------- | ------------------------------------ |
|
||
|
|
| Read | Read files in the workspace |
|
||
|
|
| Write | Create new files |
|
||
|
|
| Edit | Make precise edits to existing files |
|
||
|
|
| Bash | Execute shell commands |
|
||
|
|
| Glob | Find files by pattern |
|
||
|
|
| Grep | Search files by content |
|
||
|
|
| WebSearch | Search the web for information |
|
||
|
|
| WebFetch | Fetch and analyze web pages |
|
||
|
|
| AskUserQuestion | Ask user clarifying questions |
|
||
|
|
| Agent | Spawn subagents |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Primary Interfaces
|
||
|
|
|
||
|
|
### `query()` — Simple One-Shot Usage
|
||
|
|
|
||
|
|
The `query()` function is the simplest way to run an agent. It returns an async iterator of messages.
|
||
|
|
|
||
|
|
```python
|
||
|
|
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
|
||
|
|
|
||
|
|
async for message in query(
|
||
|
|
prompt="Explain this codebase",
|
||
|
|
options=ClaudeAgentOptions(allowed_tools=["Read", "Glob", "Grep"])
|
||
|
|
):
|
||
|
|
if isinstance(message, ResultMessage):
|
||
|
|
print(message.result)
|
||
|
|
```
|
||
|
|
|
||
|
|
### `ClaudeSDKClient` — Full Control
|
||
|
|
|
||
|
|
`ClaudeSDKClient` provides full control over the agent lifecycle. Use it when you need custom tools, hooks, streaming, or the ability to interrupt execution.
|
||
|
|
|
||
|
|
```python
|
||
|
|
import anyio
|
||
|
|
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions, AssistantMessage, TextBlock
|
||
|
|
|
||
|
|
async def main():
|
||
|
|
options = ClaudeAgentOptions(allowed_tools=["Read", "Glob", "Grep"])
|
||
|
|
async with ClaudeSDKClient(options=options) as client:
|
||
|
|
await client.query("Explain this codebase")
|
||
|
|
async for message in client.receive_response():
|
||
|
|
if isinstance(message, AssistantMessage):
|
||
|
|
for block in message.content:
|
||
|
|
if isinstance(block, TextBlock):
|
||
|
|
print(block.text)
|
||
|
|
|
||
|
|
anyio.run(main)
|
||
|
|
```
|
||
|
|
|
||
|
|
`ClaudeSDKClient` supports:
|
||
|
|
|
||
|
|
- **Context manager** (`async with`) for automatic resource cleanup
|
||
|
|
- **`client.query(prompt)`** to send a prompt to the agent
|
||
|
|
- **`receive_response()`** for streaming messages until completion
|
||
|
|
- **`interrupt()`** to stop agent execution mid-task
|
||
|
|
- **Required for custom tools** (via SDK MCP servers)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Permission System
|
||
|
|
|
||
|
|
```python
|
||
|
|
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
|
||
|
|
|
||
|
|
async for message in query(
|
||
|
|
prompt="Refactor the authentication module",
|
||
|
|
options=ClaudeAgentOptions(
|
||
|
|
allowed_tools=["Read", "Edit", "Write"],
|
||
|
|
permission_mode="acceptEdits" # Auto-accept file edits
|
||
|
|
)
|
||
|
|
):
|
||
|
|
if isinstance(message, ResultMessage):
|
||
|
|
print(message.result)
|
||
|
|
```
|
||
|
|
|
||
|
|
Permission modes:
|
||
|
|
|
||
|
|
- `"default"`: Prompt for dangerous operations
|
||
|
|
- `"plan"`: Planning only, no execution
|
||
|
|
- `"acceptEdits"`: Auto-accept file edits
|
||
|
|
- `"dontAsk"`: Don't prompt (useful for CI/CD)
|
||
|
|
- `"bypassPermissions"`: Skip all prompts (requires `allow_dangerously_skip_permissions=True` in options)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## MCP (Model Context Protocol) Support
|
||
|
|
|
||
|
|
```python
|
||
|
|
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
|
||
|
|
|
||
|
|
async for message in query(
|
||
|
|
prompt="Open example.com and describe what you see",
|
||
|
|
options=ClaudeAgentOptions(
|
||
|
|
mcp_servers={
|
||
|
|
"playwright": {"command": "npx", "args": ["@playwright/mcp@latest"]}
|
||
|
|
}
|
||
|
|
)
|
||
|
|
):
|
||
|
|
if isinstance(message, ResultMessage):
|
||
|
|
print(message.result)
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Hooks
|
||
|
|
|
||
|
|
Customize agent behavior with hooks using callback functions:
|
||
|
|
|
||
|
|
```python
|
||
|
|
from claude_agent_sdk import query, ClaudeAgentOptions, HookMatcher, ResultMessage
|
||
|
|
|
||
|
|
async def log_file_change(input_data, tool_use_id, context):
|
||
|
|
file_path = input_data.get('tool_input', {}).get('file_path', 'unknown')
|
||
|
|
print(f"Modified: {file_path}")
|
||
|
|
return {}
|
||
|
|
|
||
|
|
async for message in query(
|
||
|
|
prompt="Refactor utils.py",
|
||
|
|
options=ClaudeAgentOptions(
|
||
|
|
permission_mode="acceptEdits",
|
||
|
|
hooks={
|
||
|
|
"PostToolUse": [HookMatcher(matcher="Edit|Write", hooks=[log_file_change])]
|
||
|
|
}
|
||
|
|
)
|
||
|
|
):
|
||
|
|
if isinstance(message, ResultMessage):
|
||
|
|
print(message.result)
|
||
|
|
```
|
||
|
|
|
||
|
|
Available hook events: `PreToolUse`, `PostToolUse`, `PostToolUseFailure`, `Notification`, `UserPromptSubmit`, `SessionStart`, `SessionEnd`, `Stop`, `SubagentStart`, `SubagentStop`, `PreCompact`, `PermissionRequest`, `Setup`, `TeammateIdle`, `TaskCompleted`, `ConfigChange`
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Common Options
|
||
|
|
|
||
|
|
`query()` takes a top-level `prompt` (string) and an `options` object (`ClaudeAgentOptions`):
|
||
|
|
|
||
|
|
```python
|
||
|
|
async for message in query(prompt="...", options=ClaudeAgentOptions(...)):
|
||
|
|
```
|
||
|
|
|
||
|
|
| Option | Type | Description |
|
||
|
|
| ----------------------------------- | ------ | -------------------------------------------------------------------------- |
|
||
|
|
| `cwd` | string | Working directory for file operations |
|
||
|
|
| `allowed_tools` | list | Tools the agent can use (e.g., `["Read", "Edit", "Bash"]`) |
|
||
|
|
| `tools` | list | Built-in tools to make available (restricts the default set) |
|
||
|
|
| `disallowed_tools` | list | Tools to explicitly disallow |
|
||
|
|
| `permission_mode` | string | How to handle permission prompts |
|
||
|
|
| `allow_dangerously_skip_permissions`| bool | Must be `True` to use `permission_mode="bypassPermissions"` |
|
||
|
|
| `mcp_servers` | dict | MCP servers to connect to |
|
||
|
|
| `hooks` | dict | Hooks for customizing behavior |
|
||
|
|
| `system_prompt` | string | Custom system prompt |
|
||
|
|
| `max_turns` | int | Maximum agent turns before stopping |
|
||
|
|
| `max_budget_usd` | float | Maximum budget in USD for the query |
|
||
|
|
| `model` | string | Model ID (default: determined by CLI) |
|
||
|
|
| `agents` | dict | Subagent definitions (`dict[str, AgentDefinition]`) |
|
||
|
|
| `output_format` | dict | Structured output schema |
|
||
|
|
| `thinking` | dict | Thinking/reasoning control |
|
||
|
|
| `betas` | list | Beta features to enable (e.g., `["context-1m-2025-08-07"]`) |
|
||
|
|
| `setting_sources` | list | Settings to load (e.g., `["project"]`). Default: none (no CLAUDE.md files) |
|
||
|
|
| `env` | dict | Environment variables to set for the session |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Message Types
|
||
|
|
|
||
|
|
```python
|
||
|
|
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage, SystemMessage
|
||
|
|
|
||
|
|
async for message in query(
|
||
|
|
prompt="Find TODO comments",
|
||
|
|
options=ClaudeAgentOptions(allowed_tools=["Read", "Glob", "Grep"])
|
||
|
|
):
|
||
|
|
if isinstance(message, ResultMessage):
|
||
|
|
print(message.result)
|
||
|
|
elif isinstance(message, SystemMessage) and message.subtype == "init":
|
||
|
|
session_id = message.session_id # Capture for resuming later
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Subagents
|
||
|
|
|
||
|
|
```python
|
||
|
|
from claude_agent_sdk import query, ClaudeAgentOptions, AgentDefinition, ResultMessage
|
||
|
|
|
||
|
|
async for message in query(
|
||
|
|
prompt="Use the code-reviewer agent to review this codebase",
|
||
|
|
options=ClaudeAgentOptions(
|
||
|
|
allowed_tools=["Read", "Glob", "Grep", "Agent"],
|
||
|
|
agents={
|
||
|
|
"code-reviewer": AgentDefinition(
|
||
|
|
description="Expert code reviewer for quality and security reviews.",
|
||
|
|
prompt="Analyze code quality and suggest improvements.",
|
||
|
|
tools=["Read", "Glob", "Grep"]
|
||
|
|
)
|
||
|
|
}
|
||
|
|
)
|
||
|
|
):
|
||
|
|
if isinstance(message, ResultMessage):
|
||
|
|
print(message.result)
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Error Handling
|
||
|
|
|
||
|
|
```python
|
||
|
|
from claude_agent_sdk import query, ClaudeAgentOptions, CLINotFoundError, CLIConnectionError, ResultMessage
|
||
|
|
|
||
|
|
try:
|
||
|
|
async for message in query(
|
||
|
|
prompt="...",
|
||
|
|
options=ClaudeAgentOptions(allowed_tools=["Read"])
|
||
|
|
):
|
||
|
|
if isinstance(message, ResultMessage):
|
||
|
|
print(message.result)
|
||
|
|
except CLINotFoundError:
|
||
|
|
print("Claude Code CLI not found. Install with: pip install claude-agent-sdk")
|
||
|
|
except CLIConnectionError as e:
|
||
|
|
print(f"Connection error: {e}")
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Best Practices
|
||
|
|
|
||
|
|
1. **Always specify allowed_tools** — Explicitly list which tools the agent can use
|
||
|
|
2. **Set working directory** — Always specify `cwd` for file operations
|
||
|
|
3. **Use appropriate permission modes** — Start with `"default"` and only escalate when needed
|
||
|
|
4. **Handle all message types** — Check for `ResultMessage` to get agent output
|
||
|
|
5. **Limit max_turns** — Prevent runaway agents with reasonable limits
|