Claude Code Agent SDK: The Complete Beginner's Guide to Building AI Agents (2026)

Learn step by step how to create autonomous AI agents with the Claude Code Agent SDK. This beginner's guide includes practical code examples, from simple chatbots to complex agents with tools, memory, and subagents.

Claude Code Agent SDK: The Complete Beginner's Guide to Building AI Agents (2026)

Claude Code Agent SDK: The Complete Beginner's Guide to Building AI Agents (2026)

Want to build your first AI agent but don't know where to start? Anthropic's Claude Code Agent SDK makes it possible — even without deep programming knowledge.

In this comprehensive guide, we'll walk you through step by step how to create autonomous AI agents capable of handling complex tasks independently.


What You'll Learn in This Guide

  • What AI agents are and how they differ from chatbots
  • How the Claude Code Agent SDK works
  • Practical code examples for your first agent
  • Tools, sub-agents, and MCP integration
  • Best practices for production-ready agents

What Is an AI Agent? (And Why Is It Different from ChatGPT?)

Before we dive into code, let's clarify a fundamental concept: What makes an AI agent different from a regular chatbot?

Chatbot vs Agent

FeatureChatbot (e.g., ChatGPT)AI Agent
InteractionQuestion → AnswerGoal → Autonomous execution
ExecutionSingle requestLoops until goal is reached
ToolsLimitedInfinitely extensible
AutonomyNoneIndependent decisions

A chatbot answers your questions. An AI agent works autonomously toward a goal, using various tools and making its own decisions along the way.

The Agent Loop Pattern

Every AI agent follows a fundamental pattern — the famous Agent Loop:

┌─────────────────────────────────────────────────────────────┐
│                    AGENT LOOP PATTERN                        │
├─────────────────────────────────────────────────────────────┤
│  1. GATHER CONTEXT                                          │
│     └─▶ Understand the task, read relevant data             │
│                                                             │
│  2. EXECUTE AN ACTION                                       │
│     └─▶ Use tools, perform operations                       │
│                                                             │
│  3. VERIFY RESULTS                                          │
│     └─▶ Did the action succeed?                             │
│                                                             │
│  4. REPEAT                                                  │
│     └─▶ Until the goal is reached                           │
└─────────────────────────────────────────────────────────────┘

Example: You ask an agent to plan a trip. The agent:

  1. Gathers context: Asks for date, budget, preferences
  2. Executes actions: Searches for flights, hotels, activities
  3. Verifies: Does everything fit the budget? Are the schedules compatible?
  4. Repeats: Until a complete travel plan is ready

What Is the Claude Code Agent SDK?

The Claude Code Agent SDK is the same framework Anthropic uses internally for Claude Code — their powerful coding assistant.

It provides everything you need to build production-ready AI agents:

Key SDK Features

FeatureDescription
Automatic Context CompressionIntelligently manages large context windows
Tool EcosystemFile operations, code execution, web search
Permission ControlsGranular control over agent actions
MCP ExtensibilityIntegration of external services via Model Context Protocol
Sub-agentsDelegation to specialized sub-agents
Hook SystemEvent-driven workflows

Why Choose the Claude Code Agent SDK?

  1. Battle-tested in production: The same system powering Claude Code
  2. Minimal boilerplate: Less code, more functionality
  3. Built-in tools: File operations, Bash, Web ready out of the box
  4. MCP native: Seamless integration with Model Context Protocol

Quick Start: Installation and Setup

Prerequisites

Step 1: Install the SDK

# Install with pip
pip install claude-agent-sdk

# Or with uv (recommended for faster installation)
uv pip install claude-agent-sdk

Step 2: Configure the API Key

# Set as environment variable
export ANTHROPIC_API_KEY="sk-ant-..."

# Or in a .env file
echo "ANTHROPIC_API_KEY=sk-ant-..." > .env

Step 3: Test the First Connection

from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions

async def test_connection():
    options = ClaudeAgentOptions(
        model="sonnet",  # Claude Sonnet 4
        system_prompt="You are a helpful assistant."
    )
    
    async with ClaudeSDKClient(options=options) as client:
        await client.query("Say hello!")
        async for message in client.receive_response():
            print(message)

# Run
import asyncio
asyncio.run(test_connection())

Practical Example 1: Simple Q&A Agent

Let's start with the simplest agent — one that answers questions:

from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions
from claude_agent_sdk.types import TextBlock
import asyncio

SYSTEM_PROMPT = """You are a friendly assistant that answers questions. 
Be precise and helpful."""

async def simple_qa_agent():
    options = ClaudeAgentOptions(
        model="sonnet",
        system_prompt=SYSTEM_PROMPT,
        permission_mode="acceptEdits"  # Allows read operations
    )
    
    async with ClaudeSDKClient(options=options) as client:
        print("🤖 Q&A Agent ready! (Type 'exit' to quit)\n")
        
        while True:
            user_input = input("You: ").strip()
            
            if user_input.lower() in ['exit', 'quit']:
                print("Goodbye!")
                break
            
            await client.query(user_input)
            
            print("Agent: ", end="")
            async for message in client.receive_response():
                if hasattr(message, 'content'):
                    for block in message.content:
                        if isinstance(block, TextBlock):
                            print(block.text, end="")
            print("\n")

if __name__ == "__main__":
    asyncio.run(simple_qa_agent())

What this code does:

  1. Creates a client with a system prompt
  2. Starts an interactive loop
  3. Sends user input to Claude
  4. Returns the response via streaming

Practical Example 2: Agent with Memory

An agent with conversation memory can remember previous messages:

from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions
from claude_agent_sdk.types import TextBlock
import asyncio

SYSTEM_PROMPT = """You are an assistant with memory. 
You remember everything that has been said in this conversation.
Reference previous statements when relevant."""

async def memory_agent():
    options = ClaudeAgentOptions(
        model="sonnet",
        system_prompt=SYSTEM_PROMPT,
        permission_mode="acceptEdits",
        # The SDK automatically manages conversation history!
    )
    
    async with ClaudeSDKClient(options=options) as client:
        print("🧠 Memory Agent ready!\n")
        print("Tip: Ask questions related to previous answers.\n")
        
        while True:
            user_input = input("You: ").strip()
            
            if not user_input:
                continue
                
            if user_input.lower() == 'exit':
                break
            
            await client.query(user_input)
            
            print("Agent: ", end="")
            async for message in client.receive_response():
                if hasattr(message, 'content'):
                    for block in message.content:
                        if isinstance(block, TextBlock):
                            print(block.text, end="", flush=True)
            print("\n")

if __name__ == "__main__":
    asyncio.run(memory_agent())

Test the memory:

You: My name is Max.
Agent: Hello Max! Nice to meet you.

You: What's my name?
Agent: Your name is Max — you just introduced yourself!

Practical Example 3: Agent with Tools

This is where it gets interesting! Agents with tools can perform real actions:

from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions
from claude_agent_sdk.types import TextBlock, ToolUseBlock
import asyncio

SYSTEM_PROMPT = """You are a research assistant with access to tools.
Use the available tools to accomplish tasks:

- WebFetch: Retrieves content from web pages
- Read: Reads local files
- Grep: Searches for patterns in files
- Glob: Finds files by patterns

Always explain which tool you're using and why."""

async def tool_agent():
    options = ClaudeAgentOptions(
        model="sonnet",
        system_prompt=SYSTEM_PROMPT,
        permission_mode="acceptEdits",
        allowed_tools=[
            "WebFetch",  # Fetch web content
            "Read",      # Read files
            "Grep",      # Search text
            "Glob",      # Find files
        ]
    )
    
    async with ClaudeSDKClient(options=options) as client:
        print("🔧 Tool Agent ready!")
        print("Commands: 'search [URL]', 'find [file]', etc.\n")
        
        while True:
            user_input = input("You: ").strip()
            
            if user_input.lower() == 'exit':
                break
            
            await client.query(user_input)
            
            async for message in client.receive_response():
                if hasattr(message, 'content'):
                    for block in message.content:
                        if isinstance(block, TextBlock):
                            print(f"Agent: {block.text}")
                        elif isinstance(block, ToolUseBlock):
                            print(f"🛠️ Using tool: {block.name}")
                            print(f"   Parameters: {block.input}")
            print()

if __name__ == "__main__":
    asyncio.run(tool_agent())

Available Built-in Tools

ToolFunctionExample
ReadRead filesRead("config.json")
WriteWrite filesWrite("output.txt", content)
EditEdit filesEdit(file, old, new)
GlobSearch for filesGlob("**/*.py")
GrepSearch for textGrep("TODO", "src/")
BashExecute commandsBash("npm install")
WebFetchFetch web contentWebFetch(url, prompt)

Practical Example 4: Autonomous Travel Planner Agent

Now let's build a fully autonomous agent:

from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions
from claude_agent_sdk.types import TextBlock, ToolUseBlock, ToolResultBlock
import asyncio
import json

TRAVEL_SYSTEM_PROMPT = """You are an autonomous travel planning agent.

YOUR GOAL: Create a complete travel plan based on the user's needs.

YOUR WORKFLOW:
1. Collect all necessary information (date, budget, preferences)
2. Research options with WebFetch
3. Create a structured travel plan
4. Present the plan and ask for feedback

IMPORTANT:
- FIRST ask for missing information
- Use WebFetch for current information
- Create a clear, structured plan
- Offer alternatives

ALWAYS start with a friendly greeting and ask about the destination."""

async def travel_planner_agent():
    options = ClaudeAgentOptions(
        model="sonnet",
        system_prompt=TRAVEL_SYSTEM_PROMPT,
        permission_mode="acceptEdits",
        allowed_tools=["WebFetch", "Read", "Write"],
        max_turns=20  # Allows longer agent loops
    )
    
    async with ClaudeSDKClient(options=options) as client:
        print("✈️ Travel Planner Agent started!")
        print("=" * 50)
        
        # Initial greeting from the agent
        await client.query("Start travel planning for a new client.")
        
        async for message in client.receive_response():
            if hasattr(message, 'content'):
                for block in message.content:
                    if isinstance(block, TextBlock):
                        print(f"Agent: {block.text}")
        print()
        
        # Interactive loop
        while True:
            user_input = input("You: ").strip()
            
            if user_input.lower() in ['exit', 'done', 'thanks']:
                print("Agent: You're welcome! Have a great trip! 🌍✨")
                break
            
            await client.query(user_input)
            
            async for message in client.receive_response():
                if hasattr(message, 'content'):
                    for block in message.content:
                        if isinstance(block, TextBlock):
                            print(f"Agent: {block.text}")
                        elif isinstance(block, ToolUseBlock):
                            print(f"🔍 Searching: {block.name}...")
            print()

if __name__ == "__main__":
    asyncio.run(travel_planner_agent())

Advanced Features: MCP Integration

The Model Context Protocol (MCP) enables integration with external services:

Including MCP Servers

from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions

# MCP server configuration
MCP_CONFIG = {
    "utils": {
        "command": "npx",
        "args": ["-y", "mcp-remote", "https://your-mcp-server.com/api"]
    }
}

async def mcp_agent():
    options = ClaudeAgentOptions(
        model="sonnet",
        system_prompt="You have access to MCP tools for extended functionality.",
        permission_mode="acceptEdits",
        allowed_tools=[
            "WebFetch",
            "mcp__utils__save_note",   # MCP tools are prefixed
            "mcp__utils__find_note",
        ],
        mcp_servers=MCP_CONFIG
    )
    
    async with ClaudeSDKClient(options=options) as client:
        await client.query("Create a note with the title 'Important'")
        # ...

Creating Your Own MCP Server

# mcp_server.py - Simple MCP server
from mcp import Server

server = Server("my-tools")

@server.tool(name="save_note")
async def save_note(title: str, content: str) -> dict:
    """Saves a note."""
    # Your logic here
    return {"status": "success", "id": "note_123"}

@server.tool(name="find_note")
async def find_note(pattern: str) -> dict:
    """Finds notes by pattern."""
    # Your logic here
    return {"notes": [...]}

if __name__ == "__main__":
    import asyncio
    asyncio.run(server.run())

Sub-agents: Specialized Agents

For complex tasks, you can use sub-agents — specialized agents that handle subtasks:

from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions

ORCHESTRATOR_PROMPT = """You are a coordinator that delegates tasks to 
specialized sub-agents:

- Research Agent: For information gathering
- Writing Agent: For content creation
- Analysis Agent: For data analysis

Delegate tasks according to their type."""

async def orchestrator_agent():
    options = ClaudeAgentOptions(
        model="sonnet",
        system_prompt=ORCHESTRATOR_PROMPT,
        permission_mode="acceptEdits",
        allowed_tools=["SubAgent", "Read", "Write"],
        subagents_enabled=True  # Enables sub-agents
    )
    
    async with ClaudeSDKClient(options=options) as client:
        await client.query(
            "Research the latest AI trends and create a report."
        )
        # The agent automatically delegates to sub-agents

When to Use Sub-agents?

SituationRecommendation
Simple, linear tasks❌ No sub-agent needed
Parallel, independent tasks✅ Use sub-agents
Specialized expertise required✅ Use sub-agents
Long, complex workflows✅ Use sub-agents

Hooks: Event-Driven Workflows

Hooks enable automated actions on specific events:

from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions, HookMatcher

# Define hook function
async def log_tool_usage(event):
    """Logs every tool usage."""
    print(f"📝 Log: Tool '{event.tool_name}' was called")
    return True  # Allow execution

async def block_dangerous_commands(event):
    """Blocks dangerous Bash commands."""
    dangerous = ['rm -rf', 'sudo', 'chmod 777']
    if any(cmd in str(event.arguments) for cmd in dangerous):
        print("⚠️ Dangerous command blocked!")
        return False  # Block execution
    return True

async def hook_agent():
    options = ClaudeAgentOptions(
        model="sonnet",
        system_prompt="You are an assistant with security hooks.",
        permission_mode="acceptAll",
        allowed_tools=["Bash", "Write", "Read"],
        hooks={
            "PreToolUse": [
                HookMatcher(hooks=[log_tool_usage]),
                HookMatcher(
                    tool_name="Bash",
                    hooks=[block_dangerous_commands]
                )
            ]
        }
    )
    
    async with ClaudeSDKClient(options=options) as client:
        # ...

Hook Types

HookWhen TriggeredUse Case
PreToolUseBefore tool executionValidation, logging
PostToolUseAfter tool executionPost-processing, alerts
NotificationOn important eventsNotifications
StopAt session endCleanup, reporting

Best Practices for Production-Ready Agents

1. Clear System Prompts

# ❌ Bad: Vague instructions
SYSTEM_PROMPT = "Be helpful."

# ✅ Good: Clear role, boundaries, and behavior
SYSTEM_PROMPT = """You are a customer service agent for TechCorp.

YOUR ROLE:
- Answer questions about our products
- Escalate complex requests to humans
- Document all interactions

BOUNDARIES:
- No price negotiation
- No technical changes without approval
- When in doubt: Ask

BEHAVIOR:
- Friendly and professional
- Respond in the customer's language
- Summarize complex topics"""

2. Define Permissions Granularly

# ❌ Bad: Allow everything
permission_mode = "acceptAll"

# ✅ Good: Only allow necessary tools
permission_mode = "acceptEdits"
allowed_tools = ["Read", "WebFetch"]  # Only what's truly needed

3. Implement Error Handling

async def resilient_agent():
    max_retries = 3
    
    for attempt in range(max_retries):
        try:
            async with ClaudeSDKClient(options=options) as client:
                await client.query(prompt)
                async for message in client.receive_response():
                    # Processing
                    pass
                break  # Success, exit loop
                
        except RateLimitError:
            wait_time = 2 ** attempt  # Exponential backoff
            print(f"Rate limit hit. Waiting {wait_time}s...")
            await asyncio.sleep(wait_time)
            
        except Exception as e:
            print(f"Error: {e}")
            if attempt == max_retries - 1:
                raise

4. Context Management

# For long conversations: Compress context
options = ClaudeAgentOptions(
    model="sonnet",
    system_prompt=SYSTEM_PROMPT,
    # The SDK automatically compresses when needed
    max_context_tokens=100000,  # Maximum context size
)

Costs and Model Selection

Available Models

ModelAliasStrengthsCost
Claude Opus 4.5opusMaximum quality, complex tasks$$$
Claude Sonnet 4sonnetBest quality/cost ratio$$
Claude HaikuhaikuFast, affordable$

Model Recommendation by Use Case

Use CaseRecommended Model
Simple Q&AHaiku
General agentsSonnet
Code generationSonnet
Complex analysesOpus
Research agentsOpus

Summary: Your Path to Your First Agent

Checklist to Get Started

  • Python 3.10+ installed
  • Anthropic API key created
  • claude-agent-sdk installed
  • Simple Q&A agent tested
  • Agent with memory tried
  • Tools added
  • Autonomous agent built

Next Steps

  1. Experiment: Start with the simple Q&A agent
  2. Extend: Add tools as needed
  3. Specialize: Create domain-specific agents
  4. Scale: Use sub-agents for complex workflows
  5. Secure: Implement hooks for production environments

Frequently Asked Questions (FAQ)

What's the difference between Claude Code and the Claude Agent SDK?

Claude Code is Anthropic's complete coding assistant — a finished product you can use in your terminal.

The Claude Agent SDK is the underlying framework that lets you build your own agents for any use case. The SDK gives you the building blocks that also power Claude Code.

Do I need programming knowledge for the SDK?

Basic Python knowledge is helpful but not strictly required. You can follow the simple examples in this guide even without deep programming experience.

However, for production-ready agents, we recommend solid Python fundamentals.

How much does using the Claude Agent SDK cost?

Using the SDK itself is free. You only pay for API calls to Claude.

Sonnet costs approximately $3 per million input tokens and $15 per million output tokens (January 2026). For development and testing, we recommend starting with small contexts.

Can I use the SDK with other AI models?

The Claude Agent SDK is specifically optimized for Claude models.

For other models like GPT-4 or Gemini, alternative SDKs like OpenAI Agents SDK or Google ADK exist. However, the concepts (Agent Loop, Tools, Memory) are transferable.

How do I secure my agent for production use?

Three important steps:

  1. Set permission_mode to "manual" or "acceptEdits" instead of "acceptAll"
  2. Explicitly define allowed_tools with only the necessary tools
  3. Implement hooks for security controls and logging

For critical applications, add human approvals in the loop.


Additional Resources


This guide was created for developers and AI enthusiasts taking their first steps with AI agents. The Claude Code Agent SDK is constantly evolving — visit the official documentation for the latest updates.

Share article

Share: