> ## Documentation Index
> Fetch the complete documentation index at: https://docs.braintrust.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Claude Agent SDK

> Trace Claude Agent SDK runs in Braintrust to debug agent queries, tool calls, and multi-step reasoning

The [Claude Agent SDK](https://docs.claude.com/en/api/agent-sdk/) is Anthropic's official SDK for building production-ready AI agents with Claude. Braintrust traces Claude Agent SDK runs end-to-end, covering queries, tool executions, and multi-step reasoning.

**TypeScript**

## Setup

Install the Braintrust SDK alongside the Claude Agent SDK:

```bash pnpm theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
pnpm add braintrust @anthropic-ai/claude-agent-sdk zod
```

```bash npm theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
npm install braintrust @anthropic-ai/claude-agent-sdk zod
```

## Auto-instrumentation

To trace the Claude Agent SDK without wrapping it in your application code, run your app with Braintrust's import hook. The hook patches `query` on import, so agent queries, tool calls, and sub-agent runs are traced while you use the SDK as normal.

**1. Initialize Braintrust and run your agent**

```javascript title="trace-claude-agent-auto.js" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
import { query, tool, createSdkMcpServer } from "@anthropic-ai/claude-agent-sdk";
import { initLogger } from "braintrust";
import { z } from "zod";

initLogger({
  projectName: "claude-agent-example", // Replace with your project name
  apiKey: process.env.BRAINTRUST_API_KEY,
});

const calculator = tool(
  "calculator",
  "Performs basic arithmetic operations",
  {
    operation: z.enum(["add", "subtract", "multiply", "divide"]),
    a: z.number(),
    b: z.number(),
  },
  async ({ operation, a, b }) => {
    const results = { add: a + b, subtract: a - b, multiply: a * b, divide: a / b };
    return {
      content: [
        {
          type: "text",
          text: `The result of ${operation}(${a}, ${b}) is ${results[operation]}`,
        },
      ],
    };
  },
);

const result = query({
  prompt: "What is 15 multiplied by 7? Then subtract 5 from the result.",
  options: {
    model: "claude-sonnet-4-5-20250929",
    permissionMode: "bypassPermissions",
    mcpServers: {
      calculator: createSdkMcpServer({
        name: "calculator",
        version: "1.0.0",
        tools: [calculator],
      }),
    },
  },
});

for await (const message of result) {
  console.log(message);
}
```

**2. Run with the import hook**

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
node --import braintrust/hook.mjs trace-claude-agent-auto.js
```

The auto-instrumentation example uses plain JavaScript so `node --import` can run the file directly. The Braintrust APIs work the same in TypeScript projects. Compile your TypeScript to JavaScript and run the compiled file with the import hook, or [run TypeScript directly](https://docs.braintrust.dev/instrument/trace-llm-calls.md#auto-instrumentation) with a TypeScript loader.

> [!NOTE]
>
> If you're using a bundler, see [Trace LLM calls](https://docs.braintrust.dev/instrument/trace-llm-calls.md#auto-instrumentation) for plugin and loader setup.

## Manual instrumentation

To trace the Claude Agent SDK explicitly, wrap the SDK module with `wrapClaudeAgentSDK` and use the returned `query`, `tool`, and `createSdkMcpServer` functions. This example creates a calculator tool and traces a multi-step agent query.

```typescript title="claude-agent.ts" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
import { initLogger, wrapClaudeAgentSDK } from "braintrust";
import * as claudeSDK from "@anthropic-ai/claude-agent-sdk";
import { z } from "zod";

// Initialize Braintrust logging
initLogger({
  projectName: "claude-agent-example",
  apiKey: process.env.BRAINTRUST_API_KEY,
});

// Wrap the Claude SDK with Braintrust tracing
const { query, tool, createSdkMcpServer } = wrapClaudeAgentSDK(claudeSDK);

// Create a calculator tool
const calculator = tool(
  "calculator",
  "Performs basic arithmetic operations",
  {
    operation: z.enum(["add", "subtract", "multiply", "divide"]),
    a: z.number(),
    b: z.number(),
  },
  async (args: { operation: string; a: number; b: number }) => {
    console.log(`[Tool] Calculating: ${args.a} ${args.operation} ${args.b}`);

    let result = 0;
    switch (args.operation) {
      case "add":
        result = args.a + args.b;
        break;
      case "subtract":
        result = args.a - args.b;
        break;
      case "multiply":
        result = args.a * args.b;
        break;
      case "divide":
        if (args.b === 0) {
          return {
            content: [
              {
                type: "text",
                text: "Error: Division by zero",
              },
            ],
            isError: true,
          };
        }
        result = args.a / args.b;
        break;
    }

    return {
      content: [
        {
          type: "text",
          text: `The result of ${args.operation}(${args.a}, ${args.b}) is ${result}`,
        },
      ],
    };
  },
);

async function main() {
  console.log("Starting Claude Agent SDK example with Braintrust tracing...\n");

  try {
    // Query with mcp server for tool calls
    const result = query({
      prompt: "What is 15 multiplied by 7? Then subtract 5 from the result.",
      options: {
        model: "claude-sonnet-4-5-20250929",
        permissionMode: "bypassPermissions",
        mcpServers: {
          calculator: createSdkMcpServer({
            name: "calculator",
            version: "1.0.0",
            tools: [calculator],
          }),
        },
      },
    });

    // Stream the results
    for await (const message of result) {
      console.log(message);
    }

    console.log("\n\n✓ Example completed! Check Braintrust for tracing data.");
  } catch (error) {
    console.error("Error:", error);
    process.exit(1);
  }
}

main();
```

### Trace nested agent operations

To organize agent calls into parent-child traces, wrap coordinating functions with `wrapTraced`. Braintrust captures the hierarchical relationships, making multi-step workflows easy to follow in your logs.

```typescript title="nested-agents.ts" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
import { initLogger, wrapClaudeAgentSDK, wrapTraced } from "braintrust";
import * as claudeSDK from "@anthropic-ai/claude-agent-sdk";

initLogger({
  projectName: "nested-agents-example",
  apiKey: process.env.BRAINTRUST_API_KEY,
});

const { query } = wrapClaudeAgentSDK(claudeSDK);

// Wrapped function creates a child trace
const analyzeData = wrapTraced(
  async (data: string) => {
    const result = query({
      prompt: `Analyze this data and identify key patterns: ${data}`,
      options: {
        model: "claude-sonnet-4-5-20250929",
        permissionMode: "bypassPermissions",
      },
    });

    // Collect and return the analysis
    let analysis = "";
    for await (const message of result) {
      if (message.type === "result") {
        analysis = message.result;
      }
    }
    return analysis;
  },
  { name: "data-analyzer" },
);

// Parent function coordinates multiple operations
async function coordinatorWorkflow() {
  // This call creates a child trace under the parent
  const analysis = await analyzeData("Sales data: Q1=100k, Q2=150k, Q3=180k, Q4=200k");

  console.log("Analysis complete:", analysis);

  // In Braintrust logs, you'll see both operations
  // linked in a parent-child relationship
}

coordinatorWorkflow();
```

## What Braintrust traces

Braintrust captures the Claude Agent SDK span tree for each query:

* Agent run spans (`Claude Agent`), with the prompt as input, and the query options, turn count, and session ID as metadata.
* Run usage on agent run spans, for queries that don't resume an earlier session: token metrics and `estimated_cost` for every model the run used, including sub-agents, and the cost the Claude Agent SDK reports as `total_cost_usd` in metadata. With `includePartialMessages`, the token metrics and `estimated_cost` cover only the usage that model call spans didn't record. Requires v3.37.0 or later.
* Model call spans (`anthropic.messages.create`), with input messages, model, and assistant output; token metrics including prompt, completion, and cache read and creation tokens.
* Tool call spans (named by the tool, such as `calculator`), with tool input and output, tool name, tool call ID, and MCP server.
* Sub-agent spans (named by the sub-agent), with sub-agent metadata and token usage.
* Parent-child nesting under any enclosing Braintrust span.

## Resources

* [Claude Agent SDK documentation](https://docs.claude.com/en/api/agent-sdk/)
* [Anthropic API documentation](https://docs.anthropic.com/)

**Python**

## Setup

Install the Braintrust SDK alongside the Claude Agent SDK:

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
pip install braintrust claude-agent-sdk
```

## Auto-instrumentation

To trace the Claude Agent SDK alongside Braintrust's other supported libraries, call `braintrust.auto_instrument()` before importing the SDK, then use `claude_agent_sdk` as normal. Because auto-instrumentation patches the SDK on import, call it first.

```python title="claude_agent_auto.py" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
import asyncio
import os

import braintrust

braintrust.auto_instrument()
braintrust.init_logger(
    project="claude-agent-example",  # Replace with your project name
    api_key=os.environ.get("BRAINTRUST_API_KEY"),
)

# Import after auto_instrument() so the patched SDK is used
from claude_agent_sdk import ClaudeAgentOptions, ClaudeSDKClient

async def main() -> None:
    options = ClaudeAgentOptions(model="claude-sonnet-4-5-20250929")

    async with ClaudeSDKClient(options=options) as client:
        await client.query("What is 15 multiplied by 7? Then subtract 5 from the result.")
        async for message in client.receive_response():
            print(message)

asyncio.run(main())
```

## Manual instrumentation

To trace the Claude Agent SDK without auto-instrumenting other libraries, call `setup_claude_agent_sdk` instead. It patches the SDK's client, query, and MCP tool APIs, and initializes a logger for you. This example creates a calculator tool and traces a multi-step agent query.

```python title="claude_agent.py" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
#!/usr/bin/env python3

import asyncio
import os
from typing import Any

from braintrust.wrappers.claude_agent_sdk import setup_claude_agent_sdk
from claude_agent_sdk import ClaudeAgentOptions, ClaudeSDKClient, create_sdk_mcp_server, tool

# Setup claude_agent_sdk with braintrust tracing
setup_claude_agent_sdk(
    project="claude-agent-example",
    api_key=os.environ.get("BRAINTRUST_API_KEY"),
)

# Create a calculator tool
@tool(
    "calculator",
    "Performs basic arithmetic operations",
    {
        "operation": str,
        "a": float,
        "b": float,
    },
)
async def calculator(args: dict[str, Any]) -> dict[str, Any]:
    operation = args["operation"]
    a = float(args["a"])
    b = float(args["b"])

    print(f"[Tool] Calculating: {a} {operation} {b}")

    if operation == "add":
        result = a + b
    elif operation == "subtract":
        result = a - b
    elif operation == "multiply":
        result = a * b
    elif operation == "divide":
        if b == 0:
            return {"content": [{"type": "text", "text": "Error: Division by zero"}], "is_error": True}
        result = a / b
    else:
        result = 0

    return {"content": [{"type": "text", "text": f"The result of {operation}({a}, {b}) is {result}"}]}

async def main():
    print("Starting Claude Agent SDK example with Braintrust tracing...\n")

    try:
        # Create SDK MCP server with the calculator tool
        calculator_server = create_sdk_mcp_server(
            name="calculator",
            version="1.0.0",
            tools=[calculator],
        )

        options = ClaudeAgentOptions(
            model="claude-sonnet-4-5-20250929",
            permission_mode="bypassPermissions",
            mcp_servers={"calculator": calculator_server},
            allowed_tools=["mcp__calculator__calculator"],
        )

        # Use a persistent client session to enable custom MCP tools
        async with ClaudeSDKClient(options=options) as client:
            await client.query("What is 15 multiplied by 7? Then subtract 5 from the result.")
            async for message in client.receive_response():
                print(message)

        print("\n\n✓ Example completed! Check Braintrust for tracing data.")
    except Exception as error:
        print(f"Error: {error}")

asyncio.run(main())
```

### Trace nested agent operations

To organize agent calls into parent-child traces, decorate coordinating functions with `@traced`. Braintrust captures the hierarchical relationships, making multi-step workflows easy to follow in your logs.

```python title="nested_agents.py" theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
import asyncio
import os

from braintrust import traced
from braintrust.integrations.claude_agent_sdk import setup_claude_agent_sdk
from claude_agent_sdk import ClaudeAgentOptions, ClaudeSDKClient

setup_claude_agent_sdk(
    project="nested-agents-example",
    api_key=os.environ.get("BRAINTRUST_API_KEY"),
)

# Decorated function creates a child trace
@traced(name="data-analyzer")
async def analyze_data(data: str) -> str:
    options = ClaudeAgentOptions(
        model="claude-sonnet-4-5-20250929",
        permission_mode="bypassPermissions",
    )

    # Collect and return the analysis
    analysis = ""
    async with ClaudeSDKClient(options=options) as client:
        await client.query(f"Analyze this data and identify key patterns: {data}")
        async for message in client.receive_response():
            if type(message).__name__ == "ResultMessage":
                analysis = message.result
    return analysis

# Coordinator function orchestrates multiple operations
async def coordinator_workflow() -> None:
    # This call creates a child trace under the parent
    analysis = await analyze_data("Sales data: Q1=100k, Q2=150k, Q3=180k, Q4=200k")

    print("Analysis complete:", analysis)

    # In Braintrust logs, you'll see both operations
    # linked in a parent-child relationship

asyncio.run(coordinator_workflow())
```

## What Braintrust traces

Braintrust mirrors the Claude Agent SDK span tree for each run:

* Agent run spans (`Claude Agent`), with the conversation input and final result, plus run summary metadata (turn count, session ID, stop reason, cost, duration, and `verbatim_prompts` when verbatim prompt mode is enabled on Claude Agent SDK v0.2.158 or later).
* Sub-agent task spans (named by the task description or type), nested under the `Agent` tool call that started the sub-agent, with task metadata (task ID, session ID, status, and usage) and task output. Bundled Claude Code CLIs earlier than v2.1 name this tool `Task` and report no task status, so their task spans record only the tool call ID and sub-agent type.
* Model call spans (`anthropic.messages.create`), with the model, assistant output, token usage, and time-to-first-token.
* Tool call spans (named by the tool, such as `calculator`), with tool input and output, tool name, tool call ID, and MCP server.
* Hook spans (such as `PreToolUse hook`), with the hook input, event name, callback name, and output. The input keeps fields such as the tool name and input, the tool's `duration_ms`, and the `error` and `is_interrupt` fields of `PostToolUseFailure` hooks, and leaves out local paths such as `cwd` and `transcript_path`.
* Parent-child nesting under any enclosing Braintrust span.

## Resources

* [Claude Agent SDK documentation](https://docs.claude.com/en/api/agent-sdk/)
* [Anthropic API documentation](https://docs.anthropic.com/)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.