Claude Agent SDK: what it is and how to build your first agent
The Claude Agent SDK lets you embed Claude Code's agent loop in your own Python or TypeScript application. You call query() with a prompt and options; the SDK runs the loop (Claude calls tools, reads the results, decides the next step) and streams messages until the task is done. You control which tools run, how far the agent may go and what happens at each step.
What is the Claude Agent SDK?
The Claude Agent SDK gives you "the same tools, agent loop, and context management that power Claude Code, programmable in Python and TypeScript". Where the Claude API makes you write the tool loop yourself, the SDK runs it for you: Claude evaluates the prompt, calls tools, receives the results and repeats until the task is complete.
Under the hood both SDKs bundle a native Claude Code binary, so your agent inherits Claude Code's capabilities: built-in tools, permissions, hooks, subagents, sessions, MCP, skills and CLAUDE.md.
Install the Claude Agent SDK
You need Node.js 18 or later, or Python 3.10 or later, and an API key from the Claude Console.
bash
pip install claude-agent-sdk # Python
npm install @anthropic-ai/claude-agent-sdk # TypeScript
export ANTHROPIC_API_KEY=your-api-key
The SDK reads the key from the environment; it does not load .env files on its own. Amazon Bedrock, Google Cloud and Microsoft Foundry work through environment flags such as CLAUDE_CODE_USE_BEDROCK=1.
Your first agent with query()
query() is the entry point: it takes a prompt and options, and returns an async stream of messages. This agent reads a folder of support tickets and writes a summary, with read access and file edits pre-approved:
```python import asyncio from claude_agent_sdk import query, ClaudeAgentOptions, AssistantMessage, ResultMessage
async def main(): async for message in query( prompt="Read tickets/*.md and write a one-page summary of the top three complaints to summary.md", options=ClaudeAgentOptions( allowed_tools=["Read", "Glob", "Write"], # auto-approved permission_mode="acceptEdits", # file edits run without asking max_turns=20, # a safety cap ), ): if isinstance(message, AssistantMessage): for block in message.content: if hasattr(block, "name"): print(f"tool: {block.name}") elif isinstance(message, ResultMessage): print(message.subtype, message.total_cost_usd)
asyncio.run(main()) ```
The TypeScript version has the same shape: for await (const message of query({ prompt, options: { allowedTools, permissionMode, maxTurns } })), checking message.type === "result" at the end.
How the agent loop works
Every session follows the same cycle, and the SDK yields a message at each stage:
| Stage | Message the SDK yields |
|---|---|
| Session starts | SystemMessage with subtype init (session metadata) |
| Claude responds or asks for tools | AssistantMessage, one per content block |
| The SDK runs the tools | UserMessage with the tool results |
| Claude answers with no tool calls | A final AssistantMessage, then the ResultMessage |
One round trip of "Claude asks for tools, the SDK runs them, results go back" is a turn. The loop ends when Claude produces a response with no tool calls. The ResultMessage then carries the final text, token usage, cost and the session ID, and its subtype says how it ended:
| Subtype | Meaning |
|---|---|
success |
Claude finished the task; result holds the final text |
error_max_turns |
The max_turns cap stopped it |
error_max_budget_usd |
The max_budget_usd cap stopped it |
error_during_execution |
An error interrupted the loop |
Always check the subtype before reading result; only success has it.
Built-in tools
| Category | Tools |
|---|---|
| Files | Read, Edit, Write |
| Search | Glob, Grep |
| Execution | Bash |
| Web | WebSearch, WebFetch |
| Orchestration | Agent (subagents), Skill, AskUserQuestion, task tracking |
You can add your own tools as custom tool handlers or connect any MCP server. Read-only tools can run in parallel; tools that change state (Edit, Write, Bash) run one after another.
Permissions: allowed_tools does not mean "only these tools"
Three options decide whether a tool call runs:
allowed_toolsauto-approves the listed tools. Tools you don't list are still available; a call that needs approval falls through to the permission mode and yourcanUseToolcallback.disallowed_toolsblocks the listed tools, whatever else is set.permission_modesets the level of oversight.
| Mode | Behavior |
|---|---|
default |
Calls that need approval go to your canUseTool callback; no callback means deny |
acceptEdits |
File edits and common file commands run without asking |
plan |
Claude explores and plans; edits are never auto-approved |
dontAsk |
Never prompts: anything not pre-approved is denied |
auto |
A classifier reviews actions and allows or blocks each one |
bypassPermissions |
Runs all allowed tools; for isolated environments only |
This distinction is a classic trap: if the agent must never touch a tool, put it in disallowed_tools, not merely leave it out of allowed_tools.
Hooks: rules the model cannot skip
Hooks are callbacks in your own process at fixed points of the loop, so they cost no context and the model cannot talk its way past them.
| Hook | Fires | Typical use |
|---|---|---|
PreToolUse |
Before a tool runs | Validate input, block a dangerous call |
PostToolUse |
After a tool returns | Audit or reshape the output |
UserPromptSubmit |
When a prompt is sent | Add context |
Stop |
When the agent finishes | Check the result, save state |
SubagentStart / SubagentStop |
Around a subagent | Track parallel work |
PreCompact |
Before context compaction | Archive the full transcript |
For example, a support agent's rule "refunds over $100 need a human" belongs in a PreToolUse hook that rejects the refund call, not only in the system prompt.
Subagents and sessions
Subagents are separate agent instances your main agent spawns through the Agent tool. You define them in the agents option with a description (when to use it), a prompt and an optional tools list. Each starts with a fresh context: the only thing passed from the parent is the Agent tool's prompt, so include the file paths and decisions it needs. Only its final message comes back, which keeps your main context small.
Sessions keep the work: capture session_id from the ResultMessage, pass it as resume to continue with the full context restored, or fork a session to try a different approach without changing the original.
Context and compaction
Everything accumulates in the context window: the system prompt, tool definitions, CLAUDE.md, the conversation and every tool output. When the window nears its limit, the SDK compacts older history into a summary and emits a compact_boundary message. Instructions given only in the first prompt can be lost in that summary, so put persistent rules in CLAUDE.md, which is re-injected on every request.
The Agent SDK on the Claude Certified Architect exam
The Agent SDK is the backbone of Domain 1 (27%) and appears in three of the six scenarios: the customer support agent, the multi-agent research system and the developer productivity agent. Expect questions on the loop and its stop conditions, hooks for enforcement (task 1.5), subagent context passing (1.3) and sessions, resume and fork (1.7). One update since the guide: the tool that spawns subagents shows as Agent in tool_use blocks, not Task. Our CCAR-F study plan lists every domain.
More in all articles.
Sources: Agent SDK overview; Agent SDK quickstart; How the agent loop works; Subagents in the SDK; Agent SDK hooks; Claude Certified Architect Foundations exam guide v1.0, domain 1.
FAQ
What is the Claude Agent SDK?
A library for Python and TypeScript that gives you the same tools, agent loop and context management that power Claude Code, so you can build your own agents inside your own applications.
How do I install the Claude Agent SDK?
pip install claude-agent-sdk (Python 3.10 or later) or npm install @anthropic-ai/claude-agent-sdk (Node.js 18 or later), then set ANTHROPIC_API_KEY. Both packages bundle a native Claude Code binary, so most installs need nothing else.
Does allowed_tools restrict the agent to those tools?
No. allowed_tools auto-approves the listed tools. Tools not listed are still available, and calls that need approval fall through to the permission mode and the canUseTool callback. To block a tool, use disallowed_tools.
How do I stop an agent from running too long?
Set max_turns (tool-use round trips) or max_budget_usd (estimated spend). When a limit is hit, the ResultMessage comes back with the subtype error_max_turns or error_max_budget_usd.
What is the difference between the Agent SDK and Claude Code?
Claude Code is the finished tool you use in a terminal, IDE, desktop app or browser. The Agent SDK is the same engine as a library, for building your own agent product.