Learn Claude Code Subagents: Multi-Agent Orchestration The Claude Agent SDK: Building Programmatic Agent Applications

The Claude Agent SDK: Building Programmatic Agent Applications

Intermediate 🕐 14 min Lesson 14 of 15
What you'll learn
  • Explain what the Claude Agent SDK is and how it differs from using .claude/agents/ definition files or the CLI interactively
  • Write a working agent using the query() function with ClaudeAgentOptions and AgentDefinition objects
  • Identify the correct SDK use cases versus when the Claude Code CLI is the better choice

What the Agent SDK Is

Everything you have built in this track so far — subagent definitions, tool scoping, MCP configurations, lifecycle hooks — works through the Claude Code CLI. You write definition files, you open a session, you interact. The orchestration layer is Claude's own decision-making.

The Claude Agent SDK is a different layer. It gives you programmatic control over the same capabilities from Python or TypeScript code. Instead of defining agents in .claude/agents/ files, you define them as objects in code. Instead of starting a session and prompting Claude, you call query() and iterate over results. You write the outer loop; Claude executes within it.

This is what enables CI/CD pipelines, production automation, and custom applications built on top of Claude's agent infrastructure.

Installing the SDK

Two packages, one for each language:

# Python (requires 3.10+)
pip install claude-agent-sdk

# TypeScript
npm install @anthropic-ai/claude-agent-sdk

Set your API key:

export ANTHROPIC_API_KEY=your-api-key

The TypeScript package bundles a native Claude Code binary — you do not need to install Claude Code separately. The Python package requires Claude Code to be installed.

The query() Function

The main entry point is the query() function. It takes a prompt and options, and returns an async iterator of messages:

# Python
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions

async def main():
    async for message in query(
        prompt="Find all TODO comments in src/ and create a summary",
        options=ClaudeAgentOptions(allowed_tools=["Read", "Glob", "Grep"]),
    ):
        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 all TODO comments in src/ and create a summary",
  options: { allowedTools: ["Read", "Glob", "Grep"] }
})) {
  if ("result" in message) console.log(message.result);
}

The ClaudeAgentOptions object accepts the same controls you have learned throughout this track: allowed_tools, permission_mode, mcp_servers, and agents for defining custom subagent types programmatically.

Defining Custom Agents in Code

The agents option in ClaudeAgentOptions accepts AgentDefinition objects — the programmatic equivalent of agent definition files:

from claude_agent_sdk import query, ClaudeAgentOptions, AgentDefinition

async for message in query(
    prompt="Use the security-auditor to review src/",
    options=ClaudeAgentOptions(
        allowed_tools=["Read", "Glob", "Grep", "Agent"],
        agents={
            "security-auditor": AgentDefinition(
                description="Reviews code for security vulnerabilities.",
                prompt="Scan for SQL injection, XSS, and auth bypass risks.",
                tools=["Read", "Glob", "Grep"],
            )
        },
    ),
):

Include Agent in allowed_tools to auto-approve the Agent tool invocations needed to spawn your custom subagents.

Session Resumption

The SDK supports resuming sessions to maintain context across multiple query() calls:

session_id = None

# First query: capture session ID
async for message in query(prompt="Read the auth module", options=options):
    if message.type == "system" and message.subtype == "init":
        session_id = message.data["session_id"]

# Second query: resume with full context
async for message in query(
    prompt="Now find all callers of the functions you just read",
    options=ClaudeAgentOptions(resume=session_id),
):

The initialPrompt frontmatter field (for file-based agent definitions) works with claude --agent name for the same purpose in CLI sessions: it auto-submits as the first user turn when the agent runs as the main session.

SDK vs. CLI: When to Use Each

The SDK and CLI have the same underlying capabilities. The choice depends on your workflow:

  • Use the CLI for interactive development, exploration, one-off tasks, and workflows where you want to guide Claude turn-by-turn.
  • Use the SDK for CI/CD pipelines, production automation, custom applications, and workflows you want to run unattended on a schedule.

Many teams use both: CLI for daily development work, SDK for production pipelines that run in GitHub Actions or other automation environments. Workflows translate directly between them — an agent definition that works in .claude/agents/ can be adapted to an AgentDefinition object in SDK code without rewriting the logic.

Key takeaways
  • The Claude Agent SDK (<code>claude-agent-sdk</code> for Python, <code>@anthropic-ai/claude-agent-sdk</code> for TypeScript) gives programmatic control over the same Claude Code agent capabilities
  • The <code>query()</code> function takes a prompt and <code>ClaudeAgentOptions</code>, returning an async iterator of messages — <code>allowed_tools</code>, <code>permission_mode</code>, <code>agents</code>, and <code>mcp_servers</code> all work as expected
  • <code>AgentDefinition</code> objects in the <code>agents</code> option are the programmatic equivalent of <code>.claude/agents/</code> definition files — include <code>Agent</code> in <code>allowed_tools</code> to auto-approve subagent spawning
  • Sessions can be resumed across multiple <code>query()</code> calls using the session ID captured from the init system message — <code>initialPrompt</code> in file-based definitions serves the same role for <code>claude --agent</code> CLI sessions
  • Use the CLI for interactive work and exploration; use the SDK for CI/CD, production automation, and custom applications — workflows transfer directly between them