Skip to main content
Claude Code Tutorial: From First Command to Custom Workflows

The Claude Agent SDK: Building Agents Programmatically

The Claude Agent SDK exposes the same agentic engine that powers Claude Code as a Python and TypeScript library. Learn the core query() API, how it relates to Claude Code, and how to build production agents with full control over tools, hooks, and MCP servers.

Advanced18 minBy ToolDix Editorial

Learning objectives

  • Understand what the Claude Agent SDK is and how it differs from the Client SDK
  • Learn the core query() API shape in both Python and TypeScript
  • Build a minimal agent that reads, edits, and verifies code autonomously
  • Understand how permissions, hooks, MCP servers, and subagents work in the SDK
  • Know when to use the SDK vs. Claude Code CLI vs. the Client SDK

ToolDix original visual

Claude Code Tutorial practice loop
1

Frame

Name the outcome and constraints.

2

Build

Try one bounded workflow.

3

Review

Keep evidence, revise, and share.

What the Agent SDK is

The Claude Agent SDK is a Python and TypeScript library that exposes the same agentic engine that powers Claude Code. Instead of interacting with Claude Code via the CLI, you use the SDK to build agents programmatically and embed them in applications, scripts, CI/CD pipelines, or production services.

The SDK includes:

  • Built-in tools (Read, Write, Edit, Bash, Glob, Grep, WebSearch, WebFetch, Monitor)
  • The agentic loop (plan → act → observe, repeated until done)
  • Permissions and hooks (fine-grained control over what the agent can do)
  • MCP servers (connectors to databases, APIs, browsers)
  • Subagents (delegation to specialized workers)
  • Sessions and persistence (context maintained across turns or resumed later)

You do not need to implement the tool loop yourself. The SDK handles it. You provide the prompt, tools, and policy, and the SDK runs the agent.

SDK vs. CLI vs. Client SDK

ToolInterfaceAutonomyBest forComplexity
Claude Code CLIInteractive terminalClaude decides actions; you approve/redirectInteractive development; one-off tasksLow
Agent SDKPython or TypeScript libraryClaude autonomous; you set policy upfrontCI/CD pipelines; production agents; custom appsMedium
Anthropic Client SDKDirect API accessYou implement the loopFine-grained control; custom tool executionHigh

Quick rule:

  • Use Claude Code CLI when you're developing interactively
  • Use Agent SDK when you want to run agents unattended in production (CI, scripts, servers)
  • Use Client SDK when you need total control over the agent loop or custom tool execution

The core query() API shape

The SDK provides one main entry point: query(). It returns an async iterator of messages as Claude works.

Python API

import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions

async def main():
    async for message in query(
        prompt="Find and fix the bug in auth.py",
        options=ClaudeAgentOptions(
            allowed_tools=["Read", "Edit", "Bash"],
            permission_mode="acceptEdits"
        ),
    ):
        print(message)

asyncio.run(main())

The query() function is async and returns an async iterator. Each iteration yields a message as Claude thinks, calls tools, or reports results.

TypeScript API

import { query } from "@anthropic-ai/claude-agent-sdk";

for await (const message of query({
  prompt: "Find and fix the bug in auth.ts",
  options: {
    allowedTools: ["Read", "Edit", "Bash"],
    permissionMode: "acceptEdits"
  }
})) {
  console.log(message);
}

Same shape: async iterator, each message is a step in the agent's work.

ClaudeAgentOptions schema

The options object controls agent behavior. All fields are optional; defaults are sensible:

| Field | Type | Default | Description | | :--- | :--- | :--- | :--- | | allowed_tools (Python) allowedTools (TS) | string[] | All tools | Array of tool names to auto-approve (e.g., ["Read", "Bash"]). Unlisted tools fall through to permission mode. | | disallowed_tools (Python) disallowedTools (TS) | string[] | None | Tools to block entirely. MCP patterns supported (e.g., "mcp__*" blocks all MCP tools). | | permission_mode (Python) permissionMode (TS) | string | "default" | How to handle permission prompts: "acceptEdits", "plan", "dontAsk", "auto", "bypassPermissions", or "default" (requires callback). | | system_prompt (Python) systemPrompt (TS) | string | None | Custom system prompt prepended to Claude's instructions. | | mcp_servers (Python) mcpServers (TS) | object[] | None | MCP server configurations (e.g., {"playwright": {"command": "npx", "args": ["@playwright/mcp@latest"]}}) | | agents (Python) agents (TS) | object | None | Subagent definitions; see SDK subagents guide. | | skills (Python) skills (TS) | string[] or "all" | Discovered | Which skills to enable (from .claude/skills/). | | resume (Python) resume (TS) | string | None | Session ID to resume (for multi-turn or continuation). | | cwd (Python) cwd (TS) | string | Current dir | Working directory for the agent. | | max_turns (Python) maxTurns (TS) | number | No limit | Max turns before stopping. | | effort (Python) effort (TS) | string | "medium" | Reasoning effort: "low", "medium", "high", "xhigh", "max", or a number. |

The most important fields: allowed_tools, permission_mode, and optionally system_prompt and mcp_servers.

Production deployment patterns

Pattern 1: CI/CD pipeline

#!/bin/bash
python agent.py \
  --prompt "Run tests and report failures" \
  --allowed-tools Bash,Read,Grep \
  --permission-mode acceptEdits

The agent runs autonomously without interactive prompts.

Pattern 2: Webhook responder

from fastapi import FastAPI, WebhookPayload
from claude_agent_sdk import query, ClaudeAgentOptions

app = FastAPI()

@app.post("/fix-issue")
async def fix_github_issue(payload: WebhookPayload):
    async for message in query(
        prompt=f"Fix GitHub issue {payload.issue_id}",
        options=ClaudeAgentOptions(
            allowed_tools=["Read", "Edit", "Bash", "Agent"],
            permission_mode="acceptEdits",
            max_turns=20
        ),
    ):
        pass  # Run silently, report results at the end
    return {"status": "fixed"}

Pattern 3: Background job

import asyncio
from agent import run_codebase_audit

# Dispatch in background; user gets a result URL
asyncio.create_task(run_codebase_audit())

The agent runs without blocking the request.

Common mistake

Treating the Agent SDK as a direct replacement for Claude Code CLI. The SDK is powerful but requires you to handle edge cases, error recovery, and timeout logic yourself. For interactive work, the CLI is simpler. For production automation, the SDK is the right choice.

Also, confusing the Agent SDK with the Client SDK (Anthropic's low-level message API). The Client SDK requires you to implement the tool loop and handle all orchestration. The Agent SDK does this for you, making production agents much simpler to build.

Sources and license context

These references informed the lesson. ToolDix adds its own explanation, workflow, and practice rather than reproducing source material. Every link below leaves ToolDix and opens the publisher's own site in a new tab.

Keep going

Read these next on ToolDix.

Original lessons that build on what you just read.