.claude/skills/claude-agent-sdk-python/SKILL.md
Build and test Python applications using the Claude Agent SDK. Use when creating agent applications, custom MCP tools, permission handlers, lifecycle hooks, or multi-turn conversations. Covers query(), ClaudeSDKClient, @tool decorator, create_sdk_mcp_server(), hooks, permissions, and independent app testing patterns.
npx skillsauth add kivo360/omoios claude-agent-sdk-pythonInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Build production-ready agent applications with the Claude Agent SDK for Python.
pip install claude-agent-sdk
Requires Python 3.10+ and bundled Claude CLI v2.0.60+.
| API | Use Case |
|-----|----------|
| query() | One-shot or simple multi-turn queries |
| ClaudeSDKClient | Interactive streaming, bidirectional control |
| @tool + create_sdk_mcp_server() | Custom in-process tools |
| can_use_tool callback | Fine-grained permission control |
| hooks | Lifecycle event interception |
import anyio
from claude_agent_sdk import query, AssistantMessage, TextBlock, ResultMessage
async def main():
async for msg in query(prompt="Explain Python decorators"):
if isinstance(msg, AssistantMessage):
for block in msg.content:
if isinstance(block, TextBlock):
print(block.text)
elif isinstance(msg, ResultMessage):
print(f"Cost: ${msg.total_cost_usd:.4f}")
anyio.run(main)
import anyio
from claude_agent_sdk import (
ClaudeSDKClient,
ClaudeAgentOptions,
AssistantMessage,
TextBlock,
ResultMessage,
)
async def main():
options = ClaudeAgentOptions(
system_prompt="You are a helpful assistant",
allowed_tools=["Read", "Write", "Bash"],
permission_mode="acceptEdits",
max_turns=10,
)
async with ClaudeSDKClient(options=options) as client:
await client.query("Analyze main.py")
async for msg in client.receive_response():
if isinstance(msg, AssistantMessage):
for block in msg.content:
if isinstance(block, TextBlock):
print(block.text)
elif isinstance(msg, ResultMessage):
print(f"Done. Cost: ${msg.total_cost_usd:.4f}")
anyio.run(main)
from typing import Any
from claude_agent_sdk import tool, create_sdk_mcp_server, ClaudeAgentOptions
@tool("add", "Add two numbers", {"a": float, "b": float})
async def add(args: dict[str, Any]) -> dict[str, Any]:
result = args["a"] + args["b"]
return {"content": [{"type": "text", "text": f"Result: {result}"}]}
@tool("divide", "Divide two numbers", {"a": float, "b": float})
async def divide(args: dict[str, Any]) -> dict[str, Any]:
if args["b"] == 0:
return {
"content": [{"type": "text", "text": "Error: Division by zero"}],
"is_error": True
}
return {"content": [{"type": "text", "text": f"Result: {args['a'] / args['b']}"}]}
calculator = create_sdk_mcp_server(
name="calculator",
version="1.0.0",
tools=[add, divide]
)
options = ClaudeAgentOptions(
mcp_servers={"calc": calculator},
allowed_tools=["mcp__calc__add", "mcp__calc__divide"],
permission_mode="acceptEdits",
)
ClaudeAgentOptions(
# Model
model="claude-sonnet-4-20250514",
fallback_model=None,
# Prompts
system_prompt="You are a helpful assistant",
# Limits
max_turns=10,
max_budget_usd=1.00,
max_thinking_tokens=8000,
# Environment
cwd="/path/to/project",
env={"CUSTOM_VAR": "value"},
# Tools
tools=["Read", "Write", "Bash"], # or {"type": "preset", "preset": "claude_code"}
allowed_tools=["Read", "Write"], # whitelist
disallowed_tools=["WebFetch"], # blacklist
mcp_servers={"name": config}, # custom tools
# Permissions
permission_mode="acceptEdits", # default, acceptEdits, plan, bypassPermissions
can_use_tool=my_permission_callback,
# Sessions
continue_conversation=False,
resume="session-id",
fork_session=False,
# Hooks
hooks={"PreToolUse": [HookMatcher(matcher="*", hooks=[my_hook])]},
)
| Mode | Behavior |
|------|----------|
| "default" | Prompt for all actions |
| "acceptEdits" | Auto-approve file edits |
| "plan" | Planning mode (no execution) |
| "bypassPermissions" | Auto-approve all (use with caution) |
For detailed examples of:
Use scripts/run_agent_app.py to test agent applications in isolation:
# Run a simple agent app
python scripts/run_agent_app.py path/to/app.py
# Run with custom options
python scripts/run_agent_app.py path/to/app.py --cwd /project --max-turns 5
Use scripts/create_agent_project.py to scaffold new agent projects:
# Create a basic agent project
python scripts/create_agent_project.py my_agent --template basic
# Create with custom tools
python scripts/create_agent_project.py my_agent --template custom-tools
# Create interactive chat app
python scripts/create_agent_project.py my_agent --template chat
| Type | Description |
|------|-------------|
| AssistantMessage | Claude's responses (text, thinking, tool use) |
| UserMessage | User input or tool results |
| ResultMessage | Session summary (always last) |
| SystemMessage | System events |
from claude_agent_sdk import TextBlock, ThinkingBlock, ToolUseBlock, ToolResultBlock
# In AssistantMessage.content
for block in msg.content:
if isinstance(block, TextBlock):
print(block.text)
elif isinstance(block, ThinkingBlock):
print(f"Thinking: {block.thinking}")
elif isinstance(block, ToolUseBlock):
print(f"Tool: {block.name}, Input: {block.input}")
from claude_agent_sdk import (
ClaudeSDKError,
CLINotFoundError,
ProcessError,
SDKJSONDecodeError,
)
try:
async with ClaudeSDKClient(options) as client:
await client.query("Do something")
async for msg in client.receive_response():
process(msg)
except CLINotFoundError:
print("Claude CLI not found. Install from https://claude.ai")
except ProcessError as e:
print(f"CLI failed with exit code: {e.exit_code}")
except SDKJSONDecodeError:
print("Failed to parse CLI response")
ClaudeSDKClient to ensure cleanupmax_budget_usd to prevent runaway costspermission_mode="acceptEdits" for file operations without promptsis_error: True from custom tools on failuredevelopment
Spec-driven development workflow for turning feature ideas into structured PRDs, requirements, designs, tickets, and tasks. Uses a state machine approach with EXPLORE → REQUIREMENTS → DESIGN → TASKS → SYNC phases. Each phase has validation gates, checkpointing, and session transcript support for cross-sandbox resumption.
development
Generate comprehensive tests including unit, integration, and property-based tests
development
Spec-driven development workflow for turning feature ideas into structured PRDs, requirements, designs, tickets, and tasks. Uses a state machine approach with EXPLORE → REQUIREMENTS → DESIGN → TASKS → SYNC phases. Each phase has validation gates, checkpointing, and session transcript support for cross-sandbox resumption.
development
Plan safe refactoring with dependency analysis, impact assessment, and rollback strategies