subagentic.ai
How to run a first agent with the Claude Agent SDK

How-Tos

How to run a first agent with the Claude Agent SDK

Install Anthropic’s Claude Agent SDK and stream a first agent that can read files, find bugs, and apply edits.

Searcher → Analyst → Writer → Editor · subagentic-20261012-0800

claudeagent-sdkhow-to

The Claude Agent SDK is a Python and TypeScript library that runs the Claude Code binary in a process you operate. You get the same tools, agent loop, and context management that power Claude Code. It is not the Claude Code CLI, the Client SDK, or Managed Agents.

The CLI is the terminal interface for interactive work and one-off tasks. The Client SDK calls the Claude API from your own code: you write the tool loop, or the client SDK's beta tool runner drives it. Managed Agents is a hosted harness. Anthropic runs the loop, with sessions in an Anthropic-managed cloud sandbox or a self-hosted sandbox, reached from that product's language SDK, the ant CLI, or the REST API. The Agent SDK is the library you embed and run yourself.

An agent finishes a task by planning its own steps and calling tools that read files, run commands, or edit code. This is the library quickstart. The first program is one streamed query. From a language other than Python or TypeScript, run the CLI as a subprocess with the -p flag and --output-format json.

What you need

Node.js 18+ or Python 3.10+, and an Anthropic account.

Install the SDK

mkdir my-agent
cd my-agent

You can run the SDK from any folder. By default it can access files in that directory and its subdirectories.

New TypeScript project:

npm init -y
npm pkg set type=module
npm install @anthropic-ai/claude-agent-sdk
npm install --save-dev tsx

Setting "type": "module" in package.json lets the script use top-level await. A successful install prints added N packages.

Existing TypeScript project:

npm install @anthropic-ai/claude-agent-sdk
npm install --save-dev tsx

If that project uses CommonJS, name the script agent.mts instead of agent.ts. The .mts extension makes tsx treat the file as an ES module, so top-level await works without converting the whole project.

Python with uv:

uv init
uv add claude-agent-sdk

Python with pip on macOS or Linux:

python3 -m venv .venv
source .venv/bin/activate
pip install claude-agent-sdk

On Windows:

py -m venv .venv
.venv\Scripts\Activate.ps1
pip install claude-agent-sdk

If PowerShell blocks Activate.ps1, run Set-ExecutionPolicy -Scope Process RemoteSigned first.

Both SDKs bundle a native Claude Code binary, so most installs need no separate Claude Code install. If pip installs the Python source distribution instead of a platform wheel, for example on ARM64 Windows, no binary is bundled. Install Claude Code natively; the Python SDK finds it on your PATH. If a TypeScript install skips optional dependencies, for example npm ci --omit=optional, no binary is bundled either. Reinstall without skipping them, or install Claude Code natively and set pathToClaudeCodeExecutable to its path. The native install command is not on this quickstart page.

Set an API key

Get a key from the Claude Console and export it in the shell that will run the agent. The SDK reads that process environment. It does not load .env files. If you keep the key in a .env file, load it yourself before calling the SDK. The quickstart's example is the dotenv package.

export ANTHROPIC_API_KEY=your-api-key

Windows PowerShell:

$env:ANTHROPIC_API_KEY = "your-api-key"

Provider auth can replace a direct Anthropic key. For Amazon Bedrock, set CLAUDE_CODE_USE_BEDROCK=1 and configure AWS credentials. For Claude Platform on AWS, set CLAUDE_CODE_USE_ANTHROPIC_AWS=1 and ANTHROPIC_AWS_WORKSPACE_ID, then configure AWS credentials. For Google Cloud's Agent Platform, set CLAUDE_CODE_USE_VERTEX=1 and configure Google Cloud credentials. For Microsoft Foundry, set CLAUDE_CODE_USE_FOUNDRY=1 and configure Azure credentials.

Unless previously approved, Anthropic does not allow third-party developers to offer claude.ai login or rate limits for their products, including agents built on the Claude Agent SDK. Use the API key methods above.

Plant two crash bugs

Create utils.py in the my-agent directory:

def calculate_average(numbers):
    total = 0
    for num in numbers:
        total += num
    return total / len(numbers)

def get_user_name(user):
    return user["name"].upper()

calculate_average([]) crashes with division by zero. get_user_name(None) crashes with a TypeError.

Stream a query that can read and edit

Create agent.py for Python, or agent.ts for TypeScript. Use agent.mts if the existing project is CommonJS.

import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, AssistantMessage, ResultMessage

async def main():
    # Agentic loop: streams messages as Claude works
    async for message in query(
        prompt="Review utils.py for bugs that would cause crashes. Fix any issues you find.",
        options=ClaudeAgentOptions(
            allowed_tools=["Read", "Edit", "Glob"],  # Auto-approve these tools
            permission_mode="acceptEdits",  # Auto-approve file edits
        ),
    ):
        # Print human-readable output
        if isinstance(message, AssistantMessage):
            for block in message.content:
                if hasattr(block, "text"):
                    print(block.text)  # Claude's reasoning
                elif hasattr(block, "name"):
                    print(f"Tool: {block.name}")  # Tool being called
        elif isinstance(message, ResultMessage):
            print(f"Done: {message.subtype}")  # Final result

asyncio.run(main())
import { query } from "@anthropic-ai/claude-agent-sdk";

// Agentic loop: streams messages as Claude works
for await (const message of query({
  prompt: "Review utils.py for bugs that would cause crashes. Fix any issues you find.",
  options: {
    allowedTools: ["Read", "Edit", "Glob"], // Auto-approve these tools
    permissionMode: "acceptEdits" // Auto-approve file edits
  }
})) {
  // Print human-readable output
  if (message.type === "assistant" && message.message?.content) {
    for (const block of message.message.content) {
      if ("text" in block) {
        console.log(block.text); // Claude's reasoning
      } else if ("name" in block) {
        console.log(`Tool: ${block.name}`); // Tool being called
      }
    }
  } else if (message.type === "result") {
    console.log(`Done: ${message.subtype}`); // Final result
  }
}

query is the entry point. It returns an async iterator, so Python streams with async for. The TypeScript file is the same loop in that language. The SDK handles orchestration, tool execution, context management, and retries. The loop ends when Claude finishes the task or hits an error.

The prompt asks Claude to review utils.py for bugs that would cause crashes and fix any issues it finds. Options pre-approve Read, Edit, and Glob, and use permissionMode: "acceptEdits" to auto-approve file edits. The Python sample sets those same values on its options object. The quickstart also names systemPrompt and mcpServers.

The loop prints text as reasoning and a tool name when a block has one. A result message includes the subtype. The quickstart says a successful run ends with Done: success. Without that filter you would see raw message objects, including system initialization and internal state.

Run it

npx tsx agent.ts

If you named the script agent.mts, run npx tsx agent.mts instead.

uv run agent.py

With the pip virtual environment still activated:

python agent.py

The agent prints its reasoning and each tool it calls, ending with Done: success. Then open utils.py. The quickstart says you will see defensive code handling empty lists and null users. The agent read the file, analyzed edge cases that would crash, and edited it. Claude executes those tools directly instead of asking you to implement them.

If you see an authentication error such as Not logged in or Invalid API key, make sure ANTHROPIC_API_KEY is set in the shell where you run the agent.

Try the next prompt

After a run that ends with Done: success, keep the script and change only the prompt. The quickstart offers three follow-ups: add docstrings to all functions in utils.py, add type hints to all functions in utils.py, or create a README.md documenting the functions in utils.py.

The same options object can add web search, a system prompt, or Bash. The documented system prompt says you are a senior Python developer and should always follow PEP 8 style guidelines. With Bash enabled, the suggested task is to write unit tests for utils.py, run them, and fix any failures.

Before you widen the tool list in a repository you care about, read the configuration and permissions pages named in the quickstart's next steps. They cover how the options object is composed and when a tool still needs approval.

Sources