FOR AI ENGINEERSRead agent traces
Read agent traces
at the speed of ⌘K.
Tool calls, spans, structured outputs, eval sets — it's all deeply-nested JSON now. Ask which span failed, how many tokens a run burned, or which evals regressed. QDev writes the jq and runs it locally.
- ✓Triage a failing run without
jqgymnastics or a scratch script - ✓Pass rates & token counts are exact — jq computes them, not a model
- ✓Prompts & completions stay local — nothing uploaded
⌘K
try
● TRACE.JSON — RUN a3f1 · 214 SPANS · LOCAL
{
"spans": [
{
"name": "plan",
"kind": "llm",
"model": "gpt-5",
"ms": 1840,
"tokens": 2110,
"status": "ok"
},
{
"name": "search_web",
"kind": "tool",
"model": null,
"ms": 920,
"tokens": 0,
"status": "ok"
},
{
"name": "fetch_page",
"kind": "tool",
"model": null,
"ms": 210,
"tokens": 0,
"status": "error"
}
]
}↑ Ask about the run — jq scans all 214 spans locally. Only the schema is ever sent, never prompt or completion text.
exact metrics · reproducible jq · nothing uploaded
SOUND FAMILIAR?
Debugging the black box
Malformed tool-call JSON
The model returned arguments that don't parse, and the failure is buried three levels into a 200-span trace.
Eval sets too big to open
A 60 MB JSONL of results won't load in your editor, and you just need the pass rate per suite.
jq you rewrite every run
group_by, select on a nested status, sum the tokens — you know the query exists, you just don't want to author it again.
ASK THE TRACE ANYTHING
From raw spans to a root cause
🧯
Triage failures
Jump straight to the span that errored, or every tool call whose output failed to parse.
spans where status is error, with the message
⏱️
Latency & cost
Sum tokens by model, find the slowest step, total the wall-clock of a run — exact, via jq.
total tokens and cost by model
🧪
Score eval runs
Pass rate per suite, regressions vs a baseline, the cases that flipped — no scratch notebook.
pass rate grouped by suite
🔧
Inspect tool calls
Pull every function call's name and arguments across the conversation into one flat list.
list every tool call name and its arguments
FITS YOUR EVAL LOOP
Every format you already work in
TRACES
Agent spans
OpenTelemetry-style or your own — deeply nested runs, flattened by one ask.
TOOL CALLS
Structured output
Function-calling args and JSON-mode responses, validated against the shape.
JSONL
Eval sets
Line-delimited results — aggregate pass/fail without a parsing script.
LOGS
Request logs
Prompt/response logs and streaming NDJSON, grouped and counted locally.
# QDev: "eval cases that regressed vs baseline" → editable jq
[.cases[] | select(.pass == false)] | group_by(.suite)
| map({suite: .[0].suite, failed: length}) | sort_by(-.failed)
● YOUR PROMPTS ARE YOURS
Traces never leave the tab.
Prompts, completions, tool outputs, customer data caught in a span — the values stay local. Only the schema (span shape & field types) and your question are ever sent, and only on the hosted tier. Want zero egress? Run local AI, free.
✓jq runs in a sandboxed Web Worker — no network access
✓Hosted proxy is stateless & zero-retention — logs nothing
✓No trace exporter, no vendor account, no data pipeline to set up
Your agent failed. Find out why.
Install free, keep your traces local, and let ⌘K write the jq that finds the failing span.