Claude Agent SDK Beginner Guide: Build a Read-Only Python Agent¶
For / Key Points
For: Python developers delegating file investigation and tool use to Claude
Key Points:
- The current Python package is
claude-agent-sdk, imported asclaude_agent_sdk - Use
query()for one run andClaudeSDKClientfor multi-turn sessions and custom tools - Begin with Read, Grep, and Glob, then add mutation rights deliberately
Claude Agent SDK embeds the agent loop, file tools, permissions, and sessions derived from Claude Code into an application. The Python package supports Python 3.10+ and bundles the required Claude Code CLI, so a separate CLI installation is not mandatory.1
Older examples using anthropic-agent-sdk, AgentSDK, or agent.run() do not match the current Python API.
1. Create an environment¶
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade claude-agent-sdk anyio
On Windows PowerShell, activate it with:
.venv\Scripts\Activate.ps1
For direct Claude API authentication, provide ANTHROPIC_API_KEY from secret management. Do not place the key in source code, committed .env files, or logs.
2. Run a minimal query¶
query() returns an asynchronous message stream.
import anyio
from claude_agent_sdk import ResultMessage, query
async def main() -> None:
async for message in query(prompt="What is 2 + 2?"):
if isinstance(message, ResultMessage):
print(message.result)
anyio.run(main)
The stream includes initialization, assistant output, tool events, and the final result. The last ResultMessage exposes the result, usage, cost, and session ID.1
3. Expand to read-only code investigation¶
Do not grant shell or write access in the first practical run.
import anyio
from claude_agent_sdk import ClaudeAgentOptions, ResultMessage, query
async def main() -> None:
options = ClaudeAgentOptions(
allowed_tools=["Read", "Grep", "Glob"],
max_turns=6,
)
prompt = """
Investigate authentication in this project.
Using implementation files, configuration, and tests as evidence,
summarize the path from login to session establishment.
Do not modify files.
"""
async for message in query(prompt=prompt, options=options):
if isinstance(message, ResultMessage):
if message.is_error:
raise RuntimeError(message.result or "Agent run failed")
print(message.result)
print(f"cost_usd={message.total_cost_usd}")
anyio.run(main)
allowed_tools narrows the available toolset. If you add writing or shell tools, availability and automatic approval remain separate concerns controlled by permission_mode or can_use_tool.2
Choose query() or ClaudeSDKClient¶
| API | State | Best fit |
|---|---|---|
query() | Per invocation | One investigation or independent batch item |
ClaudeSDKClient | Multi-turn while open | Conversational UI, steering, custom tools, continued sessions |
Use query() when a run behaves like a function. Use ClaudeSDKClient for follow-up input in the same context, mid-run interaction, or in-process SDK MCP tools.2
Custom tool design¶
Define a Python function with @tool and expose it through create_sdk_mcp_server as an in-process MCP server.
- Separate read and write operations
- Use typed target IDs and actions rather than one free-text input
- Require application approval for sends, deletion, and publishing
- Log input, outcome, and failure
- Do not convert a tool exception into a success message
The SDK supplies the loop; the application still owns external authorization and side effects.
Production checklist¶
Limit the working directory¶
Built-in tools act on the process filesystem. Use a dedicated worktree, container, or temporary directory rather than a broad home directory.
Set limits¶
Bound turns, timeout, API budget, and concurrency. Store ResultMessage usage and total_cost_usd, including failed runs.
Validate outputs¶
Do not feed final prose directly into a mutation step. Apply JSON Schema, row reconciliation, static analysis, or tests appropriate to the deliverable.
Separate secrets¶
Keep API keys out of prompts and files. Inject narrow credentials only inside the tool that needs them, and redact authorization headers and personal data from logs.
Common errors¶
No matching distribution found¶
Check Python and the package name.
python --version
python -m pip install --upgrade claude-agent-sdk
Old imports fail¶
Use from claude_agent_sdk import .... The migration from the former Claude Code SDK includes breaking class and message changes; consult the current README.1
A tool waits for approval¶
An allowlist and approval mode are separate. Keep the toolset small and implement can_use_tool or hooks before removing write confirmations.
Summary¶
- Install
claude-agent-sdkand import fromclaude_agent_sdk - Use
query()for one run andClaudeSDKClientfor continued interaction or custom tools - Start with Read, Grep, and Glob; approve Bash and writes separately
- Bound filesystem scope, turns, cost, and side effects in the application
Few lines of code are a useful on-ramp, not a safety property. A minimal agent also needs narrow tools, validated results, and a reliable stop path.