claude-agent-sdk
Original:🇺🇸 English
Translated
This skill should be used when the user asks to "build an AI agent with Claude", "use the Claude Agent SDK", "integrate claude-agent-sdk into a project", "set up an autonomous agent with tools", or needs guidance on the Anthropic Claude Agent SDK best practices for Python and TypeScript.
2installs
Added on
NPX Install
npx skill4agent add the-perfect-developer/the-perfect-opencode claude-agent-sdkTags
Translated version includes tags in frontmatterSKILL.md Content
View Translation Comparison →Claude Agent SDK
Provides patterns and best practices for building production AI agents using the Claude Agent SDK (Python: , TypeScript: ).
claude-agent-sdk@anthropic-ai/claude-agent-sdkInstallation
bash
# TypeScript
npm install @anthropic-ai/claude-agent-sdk
# Python (uv — recommended)
uv add claude-agent-sdk
# Python (pip)
pip install claude-agent-sdkSet the API key before running any agent:
bash
export ANTHROPIC_API_KEY=your-api-keyThird-party providers are also supported: set , , or alongside the respective cloud credentials.
CLAUDE_CODE_USE_BEDROCK=1CLAUDE_CODE_USE_VERTEX=1CLAUDE_CODE_USE_FOUNDRY=1Core Pattern: The query()
Function
query()Every agent is built around , which returns an async iterator of streamed messages:
query()python
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions
async def main():
async for message in query(
prompt="Find and fix the bug in auth.py",
options=ClaudeAgentOptions(
allowed_tools=["Read", "Edit", "Glob"],
permission_mode="acceptEdits",
),
):
if hasattr(message, "result"):
print(message.result)
asyncio.run(main())typescript
import { query } from "@anthropic-ai/claude-agent-sdk";
for await (const message of query({
prompt: "Find and fix the bug in auth.py",
options: { allowedTools: ["Read", "Edit", "Glob"], permissionMode: "acceptEdits" }
})) {
if ("result" in message) console.log(message.result);
}The loop ends when Claude finishes or hits an error. The SDK handles tool execution, context management, and retries internally.
Built-in Tools
Grant only the tools the agent actually needs — principle of least privilege:
| Tool | Purpose |
|---|---|
| Read any file in the working directory |
| Create new files |
| Make precise edits to existing files |
| Run terminal commands, scripts, git operations |
| Find files by pattern ( |
| Search file contents with regex |
| Search the web for current information |
| Fetch and parse web page content |
| Ask the user clarifying questions |
| Spawn subagents (required when using subagents) |
Recommended tool sets by use case
| Use case | Tools |
|---|---|
| Read-only analysis | |
| Code modification | |
| Full automation | |
| Web-augmented | Add |
| Subagent orchestration | Add |
Permission Modes
Set / in options:
permissionModepermission_mode| Mode | Behavior | Best for |
|---|---|---|
| Delegates unresolved requests to | Custom approval flows |
| Auto-approves file edits and filesystem ops | Trusted dev workflows |
| Runs all tools without prompts | CI/CD pipelines |
| No tool execution — planning only | Pre-review before changes |
Best practice: use for interactive development; use only in isolated, sandboxed environments. Never use in multi-tenant or user-facing applications.
acceptEditsbypassPermissionsbypassPermissionsPermission mode changes mid-session are supported — start restrictive, loosen after reviewing Claude's plan:
python
q = query(prompt="Refactor auth module", options=ClaudeAgentOptions(permission_mode="plan"))
await q.set_permission_mode("acceptEdits") # Switch after plan is approved
async for message in q:
...Permission evaluation order
- Hooks — run first; can allow, deny, or pass through
- Permission rules — declarative allow/deny in
settings.json - Permission mode — global fallback setting
- callback — runtime user approval (when mode is
canUseTool)default
Session Management
Capture session ID
python
session_id = None
async for message in query(prompt="Analyze auth module", options=ClaudeAgentOptions(...)):
if hasattr(message, "subtype") and message.subtype == "init":
session_id = message.data.get("session_id")typescript
let sessionId: string | undefined;
for await (const message of query({ prompt: "Analyze auth module", options: { ... } })) {
if (message.type === "system" && message.subtype === "init") {
sessionId = message.session_id;
}
}Resume a session
Pass / in options to continue with full prior context:
resumeresumepython
async for message in query(
prompt="Now find all callers of that function",
options=ClaudeAgentOptions(resume=session_id),
):
...Fork a session
Set / to branch without modifying the original:
fork_session=TrueforkSession: truepython
# Explore a different approach without losing the original session
async for message in query(
prompt="Redesign this as GraphQL instead",
options=ClaudeAgentOptions(resume=session_id, fork_session=True),
):
...Forking preserves the original session; both branches can be resumed independently.
MCP Integration
Connect external services through the Model Context Protocol:
python
options = ClaudeAgentOptions(
mcp_servers={
"playwright": {"command": "npx", "args": ["@playwright/mcp@latest"]}
}
)MCP tool names follow the pattern . List them explicitly in to restrict access:
mcp__{server_name}__{tool_name}allowed_toolspython
allowed_tools=["mcp__playwright__browser_click", "mcp__playwright__browser_screenshot"]Message Handling
Filter the stream for meaningful output. Raw messages include system init and internal state:
python
from claude_agent_sdk import AssistantMessage, ResultMessage
async for message in query(...):
if isinstance(message, AssistantMessage):
for block in message.content:
if hasattr(block, "text"):
print(block.text) # Claude's reasoning
elif hasattr(block, "name"):
print(f"Tool: {block.name}") # Tool being called
elif isinstance(message, ResultMessage):
print(f"Result: {message.subtype}") # "success" or "error"typescript
for await (const message of query({ ... })) {
if (message.type === "assistant") {
for (const block of message.message.content) {
if ("text" in block) console.log(block.text);
else if ("name" in block) console.log(`Tool: ${block.name}`);
}
} else if (message.type === "result") {
console.log(`Result: ${message.subtype}`);
}
}System Prompts
Provide a / to give Claude a persona or project-specific context:
system_promptsystemPromptpython
options = ClaudeAgentOptions(
system_prompt="You are a senior Python developer. Always follow PEP 8. Prefer explicit error handling over bare excepts.",
allowed_tools=["Read", "Edit", "Glob"],
permission_mode="acceptEdits",
)Keep system prompts concise and focused on constraints the LLM doesn't already know.
Best Practices
Tool selection
- Grant only the tools the task requires — no for read-only analysis
Bash - Verify tool set is sufficient before launching; a missing tool causes the agent to stall
- Include in the parent's
Taskwhen defining subagentsallowed_tools
Prompts
- Write prompts as specific task instructions, not open-ended descriptions
- Name files explicitly when they are the target (vs
"Review auth.py")"Review some code" - Use explicit subagent invocation when precision matters: )
"Use the code-reviewer agent to..."
Error handling
- Always handle with
ResultMessage— never assume successsubtype == "error" - Catch exceptions around the loop, not inside it
async for - Avoid bare in hook callbacks; a swallowed exception can silently halt the agent
except
Security
- Never use in production systems with user-supplied prompts
bypassPermissions - Use hooks to block access to sensitive paths (
PreToolUse,.env, secrets)/etc - Restrict subagent tools — subagents do not inherit parent permissions automatically
Sessions
- Store session IDs persistently if the workflow spans multiple process runs
- Fork sessions when exploring alternative approaches to avoid losing a good baseline
- Subagent transcripts persist separately; clean up via setting
cleanupPeriodDays
Performance
- Prefer streaming () over collecting all messages; it shows progress and allows early exit
async for - Use subagents to parallelise independent tasks (security scan + style check simultaneously)
- Use mode first for expensive or irreversible operations — review before executing
plan
Additional Resources
- — Lifecycle hooks: blocking tools, modifying inputs, audit logging
references/hooks.md - — Defining, invoking, and resuming subagents; parallelisation patterns
references/subagents.md - — Building in-process MCP tools with
references/custom-tools.mdcreateSdkMcpServer