Anthropic's claude-agent-sdk: A Practical Walkthrough

CallMissed
·5 min readGuide

The claude-agent-sdk is Anthropic's productized version of the harness that powers Claude Code. It gives you the same agent loop, tool dispatch, and context-management mechanics, programmable in Python and TypeScript. If you've been wiring up tool-use loops by hand against the Messages API, this is the layer you've been re-implementing badly.

This walkthrough covers what's in it, when to use it, and the gotchas worth knowing before you commit.

What you actually get

The SDK bundles four things:

  • An agent loop. The same one Claude Code uses — model call → tool dispatch → result → model call, with smart context management (summarization, file-content tracking) baked in.
  • A tool registry. Define tools as Python functions or TypeScript objects; the SDK generates the schema and handles dispatch.
  • Hooks. Pre/post-tool-use hooks for permission gating, logging, and side effects. The hook system has expanded through 2025 to include event streaming and a defer permission decision the runtime understands. [Inference]
  • A bundled Claude Code binary (TypeScript) or installed package (Python). You don't have to install Claude Code separately; the SDK ships its agent runtime.
  • Setup

    Python

    bash
    pip install claude-agent-sdk

    The Python SDK latest release as of May 2026 includes hook event streaming and parity with the TypeScript SDK on permission decisions.

    TypeScript

    bash
    npm install @anthropic-ai/claude-agent-sdk

    The TypeScript SDK ships a native Claude Code binary as an optional dependency, so you don't need to install Claude Code separately.

    API key

    Set ANTHROPIC_API_KEY in your environment. Opus 4.7 (claude-opus-4-7) requires Agent SDK v0.2.111 or later — older SDK versions reject the model.

    A minimal agent

    Python:

    python
    from claude_agent_sdk import Agent, tool
    
    @tool
    def get_weather(city: str) -> str:
        """Return current weather for a city."""
        return f"Sunny, 72F in {city}"
    
    agent = Agent(
        model="claude-opus-4-7",
        system="You are a helpful weather assistant.",
        tools=[get_weather],
    )
    
    result = agent.run("What's the weather in Paris?")
    print(result.text)

    The SDK handles the multi-turn loop — tool call, result, follow-up — without you writing a step controller.

    TypeScript:

    typescript
    import { Agent, tool } from "@anthropic-ai/claude-agent-sdk";
    import { z } from "zod";
    
    const getWeather = tool({
      name: "get_weather",
      description: "Return current weather for a city.",
      schema: z.object({ city: z.string() }),
      handler: async ({ city }) => `Sunny, 72F in ${city}`,
    });
    
    const agent = new Agent({
      model: "claude-opus-4-7",
      system: "You are a helpful weather assistant.",
      tools: [getWeather],
    });
    
    const result = await agent.run("What's the weather in Paris?");
    console.log(result.text);

    Streaming

    Streaming is first-class:

    python
    async for event in agent.run_stream("Plan a trip to Lisbon"):
        if event.type == "text":
            print(event.text, end="", flush=True)
        elif event.type == "tool_use":
            print(f"[calling {event.name}]")

    Events come through as a typed union — text deltas, tool-use start, tool-result, and end-of-turn markers. Use this for any user-facing surface where time-to-first-token matters.

    Hooks

    The hook system is where the SDK earns its keep. A pre-tool-use hook can:

  • Block the call (return {permissionDecision: "deny"})
  • Approve it explicitly ("allow")
  • Defer to user confirmation ("defer")
  • python
    def gate_writes(event):
        if event.tool_name in ("write_file", "delete_file"):
            return {"permissionDecision": "defer"}
        return {"permissionDecision": "allow"}
    
    agent = Agent(
        ...,
        hooks={"pre_tool_use": gate_writes},
    )

    This is how Claude Code itself implements its permission model. You can build the same pattern for any sensitive tool — DB writes, money movement, anything that should be human-confirmed.

    Post-tool-use hooks fire after execution, ideal for logging into your observability backend or running tool-result validation.

    When to use claude-agent-sdk vs raw Messages API

    Use claude-agent-sdk when:

  • You need a multi-turn tool-use loop and don't want to write the controller
  • You want hooks for permission gating, logging, or side effects
  • You're building something Claude-Code-shaped (file edits, command exec, multi-step planning)
  • You want bundled context management (summarization, file tracking)
  • Use the raw Messages API when:

  • You have one or two tool calls and the loop is trivial
  • You need maximum control over the loop (custom retry, custom budgeting, custom turn-by-turn logging)
  • You're integrating into a framework that has its own loop (LangGraph, OpenAI Agents SDK with non-OpenAI backends)
  • You need provider-portability — calling Claude alongside other models through a unified abstraction
  • The split is similar to "stdlib HTTP vs requests / fetch" — both work, the higher level removes a lot of boilerplate but adds opinions.

    Gotchas

    A few sharp edges worth knowing:

  • Model version pinning. The SDK ships compat with specific model versions; using a model older than the SDK supports rejects with a clear error, but the reverse (new model, older SDK) silently degrades. Update both together.
  • Hook event streaming is opt-in via include_hook_events; without it you don't see hook events in the stream. Easy to miss.
  • The bundled Claude Code binary in TypeScript is an optional dependency — installs may skip it on systems without write access to global node_modules. Set the binary path explicitly if needed.
  • Context management is opinionated. The SDK summarizes when context gets tight; if your workflow depends on full transcripts, this can surprise you. Disable or override.
  • Frequently Asked Questions

    Is claude-agent-sdk just Claude Code under a different name?
    Roughly — the SDK exposes the same agent loop, tools, and context management that power Claude Code, programmable from your code. The Claude Code CLI uses the same primitives. The SDK is the productized version for embedding into your own apps.
    Can I use claude-agent-sdk without Claude Code installed separately?
    Yes. The TypeScript SDK ships a Claude Code binary as an optional dependency; the Python SDK includes the runtime in the package. You don't need a separate Claude Code install.
    How does it compare to the OpenAI Agents SDK?
    Both are productized agent loops with tool dispatch and lifecycle hooks. Claude Code conventions (file edits, command execution, permission gating) are first-class in claude-agent-sdk; OpenAI's SDK leans more on its handoff primitive. Pick whichever matches your model preference and shape of work.

    Related Posts