Building Agents with the Claude Agent SDK

Photo by n3wjack on flickr
The Claude Agent SDK is Anthropic's library for building production AI agents on top of the same agent loop, built-in tools, and context management that power Claude Code. It ships for Python as claude-agent-sdk and for TypeScript as @anthropic-ai/claude-agent-sdk, and it handles the tool-execution loop for you instead of requiring you to implement it against the raw API.
With the raw API you implement the tool loop yourself: send a message, check the stop reason, execute the tool, and send the result back. The Agent SDK runs that loop internally, so you call query with a prompt and an allowed tool list, and Claude reads files, runs commands, and edits code autonomously while streaming messages back.
Use subagents when a task would otherwise fill your main agent's context with intermediate noise, such as exploring dozens of files during a full codebase review. Each subagent runs in its own fresh context and returns only a final summary, and because subagents can run concurrently, independent subtasks finish in parallel rather than one after another.
Yes. Passing an allowed tools list pre-approves only those tools, and a subagent's own tools field can restrict it further, for example to Read, Grep, and Glob for a read-only reviewer. Note that an allow list does not shrink what the bypassPermissions mode approves, since that mode auto-approves every tool call regardless of what was listed.
It can be, provided you apply the same operational discipline you would for any automated system with shell and file access: pin the model and SDK version, log every tool call to a durable audit trail, add explicit deny rules for destructive commands, and cap agentic turns on unattended runs so a confused agent fails loudly instead of looping.

Photo by n3wjack on flickr
Most teams that try to build an AI agent from scratch end up rebuilding the same plumbing: a loop that sends a prompt to the model, executes whatever tool calls come back, feeds the results back in, and repeats until the model produces a final answer. The Claude Agent SDK skips that step. It is the same agent loop, tool execution, and context management that powers Claude Code, packaged as a library you can call from Python or TypeScript.
This post is a practitioner's guide, not a marketing overview. It covers the parts that actually matter when you sit down to ship something: how the loop behaves, how to define and restrict tools, when subagents earn their complexity, how permission modes decide what runs without a prompt, and the operational details that separate a demo from a production ops agent.
With the raw Anthropic API, you implement the loop: send a message, check if the stop reason is tool use, execute the tool yourself, send the result back, and repeat. The Agent SDK inverts that. You call query with a prompt and a list of allowed tools, and Claude reads files, runs commands, and edits code autonomously, streaming messages back to you as it works.
Under the hood this is the exact harness that ships inside Claude Code: the same built-in tools, the same context management, and the same session model. That matters more than it sounds, because it means the agent already knows how to decide when to stop, when to ask a clarifying question, and when a task is actually done, instead of you hand-rolling termination heuristics.
import { query } from "@anthropic-ai/claude-agent-sdk";
for await (const message of query({
prompt: "Find and fix the failing test in payments.ts",
options: {
allowedTools: ["Read", "Edit", "Bash", "Grep"],
},
})) {
if ("result" in message) console.log(message.result);
}The example below is close to the smallest useful agent you can write. It grants Read, Edit, Bash, and Grep, then lets the model figure out the rest: find the failing test, understand why it fails, and patch the code.
Start every new agent with a narrow allowed tool list, even during prototyping. It is much easier to notice a missing capability than to notice an agent quietly running commands you never intended to grant.
The SDK ships with the same built-in tools Claude Code uses day to day, so you rarely write a file-reading or shell-execution tool yourself. The set you will reach for most often in a coding or ops agent includes:
For anything outside that set, the SDK connects to external systems through the Model Context Protocol. Point it at an MCP server for a database, a browser automation tool, or an internal API, and its tools show up in the same tool list as the built-ins, with no separate integration code on your side.
A single long-running agent conversation accumulates everything it has ever done: every file it read, every command it ran, every intermediate result. For a focused bug fix that is fine. For a full codebase review, it means your main agent's context fills up with noise that has nothing to do with the final answer.
const options = {
allowedTools: ["Read", "Grep", "Glob", "Agent"],
agents: {
"code-reviewer": {
description: "Expert code reviewer for quality and security reviews.",
prompt: "Analyze code quality, flag security issues, suggest fixes.",
tools: ["Read", "Grep", "Glob"],
model: "sonnet",
},
"test-runner": {
description: "Runs and analyzes the test suite.",
prompt: "Run tests, report failures, and propose minimal fixes.",
tools: ["Bash", "Read", "Grep"],
},
},
};Subagents solve this by running in a fresh context of their own. The parent agent delegates a subtask, the subagent explores and works in isolation, and only its final summary comes back to the parent. Because each subagent can carry its own system prompt and its own restricted tool list, you can build a read-only code reviewer alongside a test runner that has shell access, and run both concurrently instead of one after another.
When the parent session runs in bypassPermissions or acceptEdits mode, every subagent it spawns inherits that same mode and cannot be locked down individually. A subagent with a looser system prompt than your main agent then gets the same unrestricted access. If you need one subagent tightly sandboxed, keep the parent session in a stricter mode instead of relying on the subagent's own tool list.
Every tool call the agent wants to make passes through a permission check before it executes. Allowed tool lists and deny rules are evaluated first, and whatever is left over falls through to the active permission mode. The four modes you will actually use in practice behave very differently:
| Mode | Behavior | When to use it |
|---|---|---|
| default | No auto-approvals; anything not explicitly allowed triggers your approval callback | Interactive sessions where a human is watching and approving |
| acceptEdits | File edits and filesystem operations are auto-approved; other tools still require normal permission checks | Fast iteration in an isolated working directory you already trust |
| plan | Claude explores and proposes a plan; file edits are never auto-approved, even with a matching allow rule | Code review workflows where changes need human sign-off before they land |
| bypassPermissions | Every tool call is approved automatically with no prompts, aside from explicit deny rules | Fully sandboxed, disposable environments only, never a shared machine |
The mistake worth calling out explicitly: an allowed tool list does not shrink what bypassPermissions can do. Naming only Read in your allow list while the mode is set to bypassPermissions still lets the agent run Bash, Write, and Edit, because the allow list only pre-approves tools, it does not restrict the ones you left out. If you need bypassPermissions but want a specific command blocked, use an explicit deny rule instead of trimming the allow list.
The gap between a working prototype and something you would actually run against production infrastructure is mostly about defaults, not features. A short checklist that has saved me from regret more than once:
None of this is exotic. It is the same operational discipline you would apply to any automated system that can run commands and edit files unattended, just applied to a system whose next action is chosen by a model instead of a fixed script.
The TypeScript package ships as @anthropic-ai/claude-agent-sdk on npm, and it bundles a native Claude Code binary as an optional dependency, so a fresh install does not require a separate Claude Code installation on the host.
The Agent SDK is not the right tool for every integration. It earns its keep specifically when the task benefits from autonomous multi-step tool use:
If your use case is a single prompt with a single expected response and no tool use, the plain Anthropic client SDK is simpler and has less surface area to secure. Reach for the Agent SDK when the value is in the loop itself, not just the model's output.