Skip to main content

SwarmTrace

**Observability for AI agents — trace, debug, and monitor with 2 lines of code **

PyPI Python License Built at AMD Hackathon

Dashboard · PyPI · GitHub


Install

pip install swarmtrace

Quick Start

from swarmtrace import observe

@observe
def my_agent(question):
    return llm.chat(question)

my_agent("What is machine learning?")
swarmtrace    # view traces in terminal

Every call is recorded — latency, tokens, cost, errors. Nothing else to configure.


Architecture

SwarmTrace is organized around a small ports-and-adapters core: public APIs and protocol ingress (@observe, run()/span(), MCP, OTLP) create canonical SpanRecords, the runtime persists them locally, and delivery adapters batch them to the dashboard when remote ingest is configured. The dashboard includes a black Node Network Map that renders individual agent nodes, collaboration mode (solo / orchestrator / sub-agent / peer), per-agent RAG badges, and live connection lines from trace context. The Traces page also includes an Architecture view for kind-level span layers. See docs/ARCHITECTURE.md for the module map, dependency rules, data flows, and extension guidelines.


Single Agent

Wrap your agent with @observe. Any LLM or tool calls inside it get tagged with kind="llm" or kind="tool" so they roll up into the agent's stats — they never appear as phantom agents on the dashboard.

from swarmtrace import observe, init

init(api_key="your-key", endpoint="https://swarmtrace.vercel.app")

@observe
def my_agent(query):
    plan = call_llm(query)
    return search_web(plan)

@observe(kind="llm")
def call_llm(prompt):
    return client.chat(model="gpt-4o-mini", messages=[...])

@observe(kind="tool")
def search_web(q):
    ...

One agent card on the dashboard. call_llm and search_web fold their tokens, cost, and errors into my_agent — they never get their own card.


Quickstart — inject into any agent in 2 lines

import swarmtrace
swarmtrace.init()              # auto-detects OpenAI, Anthropic, Gemini, LiteLLM

That's all. Now decorate your top-level function:

@swarmtrace.observe
def my_agent(prompt):
    return openai_client.chat.completions.create(...)  # traced automatically

swarmtrace.init() patches installed LLM clients so every raw LLM call is recorded as kind="llm" — with latency, model, tokens, and cost — and attributed to whatever agent is currently running. You don't decorate the LLM call. You don't pick a kind. You don't configure anything else.

Single agent

import swarmtrace
swarmtrace.init()

from openai import OpenAI
client = OpenAI()

@swarmtrace.observe                    # one decorator. that's it.
def my_agent(prompt):
    return client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": prompt}],
    )

my_agent("What is AGI?")

Dashboard: one "my_agent" card with tokens, cost, latency, error rate.

Multi-agent swarm

import swarmtrace
swarmtrace.init()

@swarmtrace.observe                    # own card on the dashboard
def researcher(q):
    return client.chat.completions.create(model="gpt-4o-mini", messages=[...])

@swarmtrace.observe                    # own card
def summarizer(text):
    return client.chat.completions.create(model="gpt-4o-mini", messages=[...])

@swarmtrace.observe                    # own card — orchestrator
def orchestrator(q):
    research = researcher(q)
    return summarizer(research)

orchestrator("Explain transformers")

Dashboard: three cards. researcher's and summarizer's LLM costs roll into their own cards automatically.

Auto-detection — @observe figures out the role at call time:

  • Nothing running yet → this call is the agent (gets its own card).
  • Already inside an agent → rolls up into it (tokens + errors fold in, no extra card).

So @observe everywhere is safe — helpers and inner calls just disappear into the agent that ran them, instead of cluttering the Agents page.

Need separate cards for named sub-agents? Add kind="agent" explicitly:

@swarmtrace.observe(kind="agent")
def researcher(q): ...

That's the only knob. kind="llm" / kind="tool" exist for labeling, but the dashboard works correctly without them.


Every bare @observe is its own agent card. Nesting is handled automatically via contextvars — no IDs, no config.

from swarmtrace import observe

@observe
def researcher(q):
    return call_llm(f"Research: {q}")

@observe
def summarizer(text):
    return call_llm(f"Summarize: {text}")

@observe
def orchestrator(q):
    research = researcher(q)
    return summarizer(research)

orchestrator("What is AGI?")
▶ orchestrator    4.2s  |  7 in / 78 out   |  $0.0003
  ▶ researcher    3.4s  |  7 in / 330 out  |  $0.0013
  ▶ summarizer    0.8s  |  338 in / 78 out |  $0.0005

Three agent cards on the dashboard — one per named agent. Sub-calls (call_llm) fold into whichever agent invoked them.


Span Kinds

Kind Decorator Dashboard
agent @observe (default) Own card — tasks, tokens, cost, status
llm @observe(kind="llm") Rolls up into calling agent
tool @observe(kind="tool") Rolls up into calling agent
function @observe(kind="function") Rolls up into calling agent

The rule: only functions you want as separate dashboard cards get bare @observe. Everything else gets a kind=.


Span Kinds — agents vs. tool/LLM calls

By default, @observe marks a call as kind="agent" — it gets its own entry on the dashboard's Agents page, with its own task count, tokens, cost, and status. That's the right default for named agents like orchestrator, researcher, and summarizer above.

If you also wrap raw LLM or tool calls with @observe for visibility, tag them so they roll up into the calling agent's stats instead of showing up as their own (fake) agents:

from swarmtrace import observe

@observe(kind="llm")
def call_llm(prompt):
    return client.chat(model="gpt-4o-mini", messages=[...])

@observe(kind="tool")
def search_web(query):
    ...

@observe(kind="function")
def helper(x):
    ...

@observe                      # kind="agent" (default)
def researcher(q):
    return call_llm(f"Research: {q}")

call_llm and search_web are attributed to whichever kind="agent" call is currently running (researcher, here) — their tokens, cost, and any errors are folded into researcher's stats. They never appear as separate entries on the Agents page, no matter how deeply nested.


Async Support

import asyncio
from swarmtrace import observe

@observe
async def async_agent(q):
    return await llm.achat(q)

@observe
async def orchestrator(q):
    results = await asyncio.gather(
        async_agent(q),
        async_agent(q + " — deep dive"),
    )
    return " | ".join(results)

asyncio.run(orchestrator("Explain transformers"))

Live Cost Tracking

Automatic cost calculation for any model from any provider — powered by LiteLLM's live pricing registry.

@observe
def agent(q):
    # OpenAI, Anthropic, Google, Mistral, DeepSeek,
    # Groq, Cohere, xAI — cost tracked automatically
    return client.chat(model="gpt-4o-mini", messages=[...])

Custom or fine-tuned models:

from swarmtrace import set_model_pricing

set_model_pricing("my-finetune", input_per_million=5.00, output_per_million=15.00)

Token Budget

Stop runaway agents before they burn your budget.

from swarmtrace import observe, budget

@observe
@budget(max_tokens=10_000, on_exceed="warn")   # or "stop"
def agent(q):
    return llm.chat(q)

Regression Detection

Catch when a prompt change breaks your agent's behavior.

pip install swarmtrace[regression]
from swarmtrace.regression import compare

compare(
    my_agent,
    inputs=["What is ML?", "How does Python work?", "What is an API?"],
    version_a_prompt="You are a helpful assistant.",
    version_b_prompt="Reply only in emojis.",
    threshold=0.6,
)
INPUT                    SIMILARITY   REGRESSION?
What is ML?              0.10         🔴 YES
How does Python work?    0.15         🔴 YES
What is an API?          0.12         🔴 YES

Result: 3/3 regressions detected

Report runs to the dashboard

Pass report_to_dashboard=True (with SWARMTRACE_API_KEY set) to upload the run — per-input similarity scores and latencies — to the Regression page of your SwarmTrace dashboard instead of only printing to the console:

from swarmtrace.regression import compare

compare(
    my_agent,
    inputs=["What is ML?"],
    version_a_prompt="You are a helpful assistant.",
    version_b_prompt="Reply only in emojis.",
    threshold=0.6,
    report_to_dashboard=True,
    run_name="emoji-test-2026-08",   # optional display name
)

The report is best-effort: a missing key, unreachable dashboard, or HTTP error is logged as a warning and never raises or changes the comparison result. Prompts, inputs, and outputs are truncated to 32 000 chars and PII-redacted (emails, API keys, card numbers, JWTs) before transmission, and the dashboard redacts again at the ingest boundary.


Tool Attention

Reduce token overhead by up to 95% — only pass relevant tools to each agent call, scored via ISO Scoring (arXiv:2604.21816).

pip install swarmtrace[tools]
from swarmtrace import ToolAttention

ta = ToolAttention(tools=all_my_tools)

@observe
def agent(query):
    relevant_tools = ta.select(query, top_k=3)
    return llm.chat(query, tools=relevant_tools)

Remote Dashboard

Send traces to the SwarmTrace dashboard for live monitoring.

from swarmtrace import init, observe

init(
    api_key="your-swarmtrace-api-key",
    endpoint="https://swarmtrace.vercel.app",
)

@observe
def my_agent(q):
    ...

Or via environment variables:

export SWARMTRACE_API_KEY=your-key
export SWARMTRACE_ENDPOINT=https://swarmtrace.vercel.app

Traces not arriving? Self-hosting the dashboard? The dashboard's Supabase project must have the migrations in supabase/migrations/ applied — that is the #1 setup failure (every ingest call 500s, nothing appears on the dashboard). See docs/SUPABASE_SETUP.md for the one-command setup (npm run db:migrate) and the self-check endpoint GET /api/health/db that names any missing migration.


Browser & Extended Capture (FOV)

@observe and init() already trace LLM calls with zero extra dependencies — that works on a laptop, Kaggle, Colab, or a serverless function with nothing else installed. fov=True adds a second, opt-in layer: outbound HTTP calls, live LLM token streaming, and filesystem writes.

from swarmtrace import init, observe

init(api_key="your-key", endpoint="https://swarmtrace.vercel.app", fov=True)

Browser screenshots are the one FOV capability that needs an actual browser, so they're opt-in on top of opt-in:

pip install swarmtrace[fov]
playwright install chromium

No Playwright? fov=True still gives you HTTP/stream/filesystem capture — screenshots are just silently skipped. Either way, init() prints one line to stderr telling you exactly what's active, so you're never guessing what a given machine is actually tracing.


Use via MCP — no Python SDK required

Any MCP-compatible client (Claude Desktop, Cursor, Hermes, etc.) can send traces straight to SwarmTrace over HTTP, without installing the Python package at all. This is the zero-install path for agents running somewhere you don't control.

{
  "mcpServers": {
    "swarmtrace": {
      "url": "https://swarmtrace.vercel.app/api/mcp",
      "headers": { "x-api-key": "your-swarmtrace-api-key" }
    }
  }
}

Exposes three tools: record_trace (send one trace), get_metrics (your usage stats), list_traces (recent traces). Exact config keys vary by client — check your client's docs for where remote/HTTP MCP servers go.


CLI

swarmtrace                       # last 100 traces
swarmtrace --limit 50            # last 50
swarmtrace-replay <id>           # replay any trace
swarmtrace-export --format json
swarmtrace-export --format csv

vs LangSmith

Feature SwarmTrace LangSmith
Open source ✅ ❌
Works offline ✅ ❌
Any LLM / any framework ✅ ❌ LangChain only
Live cost tracking ✅ all models ✅
Regression detection ✅ ❌
Token budget enforcement ✅ ❌
Tool attention (ISO) ✅ ❌
Setup 2 lines SDK + account
Price Free $20/month

Optional Extras

pip install swarmtrace[regression]   # AI regression detection
pip install swarmtrace[tools]        # Tool attention + FAISS
pip install swarmtrace[budget]       # Token budget with tiktoken
pip install swarmtrace[scraper]      # Web scraping traces
pip install swarmtrace[fov]          # Browser screenshots (playwright + watchdog)
pip install swarmtrace[all]          # Everything

AMD MI300X Benchmarks

Tested on AMD Instinct MI300X 192GB via AMD Developer Cloud.

Metric Value
Swarms tested 5
Total agent calls 20
Avg orchestrator latency 6.1s
Avg researcher latency 1.8s
Trace overhead < 1ms

Built with ❤️ at AMD Hackathon 2026 by Ravi Kumar

Metadata

Release files for swarmtrace 0.7.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for swarmtrace 0.7.0
File Size Uploaded
swarmtrace-0.7.0.tar.gz 166.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for swarmtrace 0.7.0
File Interpreter ABI Platform
swarmtrace-0.7.0-py3-none-any.whl Python 3 none any Details

Total release size: 270.8 kB

Release files / swarmtrace-0.7.0.tar.gz

Download URL swarmtrace-0.7.0.tar.gz
Size 166.9 kB
Tags Source
SHA-256 checksum
How to use checksums
4a8e2e74e4f267446174a264682209123064030cd358dea0155850ed14c9b7d1
BLAKE2b-256 checksum
How to use checksums
cc502c855481524e2d0c7ff8bd79e31a792783d919b0c0b8e6f7203ea907cd06
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.1

Release files / swarmtrace-0.7.0-py3-none-any.whl

Download URL swarmtrace-0.7.0-py3-none-any.whl
Size 104.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8f5e4a7d55cfbf28bb02f7d21683128b37003a8f92b79b63b348d3b7e51babe5
BLAKE2b-256 checksum
How to use checksums
7bfc7b35ed0ccae745cb1fbc61faa3594218505331b831c89cc00dfaad03522e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.1

Release history Release notifications | RSS feed

This release

0.7.0 This release

2 release files

0.6.7

2 release files

0.6.6

2 release files

0.6.5

2 release files

0.6.4

2 release files

0.6.3

2 release files

0.6.2

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.9

1 release file

0.4.8

2 release files

0.4.7

2 release files

0.4.6

2 release files

0.4.5

2 release files

0.4.4

2 release files

0.4.3

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.9

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page