Claude Agent SDK Basics
9 examples to get you started with the Claude Agent SDK - 6 basic and 3 intermediate.
Prerequisites
- Install the Python package:
pip install claude-agent-sdk(TypeScript:npm install @anthropic-ai/claude-agent-sdk). - Set an API key in your environment:
export ANTHROPIC_API_KEY=sk-ant-.... - The SDK bundles its own CLI binary internally; you do not need to install Claude Code separately to use it.
- Examples below use
asynciosince the Python SDK'squery()is an async generator.
Basic Examples
1. Your First query()
The minimal shape: one prompt, default tools, streamed response.
import asyncio
from claude_agent_sdk import query
async def main():
async for message in query(prompt="What is 17 * 34?"):
print(message)
asyncio.run(main())query()returns an async iterator of messages, not a single string.- With no
optionspassed, the agent runs with the SDK's default tool set. - Each yielded message represents one step of the underlying tool-use loop, including the final answer.
Related: The Claude Agent SDK Mental Model - what's happening under this call
2. Picking a Model
Choose a specific model instead of the SDK default.
from claude_agent_sdk import query, AgentOptions
options = AgentOptions(model="claude-sonnet-5")
async for message in query(prompt="Summarize this changelog.", options=options):
print(message)AgentOptionsis where most per-call configuration lives.claude-sonnet-5is the current balanced default;claude-haiku-4-5trades quality for speed and cost.- Model choice does not change the loop's mechanics, only which model makes each decide step.
3. Scoping Tool Access
Restrict which built-in tools the agent can call.
from claude_agent_sdk import query, AgentOptions
options = AgentOptions(allowed_tools=["file_edit"])
async for message in query(
prompt="Fix the typo in README.md",
options=options,
):
print(message)allowed_toolsis an explicit allowlist; anything not listed is unavailable to the loop.- Scoping down to just
file_editmeans this agent cannot run bash commands or fetch the web, even if it wanted to. - Start narrow and widen only when a task genuinely needs more.
Related: Enabling File Edit, Bash, and Web Tools in the Agent SDK - full tool scoping guide
4. Reading the Working Directory
Point the agent at a specific project root.
from claude_agent_sdk import query, AgentOptions
options = AgentOptions(
cwd="/path/to/project",
allowed_tools=["file_edit", "bash"],
)
async for message in query(prompt="List failing tests.", options=options):
print(message)cwdscopes file and bash operations to a specific directory tree.- Setting
cwdexplicitly avoids surprises when the SDK runs from a different process working directory. - Combine with
allowed_toolsso the agent can both inspect and act on that project.
5. Streaming Text as It Arrives
Print only the assistant's text content instead of every message type.
from claude_agent_sdk import query
async for message in query(prompt="Explain what this repo does."):
if message.get("type") == "text":
print(message["text"], end="", flush=True)- The message stream mixes text, tool-call, and tool-result events; filtering by
typegets you just the prose. - Streaming lets you show progress in a CLI or UI instead of waiting for the whole loop to finish.
- Exact message shapes are documented in the SDK reference; treat
typeas the primary discriminator.
6. A Synchronous One-Shot Helper
Wrap query() for callers that don't want to deal with async iteration.
import asyncio
from claude_agent_sdk import query
def ask(prompt: str) -> str:
async def _run():
chunks = []
async for message in query(prompt=prompt):
if message.get("type") == "text":
chunks.append(message["text"])
return "".join(chunks)
return asyncio.run(_run())
print(ask("Give me a one-sentence summary of asyncio."))- Useful for scripts or notebooks that just want a final string back.
- This pattern discards intermediate tool-call events; use the raw stream when you need to show or log them.
- Production code usually keeps the async form so it can run inside an existing event loop.
Intermediate Examples
7. Combining Tools with a Permission Mode
Enable multiple built-in tools while requiring approval on risky ones.
from claude_agent_sdk import query, AgentOptions
options = AgentOptions(
allowed_tools=["file_edit", "bash", "web_search"],
permission_mode="default", # pauses before destructive actions
)
async for message in query(
prompt="Investigate the failing CI run and propose a fix.",
options=options,
):
print(message)permission_mode="default"keeps the loop's tool-use decisions intact but inserts an approval gate before destructive calls.- Three tools are enabled together here because the task genuinely spans reading (bash), fixing (file_edit), and researching (web_search).
- This is the shape most "investigate and fix" agents take.
Related: Adding Human-in-the-Loop Checkpoints to an Agent SDK Workflow - approval gates in depth
8. Resuming a Session
Continue a prior run instead of starting from a blank context.
from claude_agent_sdk import query, AgentOptions
first = query(prompt="Start reviewing src/orders/", options=AgentOptions())
session_id = None
async for message in first:
if message.get("type") == "session_start":
session_id = message["session_id"]
# later, possibly in a new process
resume_options = AgentOptions(resume=session_id)
async for message in query(prompt="Continue where you left off.", options=resume_options):
print(message)- The session identifier captures conversation and tool-result history from the first run.
- Passing it via
resumeon a later call continues the loop with that history already in context. - This is what makes long-running, multi-step agent tasks practical across separate process invocations.
Related: Persisting Sessions Across Runs with the Claude Agent SDK - storage and resume patterns
9. Delegating a Piece of Work to a Subagent
Spin off an isolated child agent for one part of a larger task.
from claude_agent_sdk import query, AgentOptions, SubagentConfig
options = AgentOptions(
allowed_tools=["file_edit", "bash"],
subagents=[
SubagentConfig(
name="test-runner",
allowed_tools=["bash"],
description="Runs the test suite and reports failures only.",
)
],
)
async for message in query(
prompt="Use the test-runner subagent to check if the suite passes, then fix any failures.",
options=options,
):
print(message)- The subagent gets its own tool scope (
bashonly) and its own isolated context, separate from the parent's. - The parent agent decides when to invoke the subagent, the same way it decides to call any other tool.
- Use this when a subtask's intermediate reasoning would otherwise clutter the parent's context.
Related: Delegating Work to Subagents in the Claude Agent SDK - parallelizing independent workstreams
Stack versions: Written against the Claude model lineup current as of ~June 2026 - Claude Fable 5, Claude Opus 4.8, Claude Sonnet 5 (the default), and Claude Haiku 4.5 - and the Claude Agent SDK (latest release, Python and TypeScript). Model names, SDK versions, and pricing move quickly - verify current specifics at platform.claude.com/docs before relying on them.