The Complete Guide to Claude Code Agent SDK: Build Your Own AI Agents with Claude's Engine
Introduction
In the Multi-Agent Parallelism Guide, we covered how to orchestrate multiple Claude instances working together. In the MCP Guide, we covered how to extend Claude Code's capabilities through MCP Servers.
But all of that is still using Claude Code.
If you want to go further — build your own AI agents using Claude Code's engine — that's where Agent SDK comes in.
One-line summary: Agent SDK is Claude Code's underlying engine, packaged as a programmable library. Everything Claude Code CLI can do — agent loop, tool invocation, context management, permission control — you can implement in your own programs through the SDK.
1. What Is Agent SDK
1.1 Core Concept
Claude Code is not just a terminal application. Under the hood, it is a complete agent system:
┌─────────────────────────────────────────┐
│ Claude Code CLI │
├─────────────────────────────────────────┤
│ Agent Loop │ Tool System │ Context │
│ (reasoning │ (Bash, │ (history,│
│ cycle) │ Read, │ cache, │
│ │ Edit...) │ compression)
├─────────────────────────────────────────┤
│ Anthropic API (Claude) │
└─────────────────────────────────────────┘
Agent SDK exposes that middle layer — agent loop + tool system + context management — as a programmable interface.
1.2 Three Approaches Compared
| Dimension | Claude Code CLI | Anthropic API | Agent SDK |
|---|---|---|---|
| Interaction | Terminal conversation | HTTP requests | Programmatic calls |
| Tool System | Built-in Bash/Read/Edit etc. | Build your own | Inherits all CLI tools |
| Agent Loop | Built-in | Build your own | Built-in |
| Context Management | Automatic | Manual | Automatic |
| Permission Control | Interactive approval | None | Programmable approval |
| Use Case | Daily development | General AI apps | Custom agents |
| MCP Support | Yes | No | Yes |
In short:
- Anthropic API gives you a brain (Claude model), but you wire up the hands and feet yourself
- Agent SDK gives you a complete body (brain + hands + feet + coordination), you just tell it what to do
- Claude Code CLI is that body wearing a terminal interface
1.3 History
Agent SDK was originally called Claude Code SDK (released early 2025), since it was essentially the SDK for Claude Code. In September 2025, Anthropic renamed it to Claude Agent SDK, better reflecting its positioning — not just a Claude Code accessory, but an independent agent-building framework.
Package names remained unchanged for backward compatibility:
- TypeScript:
@anthropic-ai/claude-code - Python:
claude-code-sdk
1.4 Supported Languages
| Language | Package | Status |
|---|---|---|
| TypeScript | @anthropic-ai/claude-code | Primary, most complete |
| Python | claude-code-sdk | Full support, Pythonic API style |
Both versions have highly consistent API designs. This post provides examples in both languages.
2. Quick Start
2.1 Installation
TypeScript:
npm install @anthropic-ai/claude-codePython:
pip install claude-code-sdkPrerequisites: Agent SDK depends on the Claude Code CLI runtime. Make sure you have Claude Code CLI installed (
npm install -g @anthropic-ai/claude-code) and theANTHROPIC_API_KEYenvironment variable set. Node.js 18+ / Python 3.10+.
2.2 Minimal Example
TypeScript:
import { query, type Message } from "@anthropic-ai/claude-code";
const messages: Message[] = [];
for await (const message of query({
prompt: "Explain what an Agent Loop is",
options: {
maxTurns: 3,
},
})) {
if (message.type === "assistant") {
for (const block of message.message.content) {
if (block.type === "text") {
process.stdout.write(block.text);
}
}
}
messages.push(message);
}Python:
from claude_code_sdk import query, ClaudeCodeOptions, Message
messages: list[Message] = []
async for message in query(
prompt="Explain what an Agent Loop is",
options=ClaudeCodeOptions(max_turns=3),
):
if message.type == "assistant":
for block in message.message.content:
if hasattr(block, "text"):
print(block.text, end="")
messages.append(message)The core is a single function: query(). Pass in a prompt, get back an async iterator that yields messages. That simple.
3. Core API
3.1 query() Parameters
query() is the core function of Agent SDK. All interactions go through it:
query({
prompt: string, // User input
options: {
model?: string, // Model, defaults to claude-sonnet-4-20250514
systemPrompt?: string, // Fully replace default system prompt
appendSystemPrompt?: string, // Append to default system prompt
allowedTools?: string[], // Tool allowlist
disallowedTools?: string[], // Tool blocklist
permissionMode?: string, // Permission mode
cwd?: string, // Working directory
mcpServers?: Record<string, McpServerConfig>, // MCP servers
maxTurns?: number, // Maximum turns
},
})Key parameters explained:
systemPrompt vs appendSystemPrompt:
systemPromptcompletely replaces Claude Code's default system prompt. You lose all built-in behavior guidanceappendSystemPromptappends to the end of the default prompt. Recommended — preserves Claude Code's core capabilities
allowedTools allowlist:
// Only allow reading and searching, no write operations
options: {
allowedTools: ["Read", "Glob", "Grep"],
}permissionMode:
Identical to CLI permission modes (see the Security Guide for details):
| Mode | Description |
|---|---|
"default" | Default, dangerous operations require approval |
"plan" | Read-only, no write operations |
"autoEdit" | Auto-approve file edits, Shell still requires approval |
"fullAuto" | Auto-approve all operations |
"bypassPermissions" | Skip all permission checks (dangerous) |
3.2 Message Types
The message stream from query() contains several types:
type Message =
| { type: "assistant"; message: AssistantMessage } // Claude's response
| { type: "user"; message: UserMessage } // Tool results (auto-generated)
| { type: "result"; result: ResultMessage } // Final resultA typical message flow:
assistant → "Let me read that file"
assistant → [tool_use: Read("src/index.ts")]
user → [tool_result: file contents...]
assistant → "This file does..."
result → { final output }
3.3 Multi-Turn Conversations
query() supports passing conversation history via the messages parameter:
import { query, type Message } from "@anthropic-ai/claude-code";
// First turn
const history: Message[] = [];
for await (const msg of query({ prompt: "Read package.json" })) {
history.push(msg);
}
// Second turn, with history
for await (const msg of query({
prompt: "Change the name field to my-app",
options: { messages: history },
})) {
history.push(msg);
}3.4 V2 Session API (Preview)
V1's query() treats each call independently. V2 introduces Sessions for simpler multi-turn conversations:
import { createSession } from "@anthropic-ai/claude-code";
const session = await createSession({
model: "claude-sonnet-4-20250514",
systemPrompt: "You are a code review assistant",
});
// Multi-turn conversation, session manages context automatically
const response1 = await session.send("Analyze the security of src/auth.ts");
const response2 = await session.send("Suggest fixes for the issues found");
// Streaming output
for await (const chunk of session.stream("Summarize all findings")) {
process.stdout.write(chunk);
}V2 API is currently in preview. The interface may change. Use V1's
query()for production.
4. Permissions and Security
4.1 Permission Modes
Agent SDK's permission modes are identical to the CLI (see the Security Guide), but with different considerations in SDK scenarios:
| Scenario | Recommended Mode | Reason |
|---|---|---|
| Development/debugging | default | Keep human approval, safety first |
| Read-only analysis | plan | Ensure no file modifications |
| CI/CD pipelines | autoEdit + allowedTools | Automated but tool-scoped |
| Controlled batch processing | fullAuto + allowedTools | Fully automatic but strictly limited tools |
4.2 allowedTools Allowlist
This is the most important security mechanism in SDK scenarios. Use allowlists to precisely control what tools an agent can use:
// Code review agent: read-only, cannot modify anything
const reviewAgent = query({
prompt: "Review the code quality of this PR",
options: {
allowedTools: ["Read", "Glob", "Grep", "Bash(git diff)"],
permissionMode: "plan",
},
});
// Documentation agent: can read code, write Markdown
const docAgent = query({
prompt: "Generate API docs for the src/api/ directory",
options: {
allowedTools: ["Read", "Glob", "Grep", "Write", "Edit"],
permissionMode: "autoEdit",
},
});The Bash tool supports fine-grained control:
allowedTools: [
"Bash(npm test)", // Only allow running tests
"Bash(git diff)", // Only allow viewing diffs
"Bash(git log)", // Only allow viewing logs
]4.3 Best Practices
- Never use
bypassPermissionsin production — it skips all safety checks - Always set
allowedTools— principle of least privilege - Set
maxTurns— prevent agents from entering infinite loops - Use
cwdto restrict the working directory — prevent agents from accessing files they should not
// Recommended production configuration
query({
prompt: userInput,
options: {
allowedTools: ["Read", "Glob", "Grep"],
permissionMode: "plan",
maxTurns: 10,
cwd: "/app/workspace",
},
});5. Custom Tools (MCP)
5.1 Built-in Tools
Agent SDK inherits all of Claude Code's built-in tools:
| Tool | Function | Notes |
|---|---|---|
Bash | Execute shell commands | Supports fine-grained command allowlists |
Read | Read files | Supports line ranges |
Write | Write files | Create or overwrite |
Edit | Edit files | Precise replacements |
Glob | File search | Supports glob patterns |
Grep | Content search | Supports regex |
Agent | Sub-agents | Spawn sub-agents for subtasks |
5.2 Extending Tools via MCP
Just like the CLI (see the MCP Guide), the SDK supports extending tools through MCP Servers:
query({
prompt: "Check recent GitHub Issues",
options: {
mcpServers: {
github: {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-github"],
env: {
GITHUB_TOKEN: process.env.GITHUB_TOKEN,
},
},
},
},
});5.3 Practical Example: Agent with Database Query Capability
Combining MCP, we can build an agent that queries databases:
import { query } from "@anthropic-ai/claude-code";
async function dbQueryAgent(question: string) {
const messages = [];
for await (const message of query({
prompt: question,
options: {
appendSystemPrompt:
"You are a database analysis assistant. Users will ask questions about data. " +
"Use MCP tools to query the PostgreSQL database. " +
"Always check table structure before querying. Avoid full table scans.",
mcpServers: {
postgres: {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-postgres"],
env: {
POSTGRES_CONNECTION_STRING: process.env.DATABASE_URL,
},
},
},
allowedTools: [
"mcp__postgres__query",
"mcp__postgres__list_tables",
"mcp__postgres__describe_table",
],
maxTurns: 10,
},
})) {
messages.push(message);
}
const result = messages.find((m) => m.type === "result");
return result?.result;
}
// Usage
const answer = await dbQueryAgent("How many new users last month? Break down by week.");6. Practical Examples: Building Custom Agents
6.1 Code Review Agent
An agent that reads git diffs and outputs structured review feedback:
import { query, type Message } from "@anthropic-ai/claude-code";
interface ReviewResult {
summary: string;
issues: Array<{
severity: "error" | "warning" | "info";
file: string;
line?: number;
message: string;
}>;
}
async function codeReviewAgent(baseBranch = "main"): Promise<ReviewResult> {
const messages: Message[] = [];
for await (const message of query({
prompt: `Review all code changes on the current branch relative to ${baseBranch}.
Requirements:
1. Run git diff ${baseBranch}...HEAD to see changes
2. Analyze file by file, focusing on: security vulnerabilities, performance issues, logic errors, code style
3. Output results as JSON in this format:
{
"summary": "Overall assessment",
"issues": [
{ "severity": "error|warning|info", "file": "path", "line": lineNumber, "message": "description" }
]
}
Output only JSON, nothing else.`,
options: {
allowedTools: ["Bash(git diff)", "Bash(git log)", "Read", "Glob", "Grep"],
permissionMode: "plan",
maxTurns: 15,
},
})) {
messages.push(message);
}
const result = messages.find((m) => m.type === "result");
return JSON.parse(result?.result?.text ?? "{}");
}6.2 Documentation Generation Agent
Scan a codebase and automatically generate API documentation:
import { query, type Message } from "@anthropic-ai/claude-code";
async function generateApiDocs(sourceDir: string, outputFile: string) {
const messages: Message[] = [];
for await (const message of query({
prompt: `Generate API documentation for all TypeScript files in ${sourceDir}.
Steps:
1. Use Glob to find all .ts files
2. Read each file, extract exported functions, classes, and interfaces
3. Generate docs for each export: description, parameters, return values, usage examples
4. Write the complete documentation to ${outputFile} in Markdown format`,
options: {
allowedTools: ["Read", "Glob", "Grep", "Write"],
permissionMode: "autoEdit",
maxTurns: 30,
},
})) {
messages.push(message);
}
console.log(`Documentation generated: ${outputFile}`);
}
// Usage
await generateApiDocs("src/api", "docs/API.md");7. Advanced Topics
7.1 Hooks: Intercepting Tool Calls
Just like the CLI (see the Hooks Guide), the SDK supports Hooks for intercepting tool calls:
query({
prompt: "Refactor src/utils.ts",
options: {
hooks: {
preToolUse: [
{
matcher: "Write|Edit",
command: "echo 'File modification detected' >> /tmp/agent.log",
},
],
postToolUse: [
{
matcher: "Bash",
command: "echo 'Command executed' >> /tmp/agent.log",
},
],
},
},
});7.2 Sub-Agent Pattern
Agents can spawn sub-agents internally for task decomposition:
query({
prompt: `Complete the following tasks:
1. Review the security of src/auth/
2. Review the API design of src/api/
3. Summarize both reviews
Use sub-agents to handle the first two tasks in parallel, then summarize.`,
options: {
allowedTools: ["Read", "Glob", "Grep", "Agent"],
maxTurns: 20,
},
});When allowedTools includes Agent, Claude can automatically create sub-agents for parallel subtask processing — identical to the multi-agent parallelism behavior you see in the CLI.
7.3 Streaming and Cancellation
The SDK's streaming output naturally supports cancellation:
const controller = new AbortController();
// Cancel after 5 seconds
setTimeout(() => controller.abort(), 5000);
try {
for await (const message of query({
prompt: "Analyze the entire codebase architecture",
options: { signal: controller.signal },
})) {
// Process messages...
}
} catch (err) {
if (err.name === "AbortError") {
console.log("Task cancelled");
}
}7.4 CI/CD Integration
Agent SDK is a natural fit for CI/CD pipelines (see the CI/CD Guide):
// ci-review.ts — Auto-run code review on PRs
import { query } from "@anthropic-ai/claude-code";
async function ciReview() {
const messages = [];
for await (const msg of query({
prompt: "Review the current PR's code changes, output a Markdown review report",
options: {
allowedTools: [
"Bash(git diff)",
"Bash(git log)",
"Read",
"Glob",
"Grep",
],
permissionMode: "plan", // Read-only, no file modifications
maxTurns: 15,
},
})) {
messages.push(msg);
}
const result = messages.find((m) => m.type === "result");
return result?.result?.text ?? "Review complete, no issues found.";
}In GitHub Actions:
# .github/workflows/ai-review.yml
name: AI Code Review
on: [pull_request]
jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: "20"
- run: npm install @anthropic-ai/claude-code
- run: npx tsx ci-review.ts
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}8. FAQ
Agent SDK vs Anthropic API — when to use which?
- Use Anthropic API: You need full control over prompts, tool definitions, and message format, or your use case does not involve file system operations (e.g., chatbots, content generation)
- Use Agent SDK: You need agents that interact with the file system (read/write files, execute commands), or you want to reuse Claude Code's tool system and agent loop
Rule of thumb: if you find yourself reimplementing Bash execution, file I/O, and error retry logic on top of the Anthropic API, switch to Agent SDK.
Do I need Claude Code CLI installed?
Yes. Agent SDK depends on the Claude Code CLI runtime. The SDK is essentially a programmatic interface to the CLI — it calls the same underlying engine.
# Install CLI first
npm install -g @anthropic-ai/claude-code
# Then install SDK
npm install @anthropic-ai/claude-codeWhich models are supported?
Agent SDK supports all Claude models. Specify via options.model:
query({
prompt: "...",
options: {
model: "claude-opus-4-20250918", // Strongest reasoning
// model: "claude-sonnet-4-20250514", // Default, balanced
// model: "claude-haiku-4-5-20251001", // Fastest, for simple tasks
},
});How do I control costs?
- Set
maxTurns— limit the agent's maximum reasoning turns - Choose the right model — Haiku for simple tasks, Sonnet/Opus for complex ones
- Limit tool scope — reduce unnecessary tool calls
- Use
planmode for read-only analysis — avoid extra turns from write operations
Can I use it in the browser?
No. Agent SDK requires file system access and shell command execution. It only runs in Node.js or Python server environments. For browser-based Claude usage, use the Anthropic API directly.
V1 vs V2 — which should I use?
- V1
query(): Stable, production-ready, suitable for most scenarios - V2
createSession(): Preview stage, API may change, but better multi-turn conversation experience
Recommendation: start with V1 for new projects, migrate to V2 once it stabilizes.
9. Summary
Three key takeaways:
- Agent SDK = Claude Code's engine — it is not something new, but the underlying capabilities you use every day in the terminal, exposed as a programmable interface
- Security first —
allowedTools+permissionMode+maxTurnsare the three lines of defense for production - From using to building — with the SDK, you go from being a Claude Code user to being a Claude Code developer
Recommended Reading
- Multi-Agent Parallelism Guide — Understanding agent collaboration patterns
- MCP Deep Dive — Extending agent capabilities through MCP
- Hooks Guide — Intercepting and controlling tool calls
- Security Best Practices — Permission models and security defenses
- CI/CD Guide — Agents in CI/CD pipelines
- Anthropic Official Docs: Agent SDK — Latest API reference