Skip to main content

Documentation Index

Fetch the complete documentation index at: https://laminar.sh/docs/llms.txt

Use this file to discover all available pages before exploring further.

Overview

Laminar is an open-source, OpenTelemetry-native observability platform for the Claude Agent SDK. Trace, debug, and monitor every agent turn, tool call, and subagent spawned by ClaudeSDKClient.query and the module-level query function. Self-host via Helm or use managed cloud. Claude Agent SDK (formerly Claude Code SDK) lets you call the same agent that powers Claude Code from your own code. It handles process management, tool execution, and model calls, and exposes a query function (TypeScript) and ClaudeSDKClient (Python) for driving a session. Laminar captures the full structure of each run: the root call, every model turn, each tool call, and every subagent spawned via the Agent tool. Nested subagents show up as child spans under the invocation that spawned them, so you can read the whole agent tree in one trace. What Laminar captures:
  • The root call (ClaudeSDKClient.query / module-level query) with the prompt you sent.
  • Every model turn with prompts, responses, token counts, latency, and cost.
  • Tool calls (Read, Write, Edit, Bash, Glob, Grep, WebSearch, custom MCP tools) with arguments and results.
  • Subagents spawned via the Agent tool as nested spans under the parent turn.

Getting started

1

Install

Ensure you are using @lmnr-ai/lmnr version 0.7.10 or higher.
npm install @lmnr-ai/lmnr@latest @anthropic-ai/claude-agent-sdk@latest
# or
pnpm add @lmnr-ai/lmnr@latest @anthropic-ai/claude-agent-sdk@latest
2

Set environment variables

export LMNR_PROJECT_API_KEY=your-laminar-project-api-key
export ANTHROPIC_API_KEY=your-anthropic-api-key
3

Wrap the query function

import { query as origQuery } from '@anthropic-ai/claude-agent-sdk';
import { Laminar } from '@lmnr-ai/lmnr';

Laminar.initialize();

// Wrap the original query function to capture every turn, tool call, and subagent.
const query = Laminar.wrapClaudeAgentQuery(origQuery);

async function run() {
  for await (const message of query({
    prompt: "Scan the current directory for TODOs and create a summary markdown file.",
  })) {
    // Messages stream in; Laminar records the full span tree.
  }
}
run();
query is an async generator. You must iterate it (or collect it) for the agent to run to completion. If you need the return value before initialization, the module-level instrumentClaudeAgentQuery(originalQuery) export is equivalent to Laminar.wrapClaudeAgentQuery.

See what happened in a trace

Open the trace in Laminar and you land on the transcript view: each turn reads as a conversation, with the prompt, the model’s response, tool calls inline with their inputs and outputs, and any subagents collapsed to their final output. A tree of span names tells you the shape of the run; the transcript tells you what actually happened.
Claude Agent SDK trace in Laminar, transcript view
More on the trace UX: Viewing traces.

Multi-agent runs

The Claude Agent SDK lets you define subagents programmatically with the agents option. Each subagent gets its own system prompt and tool allowlist, and the orchestrator invokes them via the Agent tool (formerly Task). In Laminar, every subagent invocation becomes a child span of the turn that spawned it, with its own LLM calls and tool calls nested underneath.
import { query as origQuery } from '@anthropic-ai/claude-agent-sdk';
import { Laminar } from '@lmnr-ai/lmnr';

Laminar.initialize();
const query = Laminar.wrapClaudeAgentQuery(origQuery);

for await (const _ of query({
  prompt: `Review fizzbuzz.py. Kick off three subagents in parallel:
1. researcher: summarize what the code does.
2. reviewer: flag bugs, naming, and missing edge cases.
3. test-runner: propose 3-5 unit tests.
Combine their findings into a short report.`,
  options: {
    allowedTools: ['Read', 'Glob', 'Grep', 'Agent'],
    agents: {
      researcher: {
        description: 'Summarizes what code does. Use for investigation and overview.',
        prompt: 'Read the code and describe in 3-5 bullets what it does, its inputs, and outputs.',
        tools: ['Read', 'Glob', 'Grep'],
      },
      reviewer: {
        description: 'Reviews code for quality, bugs, and maintainability.',
        prompt: 'Identify bugs, unclear naming, missing edge cases, and style issues. Respond with a numbered list.',
        tools: ['Read', 'Glob', 'Grep'],
      },
      'test-runner': {
        description: 'Designs unit tests. Use for test planning.',
        prompt: 'Propose 3-5 unit tests covering happy path and edge cases.',
        tools: ['Read', 'Glob', 'Grep'],
      },
    },
  },
})) {
  // stream through messages
}
Subagents are only invoked when Agent is in allowedTools / allowed_tools. Without it, the orchestrator cannot delegate and you’ll see a single-threaded trace.
The resulting trace renders each subagent as a branch under the turn that spawned it. Switch to tree view when you want to see the hierarchy at a glance:
Claude Agent SDK multi-agent trace in Laminar

Track outcomes with Signals

Traces answer what happened on this run. Signals answer the cross-trace question: how often does the agent edit a file it wasn’t asked to, when does a subagent exceed five tool calls, which reviewers miss null-check bugs. A Signal pairs a plain-language prompt with a JSON output schema. Laminar runs it live on new traces (Triggers) or backfills it across history (Jobs) and records a structured event every time it matches. From there you query, cluster, and alert on events across every trace.
Every new project ships with a Failure Detector Signal that categorizes issues on any trace over 1000 tokens. Open it from the Signals sidebar to see events as soon as your Claude Agent SDK traces arrive.

Query across traces

  • SQL editor for ad-hoc queries across traces, spans, signals, and evals.
  • SQL API for programmatic access from scripts and pipelines.
  • CLI (lmnr-cli sql query) for terminal-driven queries and piping JSON into shell tools or coding agents.
  • MCP server to query Laminar directly from Claude Code, Cursor, Codex, or any MCP-aware client.

Troubleshooting

  • Confirm LMNR_PROJECT_API_KEY is set in the same process that runs the SDK.
  • In TypeScript, make sure you’re iterating the async generator returned by query. The agent only runs while you consume messages.
  • In Python, claude-agent-sdk must be importable when Laminar.initialize() runs. Install it with pip install claude-agent-sdk.
  • Add Agent to allowedTools / allowed_tools. Without it the orchestrator falls back to doing everything in-line.
  • Define subagents on the agents option; otherwise the Agent tool has nothing to invoke.
  • The Agent tool was called Task in earlier Claude Agent SDK versions (< 2.1.63). Upgrade to the latest SDK to match the examples above.
Set LMNR_BASE_URL and the ports of your instance before initializing. For a local OSS deployment:
export LMNR_BASE_URL=http://localhost
# Python
# Laminar.initialize(base_url="http://localhost", http_port=8000, grpc_port=8001)

What’s next

Viewing traces

Read the transcript view, filter, and search across traces.

Signals

Detect behaviors and failures across every run, then query, cluster, and alert on them.

SQL editor and MCP server

Query traces programmatically from the UI, API, or your IDE.

Tracing structure

Sessions, metadata, and tags for deeper control.

OpenCode

Running Claude Agent SDK alongside OpenCode? Trace both here.