Skip to Content

How do I trace the Claude Agent SDK in Python?

Rius traces the Claude Agent SDK in Python with an observe wrapper that makes each task the root span and a manual generation that records the model, tokens and cost from the run result. You install glassflow-rius next to claude-agent-sdk, call rius.init() once, and wrap your query() loop. Each task then shows up as a trace with an agent span and one model-call span underneath it.

How it works

The Claude Agent SDK drives the Claude Code runtime in a separate process. No model client runs inside your own process, so auto-instrumentation has nothing to hook. Rius covers it with two explicit pieces:

  • An observe wrapper with kind=SpanKind.AGENT makes each task the root agent span.
  • A manual generation wraps the query() loop. You fill it from the run’s ResultMessage with the token usage, the real model id and the collected answer.

Rius computes cost on its side from the model and token counts, as for any generation. You never send a cost value. Costs are list-price estimates in US dollars.

The base SDK is enough. No extra applies, and the integration is listed with the others on the Integrations page.

Set it up

  1. Install the SDK next to the Claude Agent SDK. Python 3.10 or newer is required, and the claude CLI must be installed and authenticated. The runtime uses whatever auth Claude Code has, and an exported ANTHROPIC_API_KEY takes precedence over a claude.ai login.

    pip install glassflow-rius claude-agent-sdk
  2. Call rius.init() once, as early as possible, then wrap your task. The code below is a complete minimal traced call. Set service_name explicitly, because it is how you find your agent later. The installation page covers every other init() option.

    import rius from claude_agent_sdk import ( AssistantMessage, ClaudeAgentOptions, ResultMessage, TextBlock, query, ) from rius import SpanKind rius.init(api_key="ri_...", service_name="my-agent") MODEL = "claude-haiku-4-5" @rius.observe(name="handle-task", kind=SpanKind.AGENT) async def handle_task(task: str) -> str: options = ClaudeAgentOptions(model=MODEL, max_turns=1) parts = [] with rius.start_as_current_generation( "claude_agent_turn", model=MODEL, provider="anthropic", input=task ) as gen: async for message in query(prompt=task, options=options): if isinstance(message, AssistantMessage): parts.extend( b.text for b in message.content if isinstance(b, TextBlock) ) elif isinstance(message, ResultMessage): usage = message.usage or {} gen.set_usage( input_tokens=usage.get("input_tokens"), output_tokens=usage.get("output_tokens"), cache_read_input_tokens=usage.get("cache_read_input_tokens"), # Anthropic's payload still calls the write count "cache creation" cache_write_input_tokens=usage.get("cache_creation_input_tokens"), ) models = list((message.model_usage or {}).keys()) if models: gen.set_response_model(models[0]) answer = "".join(parts) gen.set_output(answer) return answer
  3. Use a full model id such as claude-haiku-4-5, not an alias such as haiku, for both the CLI option and the generation. Rius prices from the requested model, and its pricing table matches real model ids only. An alias produces a generation with no cost.

  4. Pass the cache counts from the ResultMessage as they are, and keep provider="anthropic" on the generation. Anthropic reports an input_tokens figure that excludes cache reads and writes. With that provider, set_usage() adds the two cache counts to the input tokens for you, so you do no arithmetic. Cache-heavy runs, which covers most agent loops, would otherwise undercount badly.

  5. Optional: scope each conversation with rius.session() so its tasks group as one session. The Claude Agent SDK’s own session_id for resumable conversations works well as the Rius session id.

  6. Run one task and open the trace in the console. You should see the root agent span and the generation with a full model id, tokens and cost. A generation without cost means an alias was used as the model id.

What you get

Each task becomes one trace with this shape:

handle-task AGENT 5.0s └─ claude_agent_turn LLM 5.0s claude-haiku-4-5, tokens + cost
  • The root agent span is your observe wrapper, named after the task handler and timed for the whole task.
  • The generation is the whole runtime turn. It carries the model, input and output tokens, cache read and write tokens, the answer you collected and the computed cost.
  • The response model comes from the run result, so you see the model that actually answered.

The runtime’s inner work does not appear. Tool calls, sub-turns and file operations happen inside the Claude Code process and produce no spans, so the generation records the totals for the turn only.

From there you can filter and compare these traces by the service name you set, as with any other agent. For the full list of supported libraries and frameworks, see Integrations.

When something else fits

  • If your agent calls a model client such as Anthropic or OpenAI directly inside your own process, auto-instrumentation records those calls without manual generations. The Integrations page lists them.
  • If you need a span for each tool call inside the Claude Code runtime, this integration does not provide it. It records the turn’s totals only.

Still stuck? Get help

Last updated on