Skills/claude-agent-sdk/SKILL.md
Use when working with Anthropic Claude Agent SDK. Provides architecture guidance, implementation patterns, best practices, and common pitfalls.
npx skillsauth add sammcj/agentic-coding claude-agent-sdkInstall 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.
The Claude Agent SDK enables building autonomous AI agents with Claude through a feedback loop architecture. Available for Python (3.10+) and TypeScript (Node 18+).
Repository:
Documentation: https://platform.claude.com/docs/en/agent-sdk/overview
# Python
pip install claude-agent-sdk
# TypeScript
npm install @anthropic-ai/agent-sdk
Every agent follows this cycle:
This pattern applies whether you're building a simple script or a complex multi-agent system.
Choose mechanisms based on task requirements:
Rule: Use tools for repeatable operations, bash for exploration, code generation when you need structured output that can be validated.
from claude_agent_sdk import query
result = await query(
model="claude-sonnet-4-5",
system_prompt="You are a helpful coding assistant.",
user_message="List files in current directory",
working_dir=".",
)
print(result.final_message)
import { ClaudeSdkClient } from '@anthropic-ai/agent-sdk';
const client = new ClaudeSdkClient({ apiKey: process.env.ANTHROPIC_API_KEY });
const result = await client.query({
model: 'claude-sonnet-4-5',
systemPrompt: 'You are a helpful coding assistant.',
userMessage: 'List files in current directory',
workingDir: '.',
});
console.log(result.finalMessage);
In-process tools with no subprocess overhead. Primary building block for agents.
Python:
from claude_agent_sdk.mcp import tool, create_sdk_mcp_server
@tool(
name="calculator",
description="Perform calculations",
input_schema={"expression": str}
)
async def calculator(args):
result = eval(args["expression"]) # Use safe eval in production
return {"content": [{"type": "text", "text": str(result)}]}
server = create_sdk_mcp_server(name="math", tools=[calculator])
TypeScript:
import { createSdkMcpServer, tool } from '@anthropic-ai/agent-sdk';
import { z } from 'zod';
const calculator = tool({
name: 'calculator',
description: 'Perform calculations',
inputSchema: z.object({ expression: z.string() }),
async execute({ expression }) {
const result = eval(expression); // Use safe eval in production
return { content: [{ type: 'text', text: String(result) }] };
},
});
const server = createSdkMcpServer({ name: 'math', tools: [calculator] });
Benefits over external MCP: Better performance, easier debugging, shared memory space, no IPC overhead.
Intercept and modify agent behaviour at specific points.
Available hooks:
PreToolUse → Validate/modify/deny tool calls before executionPostToolUse → Process/log/modify tool resultsStop → Handle completion eventsPython validation example:
async def validate_command(input_data, tool_use_id, context):
if "rm -rf" in input_data["tool_input"].get("command", ""):
return {
"hookSpecificOutput": {
"permissionDecision": "deny",
"permissionDecisionReason": "Dangerous command blocked"
}
}
TypeScript logging example:
const loggingHook = {
matcher: (input) => input.toolName === 'bash',
async handler(input, toolUseId, context) {
console.log(`Executing: ${input.toolInput.command}`);
}
};
Four modes with progressively less restriction:
default → Prompt for each tool useplan → Agent can read/explore freely, prompts for modificationsacceptEdits → Auto-approve file edits, prompt for bash/destructive opsbypassPermissions → Fully autonomous (use carefully)Dynamic control with canUseTool:
async def permission_callback(tool_name, tool_input, context):
if tool_name == "bash" and "git push" in tool_input.get("command", ""):
return False # Deny
return True # Allow
Isolated agents with separate context windows and specialised capabilities.
When to use:
Python:
from claude_agent_sdk import ClaudeAgentOptions
options = ClaudeAgentOptions(
subagent_definitions={
"researcher": {
"tools": ["read", "grep", "glob"],
"model": "claude-haiku-4",
"description": "Fast research agent"
}
}
)
TypeScript:
const options = {
subagentDefinitions: {
researcher: {
tools: ['read', 'grep', 'glob'],
model: 'claude-haiku-4',
description: 'Fast research agent'
}
}
};
Agentic Search (Preferred): Use bash + filesystem navigation (grep, ls, tail) before reaching for semantic search. Simpler and more reliable.
Automatic Compaction: SDK automatically summarises messages when approaching token limits. Transparent and automatic.
Folder Structure as Context Engineering: Organise files intentionally—directory structure is visible to the agent and influences its understanding.
Explicit validation enables self-correction:
# In PostToolUse hook
if tool_name == "write":
# Run linter on generated file
lint_result = run_linter(tool_output)
if lint_result.has_errors:
return {"continue": True} # Let agent fix errors
For UI tasks, screenshot and re-evaluate:
@tool(name="check_ui", description="Verify UI matches requirements")
async def check_ui(args):
screenshot = take_screenshot(args["url"])
# Return screenshot to agent for evaluation
return {"content": [{"type": "image", "source": screenshot}]}
Only for fuzzy criteria where rules don't work (higher latency):
judge_result = await secondary_model.evaluate(
criteria="Does output match tone guidelines?",
output=agent_output
)
Symptom: CLAUDE.md ignored, custom prompts not applied
Solution: Set setting_sources=["project"] or ["user", "project"]
# Python
options = ClaudeAgentOptions(setting_sources=["project"])
# TypeScript
const options = { settingSources: ['project'] };
Symptom: "Tool not found" errors
Solution: Check MCP tool naming: mcp__{server_name}__{tool_name}
Symptom: Agent can't access directories Solution: Add directories explicitly:
options = ClaudeAgentOptions(add_dirs=["/path/to/data"])
Symptom: Syntax errors with async or continue parameters
Solution: Use async_ and continue_ (SDK auto-converts)
# Use async_ not async
hook_result = {"async_": True, "continue_": False}
Symptom: Token limit errors Solution: Use subagents for isolation or let automatic compaction handle it
Symptom: Tools fail silently or with unclear errors Solution: Return structured error messages in tool responses:
return {
"content": [{
"type": "text",
"text": "Error: Invalid input. Expected format: ...",
"isError": True
}]
}
Symptom: stdio/SSE MCP servers timeout Solution: Verify server is executable and logs are accessible:
# Check server stderr in context.mcp_server_logs
async def debug_hook(input_data, tool_use_id, context):
print(context.mcp_server_logs.get("server_name"))
| Aspect | Python | TypeScript |
|--------|--------|------------|
| Runtime | anyio.run(main) | Native async/await |
| Min Version | Python 3.10+ | Node.js 18+ |
| Type Safety | Type hints optional | Strict types with Zod |
| Hook Fields | async_, continue_ | async, continue |
| CLI | Bundled (no install) | Separate install needed |
| Tool Validation | Dict-based schemas | Zod schemas |
✅ Use when:
❌ Don't use when:
Use Custom Tools when:
Use Bash when:
Use Code Generation when:
Use SDK MCP (in-process) when:
Use External MCP (stdio/SSE) when:
Python:
# First run
result1 = await query(user_message="Create a file", working_dir=".")
# Resume with new message
result2 = await query(
user_message="Now modify it",
working_dir=".",
session_id=result1.session_id
)
TypeScript:
// First run
const result1 = await client.query({ userMessage: 'Create a file' });
// Resume
const result2 = await client.query({
userMessage: 'Now modify it',
sessionId: result1.sessionId
});
Create alternative branches from a point:
# Fork for different approach
result_fork = await query(
user_message="Try different implementation",
session_id=original_result.session_id,
fork_session=True
)
Set USD spending limits:
options = ClaudeAgentOptions(budget={"usd": 5.00})
Agent stops when budget exceeded. Useful for cost control in production.
Python:
import pytest
from unittest.mock import AsyncMock
@pytest.fixture
def mock_tool():
return AsyncMock(return_value={
"content": [{"type": "text", "text": "mocked"}]
})
async def test_agent(mock_tool):
server = create_sdk_mcp_server(name="test", tools=[mock_tool])
# Test with mocked tool
TypeScript:
import { jest } from '@jest/globals';
const mockTool = {
name: 'test',
execute: jest.fn().mockResolvedValue({
content: [{ type: 'text', text: 'mocked' }]
})
};
Test with real tools in isolated environment:
import tempfile
import os
async def test_file_operations():
with tempfile.TemporaryDirectory() as tmpdir:
result = await query(
user_message="Create test.txt with content 'hello'",
working_dir=tmpdir,
permission_mode="bypassPermissions"
)
assert os.path.exists(f"{tmpdir}/test.txt")
If migrating from the deprecated claude-code-sdk:
claude-code-sdk → claude-agent-sdksetting_sourcesClaudeCodeOptions → ClaudeAgentOptionssetting_sources=["project"]See migration guide: https://platform.claude.com/docs/en/agent-sdk/migration-guide
turn_limit parameter)add_dirs to limit scopetools
Provides tools for managing MarkEdit, a macOS markdown editor
tools
Provides knowledge on using the `glean` CLI tool to access company knowledge and documents through Glean. Use when the user asks you to use Glean to search, read or otherwise access knowledge from their company's Confluence, Slack, Google Drive Files (Slides, Documents, Sheets) etc.
development
Applies the Diataxis framework to create or improve technical documentation. Use when being asked to write high quality tutorials, how-to guides, reference docs, or explanations, when reviewing documentation quality, or when deciding what type of documentation to create. Helps identify documentation types using the action/cognition and acquisition/application dimensions.
development
Use when answering questions from this machine-learning knowledge base. Triggers: questions about transformers, attention cost and efficiency, and long-context scaling; 'what do we know about attention', 'check the ML wiki'. Read-only querying of compiled knowledge; to add, update, supersede, lint, audit, or critique, use the llm-wiki skill instead.