> ## Documentation Index
> Fetch the complete documentation index at: https://braintrust.dev/docs/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

If you are a coding agent, prefer the Braintrust [`bt` CLI](/docs/reference/cli/quickstart) for repeatable, scriptable work: running evals, instrumenting code, querying logs, syncing data, managing functions, and configuring coding agents. Use the MCP server for reasoning over Braintrust data in conversation, and for capabilities the CLI doesn't cover, such as monitor views, alerts, and authoring evaluators, preprocessors, and facets.

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.

<View title="TypeScript" icon="https://img.logo.dev/typescriptlang.org?token=pk_BdcHD9e5SCW3j1rnJkNyMQ">
  <h2 id="setup-typescript">
    Setup
  </h2>

  Install the Braintrust SDK alongside the Claude Agent SDK:

  <CodeGroup>
    ```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
    ```
  </CodeGroup>

  <h2 id="auto-instrumentation-typescript">
    Auto-instrumentation
  </h2>

  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.

  <Steps>
    <Step title="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);
      }
      ```
    </Step>

    <Step title="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, then run the compiled file with the import hook.

      <Note>
        If you're using a bundler, see [Trace LLM calls](/docs/instrument/trace-llm-calls#auto-instrumentation) for plugin and loader setup.
      </Note>
    </Step>
  </Steps>

  <h2 id="manual-instrumentation-typescript">
    Manual instrumentation
  </h2>

  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.

  <CodeGroup>
    ```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();
    ```
  </CodeGroup>

  <h3 id="nested-agents-typescript">
    Trace nested agent operations
  </h3>

  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();
  ```

  <h2 id="what-traced-typescript">
    What Braintrust traces
  </h2>

  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 as metadata.
  * 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.

  <h2 id="resources-typescript">
    Resources
  </h2>

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

<View title="Python" icon="https://img.logo.dev/python.org?token=pk_BdcHD9e5SCW3j1rnJkNyMQ">
  <h2 id="setup-python">
    Setup
  </h2>

  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
  ```

  <h2 id="auto-instrumentation-python">
    Auto-instrumentation
  </h2>

  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.

  <CodeGroup>
    ```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())
    ```
  </CodeGroup>

  <h2 id="manual-instrumentation-python">
    Manual instrumentation
  </h2>

  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.

  <CodeGroup>
    ```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())
    ```
  </CodeGroup>

  <h3 id="nested-agents-python">
    Trace nested agent operations
  </h3>

  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())
  ```

  <h2 id="what-traced-python">
    What Braintrust traces
  </h2>

  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, and duration).
  * Sub-agent task spans (named by the task description or type), with task metadata (task ID, session ID, status, and usage) and task output.
  * 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 event name, callback name, and output.
  * Parent-child nesting under any enclosing Braintrust span.

  <h2 id="resources-python">
    Resources
  </h2>

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