The Claude Agent SDK lets you build production AI agents in Python or TypeScript. Inbox triage tutorial, MCP servers, cron deploy, rate-limit gotchas.
The Claude Agent SDK is a Python and TypeScript library that gives you a production-ready AI agent loop — file reading, command execution, code editing, and web search — built directly on top of the same engine that powers Claude Code.
If you have spent any time with the raw Anthropic Messages API, you know the drill: send a prompt, check whether the response includes a tool call, execute the tool, send the result back, repeat. The Claude Agent SDK removes that entire plumbing layer. You hand it a prompt and a list of allowed tools, then stream the results while Claude handles the loop. This post walks through a real working agent, a daily inbox triage system that summarises high-priority emails and posts to Slack, including the rate-limit gotchas, the tool-loop pattern, and a cron-based production deploy.
I have been building production agents with Claude for over a year. This is the clearest path I have found from zero to a working autonomous system.
The Claude Agent SDK is a library from Anthropic that exposes the full Claude Code agent loop as a programmable interface in Python and TypeScript. Rather than implementing your own tool-use loop against the Messages API, you import `query` from the SDK, pass it a prompt and a set of permitted tools, and stream back structured messages as Claude reads files, runs commands, searches the web, and edits code autonomously.
Anthropic recently renamed it from the Claude Code SDK to the Claude Agent SDK. If you see references to `claude-code-sdk` in older posts or packages, they point to the same thing. The current Python package is claude-agent-sdk and the npm package is @anthropic-ai/claude-agent-sdk.
The SDK sits between the raw Anthropic Client SDK (which requires you to write the tool loop) and Managed Agents (where Anthropic runs the infrastructure). With the Agent SDK, the loop runs in your own process, on your own infrastructure.
The Agent SDK exposes a single core function called `query`. You call it with a natural-language prompt and an `options` object that specifies which tools Claude is allowed to use. `query` returns an async iterator that yields messages as Claude works: reasoning text, tool calls, tool results, and a final result message.
Under the hood, Claude reads your prompt, decides which tool to call first, executes it, observes the output, and decides what to do next. That loop continues until Claude decides the task is complete. The SDK handles retries, context management, and session state, none of that is your problem.
Here is the minimal Python pattern:
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, AssistantMessage, ResultMessage
async def run_agent(task: str):
async for message in query(
prompt=task,
options=ClaudeAgentOptions(
allowed_tools=["Read", "Bash", "Glob", "Grep"],
permission_mode="acceptEdits",
),
):
if isinstance(message, AssistantMessage):
for block in message.content:
if hasattr(block, "text"):
print(block.text)
elif isinstance(message, ResultMessage):
return message.result
asyncio.run(run_agent("Summarise the five most recent emails in ~/mail/inbox/"))The `async for` loop is the whole pattern. Claude calls tools, you get message objects. Filter for `AssistantMessage` to show Claude's reasoning, and `ResultMessage` for the final output.
The SDK ships with ten built-in tools you enable by name. Read opens files. Write creates them. Edit makes targeted changes to existing files. Bash runs terminal commands and scripts. Monitor watches background processes. Glob finds files by pattern. Grep searches file contents. WebSearch queries the web. WebFetch fetches and parses pages. AskUserQuestion pauses to collect user input.
The `permission_mode` option controls how much the agent can do without pausing. `acceptEdits` auto-approves file edits and common filesystem commands. `dontAsk` denies anything not in `allowed_tools`. `bypassPermissions` runs every tool without prompts (use only in sandboxed CI). `default` requires a `canUseTool` callback for custom approval flows. For production headless agents, `acceptEdits` with a narrow `allowed_tools` list is the safest default.
The agent reads unread emails via a local fetchmail dump, classifies them by priority, writes a Markdown summary, then posts it to a Slack webhook. The whole thing runs in under two minutes and costs roughly $0.04 per run.
inbox-agent/
agent.py # main agent script
prompts.py # task prompt
.env # ANTHROPIC_API_KEY, SLACK_WEBHOOK_URL
mail/inbox/ # fetchmail drops .eml files hereimport asyncio
import os
import httpx
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
SLACK_WEBHOOK = os.environ["SLACK_WEBHOOK_URL"]
TASK = """
Read every .eml file in mail/inbox/.
For each email, extract: sender, subject, date, and a one-sentence summary.
Classify each as HIGH, MEDIUM, or LOW priority.
HIGH = investor updates, customer complaints, payment failures, anything with URGENT in subject.
Write a Markdown summary grouped by priority to mail/triage-summary.md.
Return the raw Markdown as your final result.
"""
async def main():
result_text = None
async for message in query(
prompt=TASK,
options=ClaudeAgentOptions(
allowed_tools=["Read", "Glob", "Write"],
permission_mode="acceptEdits",
),
):
if isinstance(message, ResultMessage):
result_text = message.result
if result_text:
async with httpx.AsyncClient() as client:
await client.post(
SLACK_WEBHOOK,
json={"text": f"*Daily inbox triage*\n\n{result_text[:2900]}"},
)
print("Posted to Slack.")
asyncio.run(main())Three tools only: Read to open emails, Glob to find all `.eml` files, Write to save the summary. No Bash, no internet access. The agent cannot do anything outside those three operations, which is exactly right for production.
The Claude Agent SDK connects to any MCP server, which means you can drop in a Postgres MCP server and your agent can query your database, or add the Playwright MCP server for browser automation, all without writing custom tool code. Pass an `mcp_servers` dict in `ClaudeAgentOptions` with the command and args for each server. The SDK connects to any MCP-compliant server: databases, browsers, APIs, and the growing ecosystem of community-built servers.
options=ClaudeAgentOptions(
mcp_servers={
"playwright": {"command": "npx", "args": ["@playwright/mcp@latest"]}
}
)You can resume a session across multiple calls, which means Claude retains memory of everything it has read and done. The session ID comes from the first `SystemMessage` with `subtype == "init"`. Capture it on the first run, pass it as `resume=session_id` on the next. This is the pattern that makes multi-step research agents practical. Each sub-task builds on what Claude already knows.
session_id = None
async for message in query(prompt="Read auth.py"):
if message.type == "system" and message.subtype == "init":
session_id = message.data["session_id"]
# Later, same context:
async for message in query(
prompt="Now find all callers of the auth functions",
options=ClaudeAgentOptions(resume=session_id),
):
...You can spawn named subagents with their own tools and system prompts. The orchestrator delegates, subagents report back. For a codebase audit, you might have a `security-reviewer` subagent with Read, Glob, and Grep, and a separate `docs-writer` subagent with Read and Write. Include `Agent` in `allowed_tools` since subagents are invoked via the Agent tool.
from claude_agent_sdk import AgentDefinition
options=ClaudeAgentOptions(
allowed_tools=["Read", "Glob", "Agent"],
agents={
"security-reviewer": AgentDefinition(
description="Expert security code reviewer.",
prompt="Find SQL injection, XSS, and authentication vulnerabilities.",
tools=["Read", "Glob", "Grep"],
)
},
)Hooks let you run custom code at lifecycle events. A `PostToolUse` hook fires after every tool call. Use it for audit logs, cost tracking, or blocking writes to production paths. For a deeper look at how hooks apply to the broader Claude Code configuration system, see our Claude Code guide.
from datetime import datetime
async def audit_log(input_data, tool_use_id, context):
file_path = input_data.get("tool_input", {}).get("file_path", "unknown")
with open("./audit.log", "a") as f:
f.write(f"{datetime.now()}: {file_path}\n")
return {}The SDK runs inside your process, on your infrastructure. That is a feature for most teams, but it means you own all the operational overhead: container sizing, retry logic, cold-start latency, and session storage (stored as JSONL on your filesystem by default). For long-running or asynchronous jobs, Anthropic's Managed Agents API offloads that to Anthropic-hosted infrastructure.
Rate limits are the other practical friction point. The SDK does not have built-in backoff. If you fire twenty concurrent agents with Bash and WebSearch enabled, you will hit token-per-minute limits quickly. The safest production pattern is a queue with one agent running at a time, or a semaphore if you need concurrency. Catch the API error and retry with exponential backoff.
The Claude Agent SDK also does not yet expose a direct REST interface, so you cannot call it from a non-Python, non-TypeScript runtime without spawning a subprocess. For Go or Java backends, Managed Agents is the right call.
# Python (pip)
python3 -m venv .venv && source .venv/bin/activate
pip install claude-agent-sdk
# Python (uv - faster)
uv init && uv add claude-agent-sdk
# TypeScript
npm install @anthropic-ai/claude-agent-sdkThe TypeScript package bundles a native Claude Code binary for your platform, so you do not need to install Claude Code separately.
Get an API key from the Anthropic Console, then set it as an environment variable:
export ANTHROPIC_API_KEY=your-api-keyThe SDK also supports Amazon Bedrock (`CLAUDE_CODE_USE_BEDROCK=1`), Google Vertex AI (`CLAUDE_CODE_USE_VERTEX=1`), and Microsoft Azure (`CLAUDE_CODE_USE_FOUNDRY=1`) if you need to run agents through those providers.
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions
async def main():
async for message in query(
prompt="What files are in this directory?",
options=ClaudeAgentOptions(allowed_tools=["Glob"]),
):
if hasattr(message, "result"):
print(message.result)
asyncio.run(main())python3 agent.pyFor the inbox triage agent, a simple cron job on a VPS handles the schedule:
# /etc/cron.d/inbox-agent
0 7 * * 1-5 /home/tom/inbox-agent/.venv/bin/python /home/tom/inbox-agent/agent.pyThat runs Monday to Friday at 7am. The agent finishes in under two minutes, posts to Slack, and exits. For n8n users, wrap the agent in a Python subprocess node on a scheduled trigger. See our Claude Code on the web guide for the broader deployment patterns.
The Client SDK gives you raw API access: you send a prompt and implement every tool call yourself. The Agent SDK wraps that loop. If you want control over every decision point in the tool-use cycle, use the Client SDK. If you want Claude to run autonomously and just tell you when it is done, use the Agent SDK.
Managed Agents is a hosted REST API: Anthropic runs the agent loop and the sandbox, and your application sends events and streams back results. The Agent SDK runs the loop inside your own process. The practical path: prototype with the Agent SDK, move to Managed Agents when you need Anthropic to handle the infrastructure. You can read more about the full Claude Code ecosystem in our Claude Code guide.
OpenAI's Agents SDK follows a similar pattern. The main difference is the tool inventory: Claude Agent SDK ships with Bash, Monitor, and WebFetch built in, which OpenAI's does not. Claude also handles long-context tasks better (200k token window) for codebase-wide analysis. For MCP support, the Claude Agent SDK is currently more mature. The Anthropic Agent SDK documentation covers the full comparison.
Yes, if you are building any kind of autonomous workflow that touches files, code, or the web. The SDK collapses what would be several hundred lines of tool-loop boilerplate into a ten-line async iterator. The built-in tools are production-quality. The MCP integration means you can add capabilities without writing custom tool definitions.
It is not the right choice if you need a non-Python, non-TypeScript runtime, if you want Anthropic to own the sandboxing and session storage, or if your task is simple enough that a single Messages API call handles it.
For most builders in the AI Operators community, the Claude Agent SDK is the correct abstraction. You get Claude's full capability set without owning the plumbing. If you are ready to put this to work, the 30-day AI Operator challenge is where we build real agents together.
The Claude Agent SDK is a Python and TypeScript library from Anthropic that gives you a production-ready AI agent loop. You pass it a prompt and a list of allowed tools, and Claude autonomously reads files, runs commands, edits code, and searches the web until the task is complete.
The SDK itself is free to download and use. You pay for API usage at standard Anthropic pricing. A typical agent run that reads ten files and makes a few edits costs between $0.02 and $0.10 depending on the model. Sonnet 4.6 is the cost-efficient default for most production workloads.
They are the same product. Anthropic renamed the Claude Code SDK to the Claude Agent SDK. The Python package changed from `claude-code-sdk` to `claude-agent-sdk`. The TypeScript package changed from `@anthropic-ai/claude-code-sdk` to `@anthropic-ai/claude-agent-sdk`. The official migration guide covers all the breaking changes.
Yes. Pass an `mcp_servers` dict in `ClaudeAgentOptions` with the command and args for each server. The SDK connects to any MCP-compliant server, from Postgres to Playwright to custom-built servers, without you writing any tool-execution code.
Python 3.10 or later. For TypeScript, Node.js 18 or later. The TypeScript package bundles a native Claude Code binary for your platform, so you do not need Claude Code installed separately.
The SDK does not have built-in backoff. For production deployments with multiple concurrent agents, add a semaphore or run agents sequentially through a queue. Hitting rate limits produces a standard API error you can catch and retry with exponential backoff using a library like `tenacity`.
Yes. Set `CLAUDE_CODE_USE_BEDROCK=1` for Bedrock or `CLAUDE_CODE_USE_VERTEX=1` for Vertex AI and configure the corresponding cloud credentials. The SDK routes calls through the appropriate provider automatically.
The Claude Agent SDK gives you the same tools that power Claude Code, wrapped in an async iterator you can run anywhere. The inbox triage agent above is a good starting point: narrow tool set, clear task, sub-two-minute runtime, and a Slack notification when it is done. If you want a structured path from your first agent to a full AI operating system for your business, the Claude Code Blueprint lays it out step by step.
Five interactive lessons. Install Claude Code, build your first automation, and deploy it live on the internet — all in under an hour. Free, no coding required.
Grab the Blueprint →