Quickstart

Instrument a real LLM call and see it attributed to a named agent, from a clean environment to a recorded event in about five minutes.

This example makes two provider calls, attributes them to two different agents, and reports per-agent cost.

It assumes you have installed the SDK and set CAPSERA_API_KEY. See Install if not.

The script

import os

import anthropic
import capsera

capsera.init(api_key=os.environ["CAPSERA_API_KEY"])

client = anthropic.Anthropic()
MODEL = "claude-sonnet-4-6"


@capsera.agent("drafter", team="content")
def draft(topic: str) -> str:
    response = client.messages.create(
        model=MODEL,
        max_tokens=400,
        messages=[{"role": "user", "content": f"Write a short paragraph about {topic}."}],
    )
    return response.content[0].text


@capsera.agent("critic", team="content", task_type="review")
def critique(draft_text: str) -> str:
    response = client.messages.create(
        model=MODEL,
        max_tokens=200,
        messages=[
            {
                "role": "user",
                "content": f"Give one sentence of critical feedback:\n\n{draft_text}",
            }
        ],
    )
    return response.content[0].text


if __name__ == "__main__":
    text = draft("the cost of running agents in production")
    print(critique(text))
    capsera.shutdown()

Run it. The output is unchanged from the uninstrumented version.

What was recorded

capsera.init() patched the Messages class, not the client object created after it. Both calls went through the patch, which recorded the model, token counts, cost, latency, and the file and line that made each call.

The decorators supplied the attribution the provider request cannot carry. One call is attributed to drafter, the other to critic, both on team content, and the critique also carries task_type="review".

Both calls used the same model, so the difference in their cost comes only from how much text each agent sent and received.

Why shutdown() is required

A background thread ships events, so a short-lived process can exit before the queue drains. capsera.shutdown() flushes pending events and stops the worker.

capsera.shutdown()   # blocks until queued events are delivered

Long-running services do not need it, because the flush interval (500 ms by default) handles delivery. Scripts, cron jobs, CI steps, and notebook cells do need it. Omitting it is the most common reason a one-off script reports nothing.

Use capsera.flush() instead if you want to deliver queued events and keep the worker running.

In the dashboard

Spend now breaks down by agent (drafter and critic) and by team (content). Each event also carries the file and line that made the call, so an unexpected cost traces back to code rather than to a model name.

Next

Verify it works covers what to check if nothing appeared.

Agents covers nested decorators, async functions, methods, and the unknown agent.

Tags and sessions covers attribution without decorating a function, and grouping a multi-turn conversation.