spantrace
v0.1.1
Published
Local-first debug visualizer for multi-step agentic LLM runs
Readme
spantrace
A local-first, open-source debug visualizer for multi-step agentic LLM runs — think "Chrome DevTools for AI agents."
spantrace ingests a JSONL-based .agtrace span log and renders it as an inspectable, navigable trace so you can debug what an agent actually did: which LLM calls it made, which tools it invoked, what came back, and where it errored or retried.
The core pipeline (parse a .agtrace file, reconstruct the span tree, print it to stdout) is a CLI. There's also a local web viewer — spantrace view — that renders the same tree as an interactive, collapsible view with a detail panel per span.
Install
npm install -g spantraceOr run it without installing:
npx spantrace path/to/trace.agtraceFrom source
git clone https://github.com/the-orbital-labs/spantrace.git
cd spantrace
npm install
npm run buildUsage
Run the CLI against a .agtrace file:
spantrace path/to/trace.agtrace(If you're working from a source checkout instead of a global install, use npm start -- or npm run dev -- in place of spantrace in any command below.)
Sample output
Given the fixture at fixtures/sample.agtrace:
spantrace fixtures/sample.agtrace└─ [LLM_CALL] claude-sonnet-5 — "What's the weather in Dubai and log it to the tracker?" (span-1)
├─ [TOOL_CALL] get_weather({"city":"Dubai"}) (span-2)
│ └─ [TOOL_RESULT] get_weather -> {"tempC":41,"condition":"sunny"} (span-3)
├─ [TOOL_CALL] log_to_tracker({"city":"Dubai","tempC":41}) (span-4)
│ ├─ [ERROR] connection reset by tracker service (span-5)
│ ├─ [RETRY] attempt 1/3 — connection reset, retrying (span-6)
│ └─ [TOOL_RESULT] log_to_tracker -> {"status":"ok"} (span-7)
└─ [LLM_CALL] claude-sonnet-5 — "Summarize the result for the user." (span-8)Each line shows the span type, a type-specific summary, and the span's id. Nesting reflects the parent_id relationships in the trace file.
Malformed lines fail loudly with the file, line number, and reason:
Failed to parse trace.agtrace:2 — invalid JSON (Unexpected token 'o', "not json" is not valid JSON)
Line: not jsonWeb viewer
spantrace view starts a local server and opens the trace in your browser as an interactive tree with a detail panel for the selected span:
spantrace view fixtures/sample.agtraceBy default it binds to an OS-assigned ephemeral port; pass --port to pin a specific one:
spantrace view fixtures/sample.agtrace --port 4317The server reads the file once at startup — it doesn't watch for changes or support live/streaming ingestion.
The .agtrace format
A .agtrace file is JSONL — one JSON object per line, each representing a single span. Every span has:
| field | type | notes |
| ----------- | --------------------------------------------------------------------- | ----------------------------- |
| id | string | unique span id |
| parent_id | string \| null | null for root spans |
| type | "llm_call" \| "tool_call" \| "tool_result" \| "error" \| "retry" | discriminates the data shape |
| timestamp | string (ISO 8601) | |
| data | object | shape depends on type |
See src/schema.ts for the full per-type data payload definitions.
Development
npm test # run the test suite (vitest)
npm run build # compile the CLI/server and build the frontend
npm run dev -- <file> # run the CLI from source, no build step
npm run dev -- view <file> # run the viewer from source (serves the last built frontend)To iterate on the frontend with hot reload, run the backend and frontend dev servers side by side:
npm run dev:server -- fixtures/sample.agtrace --port 4317 # terminal 1
npm run dev:frontend # terminal 2, proxies /api to :4317License
Apache-2.0
