When a CLI script is not enough, the SDK lets you build custom agents on the same engine with full programmatic control.
The Claude Agent SDK (formerly the Claude Code SDK) is Claude Code as a library. It gives your program the same agent loop, built-in tools, context management, permissions, sessions, hooks, subagents, MCP support and skills, from Python or TypeScript. Compare the options:
- the CLI with
-p: quickest for scripts and CI, any language via a subprocess, - the Agent SDK: an agent inside your own application, with callbacks and typed messages,
- the plain Claude API client SDKs: you write the tool loop yourself.
In Python, install claude-agent-sdk (Python 3.10+); the TypeScript package is @anthropic-ai/claude-agent-sdk. The entry point query() is an async function that yields messages as the agent works: assistant text, tool use, tool results and a final result with cost. Options go in ClaudeAgentOptions:
allowed_tools: tools approved automatically (it does not remove others; usedisallowed_toolsfor that),permission_mode: for exampleacceptEditsordontAsk,cwd: the project directory,system_prompt,max_turns, MCP servers and more.
For two-way conversations, custom tools written as Python functions and hooks as callbacks, use ClaudeSDKClient. The SDK loads skills, commands and memory from .claude/ like the CLI does unless you configure otherwise.
Authentication for products you build uses an API key (ANTHROPIC_API_KEY) or a cloud provider, not a personal claude.ai login. Treat an SDK agent like any service with shell access: run it in a container, give it minimal tools and credentials, cap turns and budget, and log its actions.
Example
# pip install claude-agent-sdk (needs ANTHROPIC_API_KEY)
import anyio
from claude_agent_sdk import query, ClaudeAgentOptions, AssistantMessage, TextBlock
async def main():
options = ClaudeAgentOptions(
cwd="/srv/repos/billing",
allowed_tools=["Read", "Grep", "Glob", "Bash(pytest *)"],
permission_mode="dontAsk", # anything not allowed is denied
system_prompt="You are a careful maintenance bot. Never edit tests.",
max_turns=15,
)
async for message in query(prompt="Run pytest and summarize failures by root cause",
options=options):
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
print(block.text)
anyio.run(main)Remember
- The Agent SDK exposes Claude Code's loop, tools, permissions and hooks as a library
- Python: query() streams messages; configure with ClaudeAgentOptions
- allowed_tools auto-approves; it doesn't remove tools, so also set permission_mode or disallowed_tools
Watch out for
- Assuming allowed_tools is a whitelist that hides every other tool; unlisted tools fall through to the permission mode.