Open-source agent tracing
Open-source tracing for LangGraph and LangChain. Traces stay in your files or your AWS account, with a viewer you run.

Fits the stack you already run
The tracer speaks the LangChain callback API, so adding it is a config change, not a rewrite.
The root entry has no runtime dependencies.
Every chain, model, tool and retriever call lands in ./.traces. Your graph code stays as it is.
One command serves the run tree, payloads and annotations on localhost.
pnpm add @m4trix/tracingimport { FsPayloadStoreAdapter, FsStructureStoreAdapter, TraceStore, Tracer, toLangGraph,} from '@m4trix/tracing';
const traceStore = TraceStore.of({ structureStoreAdapter: new FsStructureStoreAdapter({ path: './.traces' }), payloadStoreAdapter: new FsPayloadStoreAdapter({ path: './.traces' }),});
const tracer = Tracer.from(traceStore).adapt(toLangGraph);
await graph.invoke(input, { callbacks: [tracer] });await tracer.flush();npx m4trix-trace-viewer --adapter fs --path ./.tracesSmall rows for lists and filters, full payloads when you open a run, and notes that stay with the trace.
Profiles turn raw JSON into messages, tool calls and tables. A model drafts the mapping from samples of your traces, with your own key, straight from the browser.

No sign-up, no API key, no upload queue. Grep it, commit a fixture, or mount it in Docker.
Structure rows hold timing, status and tokens. Prompts and completions are blobs, fetched by ref only when you open a span.
Annotate traces and single runs after the fact. Notes live next to the structure rows, not in another tool.
annotation: { review: 'approved' }The adapters that write a trace also serve it back through TraceViewerApi. No read replica, no sync lag.
The viewer also runs as an MCP server. Claude Code, Cursor or any MCP client can search payloads, find the root cause of an error and diff two runs.
claude mcp add m4trix-traces -- \ npx m4trix-trace-viewer mcp --path "$PWD/.traces"11 tools, read-only unless you approve a note
Find
Inspect
Diagnose
analyze_trace flags error roots, unfinished runs, the critical path, token hotspots and loops in one call.
Same Tracer, same viewer at every stage. Only the adapters change.
Filesystem adapters write to ./.traces. Open them with the viewer CLI.
--adapter fs --path ./.tracesThe app writes to a shared volume. A sidecar ships it, so the app needs no AWS credentials.
m4trix-tracing-sidecar --root /tracesStructure goes to DynamoDB, payloads to S3. The same viewer reads it back.
--adapter aws-stackSwap any adapter without touching the tracer or the viewer.
Tracer.from(traceStore) implements the callback surface LangGraph expects. Pass tracer.adapt(toLangGraph) to callbacks. Every chain, LLM, tool, and retriever span lands in your store without rewriting agent code.import { Tracer, toLangGraph } from '@m4trix/tracing';
const tracer = Tracer.from(traceStore);const lgTracer = tracer.adapt(toLangGraph);
await graph.invoke(input, { callbacks: [lgTracer] });await lgTracer.flush();Not by default. The filesystem adapters write to a folder you choose. Data only moves if you configure the S3 and DynamoDB adapters or run the sidecar. AI profiles call the model provider directly from your browser, with your key.
No. The Tracer implements the LangChain callback methods without importing LangChain, so anything that emits those callbacks works. LangGraph gets a typed adapter through toLangGraph.
Those are platforms: a hosted service, or a database and web app you operate. m4trix tracing is a library. Traces are files or rows in your own AWS account, and the viewer is a CLI you start when you need it.
The sidecar pattern is built for it: the app writes locally and a companion container ships to S3 and DynamoDB. Sampling, PII redaction, viewer auth and retention policies are not included yet.
Nothing. It is MIT licensed with no seats or usage tiers. You pay only for the storage you choose to use.
Each package works on its own. Together they share one TypeScript model.
One callback, one folder, one command to open it.