Production observability adapter for LangChain/LangGraph multi-agent systems
Project description
tracesage
Production observability for LangChain & LangGraph multi-agent systems. Drop in two lines, see live execution traces in your browser.
from tracesage import TraceSage
# Illustrative only — `await` runs inside an async function. See Quick start
# below for a complete, runnable `async def main()`.
tracer = await TraceSage.create() # one-time setup
result = await graph.ainvoke(
{"input": payload},
config={"callbacks": [tracer.handler]}, # only line you add
)
# Open http://localhost:7842/ui to see the trace live
Contents
- Why tracesage
- Install
- Quick start
- Concepts: topology node kinds
- Features
- Examples
- Documentation
- Comparison
- Performance
- Status
- Contributing
- License
Why tracesage
LangChain agents emit a rich callback stream — chain start/end, tool start/end, LLM start/end, retrieval, errors. tracesage captures all of it without changing your workflow logic, persists it locally (SQLite + gzipped blobs), and renders it in an interactive graph + timeline UI in real time.
- Zero infrastructure. No Docker. No Postgres. No external services.
pip install. - Two-line integration. One callback added to your existing
ainvoke. - Production-grade safety. The handler never raises. The tracer never crashes your pipeline.
- Interactive graph view. Custom SVG graph (no framework), auto-laid-out. Hover, click, replay any run.
- MCP-aware. Tools loaded from MCP servers are attributed by source, so you can see which tools came from which server vs. which are hardcoded. See docs/mcp.md.
- Pluggable storage. SQLite today; Postgres / remote-collector / object-store backends planned (see
production_roadmap.md). - MIT licensed. Free forever.
Install
pip install tracesage[langchain]
Requires Python 3.11+. The [langchain] extra pulls langchain-core;
that's the only mandatory third-party dep beyond the standard FastAPI /
aiosqlite / pydantic stack. If your app uses LangGraph, also pip install langgraph (tracesage doesn't pull it).
tracesage is provider-agnostic — it traces LangChain's callback stream, so OpenAI / Anthropic / local models are all captured automatically; there's no provider setting in tracesage. Install whichever provider you use:
pip install langchain-openai # OPENAI_API_KEY=...
pip install langchain-anthropic # ANTHROPIC_API_KEY=...
For MCP tool-source attribution (loads tools from MCP servers and tags them by
source), install the mcp extra:
pip install 'tracesage[mcp]'
Quick start
See it in 5 seconds — seed a sample trace and open the UI:
tracesage demo
Sync scripts / notebooks — wrap your code; every LangChain call is captured
automatically (no callbacks= wiring) and a clickable trace link is printed:
import tracesage
with tracesage.trace() as tl: # starts the UI + global capture
result = agent.invoke("your input") # 🔍 tracesage: http://127.0.0.1:7842/ui/#run=...
input("Trace ready — open the printed link, then Enter to exit.") # keep the UI up
(The embedded UI stops when the with block / process exits; traces persist to
~/.tracesage, so you can also reopen them later with tracesage serve.)
Async apps — use the context manager (or await TraceSage.create() for full control):
import asyncio
from tracesage import TraceSage
async def main():
async with TraceSage.session(install=True) as tl: # install=True → global capture
await graph.ainvoke({"input": "your payload"}, config={"tags": ["my-system"]})
await tl.flush() # ensure events are persisted
print(tl.run_url("<run_id>")) # deep link to a run
asyncio.run(main())
Prefer explicit wiring? Pass config={"callbacks": [tl.handler]} instead of install=True.
That's it. Open http://localhost:7842/ui and explore.
Developer workflow
Once you have traces, debug them without leaving your terminal:
tracesage show <run_id> # render a run as a tree in the terminal
tracesage watch <run_id> # live-tail events as they stream
tracesage diff <run_a> <run_b> # compare two runs (tokens, tools, errors)
tracesage view trace.jsonl # open an exported trace in the UI directly
Test your agents — the tracesage_capture pytest fixture is auto-registered:
def test_agent_uses_search(tracesage_capture):
agent.invoke("find me a hotel")
tracesage_capture.assert_tool_called("search")
tracesage_capture.assert_no_errors()
assert tracesage_capture.total_tokens()[0] < 5000
See docs/development.md for the full developer guide, and
examples/showcase/ for 30 before/after apps across popular use cases.
Concepts: topology node kinds
When you open the UI, every node in the topology graph is one of five event-based
kinds — plus a synthesized mcp node when you attribute tools to an MCP server.
Knowing what each means is the prerequisite to reading a trace:
| Kind | What it is | Examples you'll see |
|---|---|---|
agent |
A function you registered as a LangGraph node, that calls other components | agent:billing_agent, agent:fact_extractor, agent:supervisor |
tool |
A side-effect function (DB query, API call, calculation) decorated with @tool |
tool:lookup_account, tool:run_sql, tool:cite_sources |
llm |
A language-model call (chat or completion) | llm:FakeListChatModel, llm:ChatOpenAI, llm:ChatAnthropic |
retriever |
A BaseRetriever subclass — the "R" in RAG |
retriever:Chroma, retriever:FAISS, retriever:_FixedCorpusRetriever |
chain |
Plumbing — LCEL primitives, the LangGraph orchestrator, routing functions | chain:LangGraph, chain:RunnableSequence, chain:ChatPromptTemplate, chain:route_after_quality |
mcp |
An MCP server (synthesized) — groups the tools loaded from it | mcp:weather, mcp:math, mcp:github |
Quick mental model:
agentis your code that calls something. It does reasoning.tooldoes the actual side-effect work and returns a result.llmis what you count, cost, and cache.retrieveris its own dimension — "did we find the right docs?" is a different question from "did the LLM use them well?".chainis the wrapping machinery (theprompt | llm | parserpipe operator, the LangGraph state machine, routing functions). It's infrastructure, not business logic.mcpgroups tools by the MCP server they came from — provenance, so you can tell server-provided tools from your hardcoded ones (see docs/mcp.md).
Read the full reference at docs/concepts.md —
it covers how tracesage classifies events into kinds, why agents with no
descendants get demoted to chain, and walks through a research-pipeline
topology piece by piece.
Features
Live interactive UI
- Run list with status badges (running / completed / failed), search, status filter
- SVG graph showing agents, tools, and execution paths — pulses as events arrive
- MCP attribution —
mcp:server nodes with per-server colors, agent→server and server→tool edges, and a draggable "Tools by source" panel grouping tools by origin - Timeline with click-to-expand step cards, lazy-loaded full payloads
- Replay mode that re-animates a run at 1x / 2x / 5x speed
- Dark / light themes, persisted in
localStorage - Keyboard shortcuts:
j/knext/prev run,/focus search,ttoggle theme,Esc,?
Production safety
- Refuses to bind non-loopback addresses without
auth_token(hard fail-stop) - Bearer-token HTTP auth + WebSocket auth via
?token=or subprotocol - Constant-time token comparison
- Path-traversal blocked at runtime
- Per-run event cap (circuit breaker) and root-level sampling for high volumes
- Bounded internal state (no unbounded memory growth in long-running processes)
- Kill switch:
TRACESAGE_ENABLED=falsemakes it a complete no-op (no server, no DB/worker, no-op handler) — integrate once, disable per-environment. See docs/production.md.
CLI
tracesage serve --data-dir ~/.tracesage # read-only viewer
tracesage export --run-id RUN_ID -o trace.jsonl # export to JSONL
tracesage import -i trace.jsonl # import a JSONL export
tracesage stats --data-dir ~/.tracesage # summary stats
tracesage runs --status failed --limit 20 # list runs
tracesage gc --max-runs 10000 # retention cleanup
tracesage doctor --data-dir ~/.tracesage # data-dir diagnostics
tracesage version
See docs/cli.md for full reference.
Examples
The examples/ directory has three tiers:
getting_started/— 3 standalone demos driven byFakeListChatModel(no API key): smart-search agent, research supervisor, RAG.mcp/— tools from 2 local MCP servers + 2 hardcoded tools, attributed by source in the topology (needstracesage[mcp]).showcase/— 30 real before/after apps across popular use cases (customer support, RAG, multi-agent, MCP, reasoning loops, finance/legal/insurance). Each ships a plainbefore.pyand anafter.pywith tracesage added, sodiffshows the exact integration.
# instant, no key:
python examples/getting_started/01_smart_search_agent.py # then open http://localhost:7842/ui
# the real-world gallery (needs an LLM key):
pip install -r examples/showcase/requirements.txt
export OPENAI_API_KEY=...
python examples/showcase/01_support_faq_router/after.py
The showcase gallery has 30 before/after apps spanning LangChain + LangGraph: routing, parallel fan-out, the supervisor pattern, RAG variants, writer-critic loops, map-reduce, MCP, self-correction, and finance/legal/insurance verticals.
Documentation
| Doc | What's in it |
|---|---|
| Quickstart | First trace in five minutes |
| Developer guide | Trace links, sync/notebook setup, CLI debugging, pytest fixture |
| Configuration | Every TRACESAGE_* env var explained |
| CLI reference | All tracesage subcommands |
| Production guide | Sampling, auth, retention, deployment |
| Comparison | tracesage vs LangSmith / LangFuse / Phoenix |
| Extending tracesage | Adding framework adapters and storage backends |
| Examples | 30 before/after apps with tracesage added |
Comparison
When to use tracesage vs alternatives:
| tracesage | LangSmith | LangFuse | Phoenix | |
|---|---|---|---|---|
| Zero infra | ✓ | cloud / enterprise self-host | Docker + Postgres | ✓ |
| Pure pip install | ✓ | ✓ (cloud) | ✗ | ✓ |
| Live UI | ✓ | ✓ | ✓ | ✓ |
| MIT licensed | ✓ | proprietary | MIT | Elastic v2 |
| Eval framework | non-goal | ✓ | ✓ | ✓ |
| OpenTelemetry export | v0.3+ | partial | ✓ | ✓ |
See docs/comparison.md for the full breakdown.
Performance
Bench results (5,000 events, 100 distinct run_ids, 20% blob-eligible):
| Platform | Sustained | p99 write | Drops |
|---|---|---|---|
| Linux x86 + NVMe | 800–1200 ev/s | 80–150 ms | 0 |
| Windows NTFS | 60–100 ev/s | 1–2 s | 0 |
Windows NTFS is the bottleneck (gzip + fsync amplification). For very high
throughput on Windows, raise TRACESAGE_WORKER_BATCH_SIZE to 200 and
TRACESAGE_WORKER_BATCH_TIMEOUT to 0.5.
Status
v0.1 — alpha. API may still shift before v1.0. Production-monitoring-ready for
single-Python-process deployments; centralized multi-process / remote-collector mode
is on the roadmap (see production_roadmap.md).
See the changelog for release notes.
Contributing
Issues and pull requests are welcome.
- Read
docs/contributing.mdbefore sending a PR - For non-trivial changes, open a discussion first
- Bugs and feature requests use the issue templates
- Security reports: see
SECURITY.md— please don't open public issues for vulnerabilities - All participation is governed by the Code of Conduct
License
MIT © tracesage contributors
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tracesage-0.1.0.tar.gz.
File metadata
- Download URL: tracesage-0.1.0.tar.gz
- Upload date:
- Size: 246.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
08928bd52aa3124e74f677bd253f4c705350db08e1cb570788b55e0fd8742505
|
|
| MD5 |
7ec3f7d46ae435f8292f3a8f466e6582
|
|
| BLAKE2b-256 |
84906f000443c46859abab71108bd95d8ad712720c4f20f999a7292d07e37b37
|
Provenance
The following attestation bundles were made for tracesage-0.1.0.tar.gz:
Publisher:
release.yml on kjgpta/tracesage
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tracesage-0.1.0.tar.gz -
Subject digest:
08928bd52aa3124e74f677bd253f4c705350db08e1cb570788b55e0fd8742505 - Sigstore transparency entry: 1835521550
- Sigstore integration time:
-
Permalink:
kjgpta/tracesage@85af8adbfce5ac35046adda64c01d1e40fad8f01 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/kjgpta
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@85af8adbfce5ac35046adda64c01d1e40fad8f01 -
Trigger Event:
push
-
Statement type:
File details
Details for the file tracesage-0.1.0-py3-none-any.whl.
File metadata
- Download URL: tracesage-0.1.0-py3-none-any.whl
- Upload date:
- Size: 125.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a14ff24cbf9b2fdb9d5709f0fd94acf869225a6642d3361ac453bd7970f47d98
|
|
| MD5 |
9af1de6bc4cc6ace26580daab51fb549
|
|
| BLAKE2b-256 |
1d9889b37f517ee005c589f959c0b2b3996dce86e367a32ccba80fcb07e1f918
|
Provenance
The following attestation bundles were made for tracesage-0.1.0-py3-none-any.whl:
Publisher:
release.yml on kjgpta/tracesage
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tracesage-0.1.0-py3-none-any.whl -
Subject digest:
a14ff24cbf9b2fdb9d5709f0fd94acf869225a6642d3361ac453bd7970f47d98 - Sigstore transparency entry: 1835521644
- Sigstore integration time:
-
Permalink:
kjgpta/tracesage@85af8adbfce5ac35046adda64c01d1e40fad8f01 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/kjgpta
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@85af8adbfce5ac35046adda64c01d1e40fad8f01 -
Trigger Event:
push
-
Statement type: