Traza is a trace database for LLM and agent workloads. It runs as a single binary with no external database, no queue, and no coordinator.
Sub-millisecond trace lookup. 4.4 ms filtered search over a million spans. 208,000 spans/s sustained ingest. Stores 0.23–0.41x the bytes you send on service-trace and LLM-call shapes. One process, one directory.
Replayed from real runs of the demo tour — six scripted proofs, one command each. Every number a demo prints is measured on your machine while you watch, each script asserts its own claims, and CI runs all six. Clone, then pick one:
./examples/swarm/run.sh # a live agent cockpit in the dashboard, until Ctrl-C
./examples/crash/run.sh # kill -9 mid-ingest; every acknowledged span survives
./examples/needle/run.sh # a million spans in, one sentence found in milliseconds
./examples/incident/run.sh # an agent diagnoses a runaway over MCP, promotes, diffs
./examples/vanish/run.sh # tenant-precise erasure, and a receipt that names the backupThe server with the dashboard already built in. No Rust, no Node.
VERSION=0.24.2
PLATFORM=macos-aarch64 # or linux-x86_64, linux-aarch64
curl -LO https://github.com/toshish/traza/releases/download/v$VERSION/traza-$VERSION-$PLATFORM.tar.gz
tar xzf traza-$VERSION-$PLATFORM.tar.gz
cd traza-$VERSION-$PLATFORMdocker run -p 8080:8080 -v traza-data:/data \
-e TRAZA_TOKENS="rw:$(openssl rand -hex 16)" \
ghcr.io/toshish/traza:latestcargo install traza --locked --bin traza-serverInstalls the server and API. The dashboard ships with the release archives, or build it from ui/.
To embed the engine directly in your own process instead:
cargo add trazagit clone https://github.com/toshish/traza && cd traza
cargo build --release
(cd ui && npm ci && npm run build)./traza-servertraza-server listening on 127.0.0.1:8080
traza-server: durability=wal — acknowledged writes are fsynced to the write-ahead log and recovered on restart
traza-server serving dashboard from ./ui/dist
That is the whole setup. Data lands in ./data, the dashboard is on http://localhost:8080.
| Flag | Default | |
|---|---|---|
--data-dir DIR |
./data |
All state. One writer process per directory. |
--host ADDR |
127.0.0.1 |
A non-loopback bind requires TRAZA_TOKENS. |
--port PORT |
8080 |
0 binds an ephemeral port and announces it. |
--durability MODE |
wal |
buffered, wal, or flushed. Every response says which one answered. |
--profile NAME |
balanced |
throughput, balanced, or latency. Sets the write-path knobs together. |
--ttl-seconds N |
off | Retention window for spans, annotations and payloads. |
--mcp |
off | Serve Model Context Protocol at /v1/mcp. |
--ui-dir DIR |
beside the binary | Where the built dashboard lives. |
--restore DIR |
Install a backup into --data-dir, then serve it. |
|
TRAZA_TOKENS |
unset | Bearer auth: rw: and ro: scoped, plus admin: for erasure. Bind a credential to one tenant with rw@acme:token. |
--help prints all thirty-one. The configuration reference explains what each one costs.
Serving a team. Named paths, an open bind address with auth, thirty days of retention, and the agent endpoint on:
export TRAZA_TOKENS="rw:$(openssl rand -hex 16),ro:$(openssl rand -hex 16)"
./traza-server \
--data-dir /var/lib/traza \
--host 0.0.0.0 \
--ttl-seconds 2592000 \
--mcpBulk backfill. The throughput profile seals larger segments and lets more acknowledgements share one fsync, which is what you want when nothing is waiting on any single batch:
./traza-server --data-dir /var/lib/traza --profile throughputA client blocking on the acknowledgement. The latency profile trades peak ingest for a materially better p95:
./traza-server --data-dir /var/lib/traza --profile latencyTests and CI. buffered is the fastest mode and lossy by design, which is exactly right for a store you are about to throw away. Port 0 picks a free port and prints it, so parallel test runs do not collide:
./traza-server --data-dir "$(mktemp -d)" --port 0 --durability bufferedDebugging an agent from your terminal. Serve MCP, then point a client at it:
./traza-server --mcp
claude mcp add --transport http traza http://localhost:8080/v1/mcpBacking up a running server. Pin and verify a consistent copy, take it, then release the pin:
curl -X POST http://localhost:8080/v1/backups/nightly
cp -a ./data/pins/nightly /backups/traza-$(date +%F)
curl -X POST http://localhost:8080/v1/backups/nightly/releaseRestoring one. Verified before anything is swapped, then served:
./traza-server --data-dir /var/lib/traza --restore /backups/traza-2026-08-10Erasing a session, and proving it. Deletion by trace, span, session, tenant or payload, published at a checkpoint; the receipt re-checks every domain by name:
curl -X POST http://localhost:8080/v1/erasures \
-H 'Content-Type: application/json' \
-d '{"subject": {"kind": "session", "session_id": "sess-42"}}'
curl http://localhost:8080/v1/erasures/1/verifycurl -X POST http://localhost:8080/v1/spans \
-H 'Content-Type: application/json' \
-d '[{
"trace_id": "trace-1",
"span_id": "span-1",
"name": "charge",
"service": "checkout",
"start_time_unix_nano": 1700000000000000000,
"end_time_unix_nano": 1700000000002500000,
"status": "ok"
}]'{"accepted":1,"durability":"wal"}Or point an existing app at it with two environment variables:
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:8080
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobufApps instrumented with OpenLLMetry or the OpenTelemetry GenAI conventions arrive with sessions and token/cost analytics already populated. No attribute renaming, no mapping file.
Fast reads. Trace lookup at p95 0.86 ms and filtered search at p95 4.4 ms over a million spans. Full-text search across prompt text returns a selective term in 1.5 ms where scanning takes 1,258 ms.
One process. No metadata database, no column store, no lock service, no object store to configure. It starts in milliseconds, and there is no control plane to lose a quorum at 3am.
A small surface. Three direct dependencies, thirteen packages in the whole lockfile, a 3.4 MB binary. HTTP, threading and file I/O are the standard library, and the crate is #![forbid(unsafe_code)].
Agent telemetry as the workload. Sessions, token and cost rollups, prompts and completions with large ones offloaded and deduplicated, evals and human feedback attached after the fact, live tail, and one-command dataset export.
An endpoint your agent can query. --mcp serves Model Context Protocol from the same binary and port: ten tools shaped like the questions people actually ask, with stored span text confined as untrusted and results bounded in tokens.
Durability you choose. Three acknowledgement modes, and every response states which one answered it. The suite proves them by killing the process, not by asserting.
Backup without stopping. One call pins and verifies a consistent copy of spans, annotations and payload bytes together. Restore is one flag.
Deletion with a receipt. Erase a trace, a session, a whole tenant, or one offloaded payload from every domain — buffer, log, segments, annotations, payload files, datasets — then prove it: verify --erasure re-checks each domain by name and reports the result of each, down to the pinned backup that still holds the bytes and the dataset example that carries a promoted copy.
Tenants in the key, not bolted on. Span identity is (tenant, trace_id, span_id), so two customers sharing a trace id can never overwrite each other. A token bound with rw@acme:token writes and reads exactly one tenant on every surface; retention takes per-tenant windows; GET /v1/tenants accounts usage per tenant. Single-tenant stores write byte-identical files and notice nothing.
The eval loop is representable. Promote failing production traces into an immutable, content-addressed dataset version — examples keep their own copies, so deleting the source trace cannot corrupt them — run the experiment with your own harness, record runs and scores against (experiment, example, span), and read score distributions and experiment-over-experiment diffs back out. Identity and addressing only: no runner, no scorer library, and your workflow stays yours.
| Trace lookup, 1M spans | p95 0.86 ms |
| Filtered search, 1M spans | p95 4.4 ms |
| Content search, selective term | 1.5 ms (1,258 ms scanning) (v5-format record) |
Sustained ingest, wal |
208,973 spans/s (v6-format run, 2026-07) |
| Stored vs ingested, service traces | 0.41x |
| Stored vs ingested, LLM calls | 0.23x |
| Binary | 3.4 MB |
| Direct dependencies | 3 |
Every number is produced by a benchmark bundled in this repo, run over the real HTTP path. The harness writes the records itself and refuses to publish a result it cannot stand behind — the latency and storage benchmarks assert the format's acceptance gates before writing theirs. The two rows marked with a format vintage predate v7: sustained ingest is ingest.md's 2026-07 record on the v6-format build — conservative, since gate 6's interleaved A/B measured v7 ingest no slower — and content search is capacity.md's v5-era record, not re-measured on the v7 scan path. Run them yourself with cargo run --release --bin bench.
HA storage cost on ordinary traffic is your binding constraint. Traza stores less than you send — measured at 0.41x the ingested bytes on service traces and 0.23x on LLM calls (storage.md); the v6-era 1.8–2.1x amplification is gone with format v7. What still stands is architectural: Traza keeps its data on local block storage, once per node, so a columnar engine writing to shared object storage still wins the HA cost row by two orders of magnitude on ordinary span traffic, and scan-heavy analytics over columns is not this engine's shape — the comparison runs the full table. The exception is agent context: a 320 KiB pinned context repeated across 10,000 calls is content-addressed, stored once, and compressed — 3.1 GiB ingested became 4.1 MiB on disk, a 770:1 ingested-to-stored ratio on the pinned-context corpus (storage.md).
You need metrics and logs in the same system. Traza stores traces and their analytics. That is the whole surface, on purpose.
You need horizontal scale-out today. Traza is single-node.
Everything is in docs/ — getting started, the HTTP API, LLM semantics, the MCP server, deployment, durability, backup and restore, capacity, and the engine internals.
See CONTRIBUTING.md. Stable Rust is the only dependency, ./ci.sh is the merge bar, and a new dependency needs a written reason.
Copyright © 2026 Toshish Jawale. Apache-2.0.
