Back to List

The Complete Guide to Claude Code Agent SDK: Build Your Own AI Agents with Claude's Engine

2026-03-20·8 min read·AITutorial

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

DimensionClaude Code CLIAnthropic APIAgent SDK
InteractionTerminal conversationHTTP requestsProgrammatic calls
Tool SystemBuilt-in Bash/Read/Edit etc.Build your ownInherits all CLI tools
Agent LoopBuilt-inBuild your ownBuilt-in
Context ManagementAutomaticManualAutomatic
Permission ControlInteractive approvalNoneProgrammable approval
Use CaseDaily developmentGeneral AI appsCustom agents
MCP SupportYesNoYes

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

LanguagePackageStatus
TypeScript@anthropic-ai/claude-codePrimary, most complete
Pythonclaude-code-sdkFull 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-code

Python:

pip install claude-code-sdk

Prerequisites: 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 the ANTHROPIC_API_KEY environment 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:

  • systemPrompt completely replaces Claude Code's default system prompt. You lose all built-in behavior guidance
  • appendSystemPrompt appends 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):

ModeDescription
"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 result

A 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:

ScenarioRecommended ModeReason
Development/debuggingdefaultKeep human approval, safety first
Read-only analysisplanEnsure no file modifications
CI/CD pipelinesautoEdit + allowedToolsAutomated but tool-scoped
Controlled batch processingfullAuto + allowedToolsFully 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

  1. Never use bypassPermissions in production — it skips all safety checks
  2. Always set allowedTools — principle of least privilege
  3. Set maxTurns — prevent agents from entering infinite loops
  4. Use cwd to 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:

ToolFunctionNotes
BashExecute shell commandsSupports fine-grained command allowlists
ReadRead filesSupports line ranges
WriteWrite filesCreate or overwrite
EditEdit filesPrecise replacements
GlobFile searchSupports glob patterns
GrepContent searchSupports regex
AgentSub-agentsSpawn 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-code

Which 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?

  1. Set maxTurns — limit the agent's maximum reasoning turns
  2. Choose the right model — Haiku for simple tasks, Sonnet/Opus for complex ones
  3. Limit tool scope — reduce unnecessary tool calls
  4. Use plan mode 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:

  1. 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
  2. Security firstallowedTools + permissionMode + maxTurns are the three lines of defense for production
  3. From using to building — with the SDK, you go from being a Claude Code user to being a Claude Code developer

Recommended Reading