Summary
traceroot traces get takes exactly one input — the trace id — and offers no way to bound what comes back. Under --json the entire trace, every span included, is serialized as a single line (src/commands/traces/get.ts:51, one-line-per-document by design in src/output.ts:53-55). The human tree renderer recursively prints every span with no depth or count cap (src/render/tree.ts:81-105). There is no --max-spans, --depth, --errors-only, or field selection.
For a small trace this is fine. For a several-thousand-span agent trace it is a multi-megabyte single line — a context bomb for the very consumer the CLI targets: a coding agent piping traces get --json into its own context. And it gets strictly worse the moment span input/output becomes fetchable through get (the backend already supports a fields projection): today's unbounded output is span skeletons; tomorrow's is skeletons plus every prompt and completion in the trace.
Current behavior
traceroot traces get <id> --json → one line containing the full trace document. Output size is linear in span count with no ceiling.
- Human mode renders the complete span tree; deep or wide traces flood the terminal.
- There is no way to ask for "just the error spans", "the top 2 levels", "at most 50 spans", or "only these fields" — the choices are everything, or the separate
traces export disk round-trip.
- Because the JSON is one physical line, line-oriented tooling (
grep, head) cannot subset it; the only recourse is jq over the whole document, which materializes all of it anyway.
Proposal
--max-spans <n> — cap emitted spans, with an explicit truncation marker and the true total count.
--depth <n> — cap tree depth in both human and JSON output.
--errors-only — only error-status spans plus their ancestor chain (the top debugging query).
- Field selection — pass through the backend's
fields groups so payload size is opt-in.
--output jsonl — one span per line (trace header first), making output streamable and greppable: traceroot traces get <id> --output jsonl | grep '"status":"error"' pays only for the spans that matter.
Impact
- A single
traces get --json on a large trace can consume a huge share of an agent's context window (or exceed a tool-output cap) for a task that needed three error spans.
- Deep traces scroll the useful root/error information out of a human's view with no recourse.
- Bounding is a prerequisite for shipping span I/O through
get — without it, that needed feature becomes a bigger context bomb.
- Single-line JSON defeats the shell idioms scripts reach for first;
jsonl closes that cheaply.
Acceptance criteria
traces get supports at least a span-count cap, an errors-only filter, and field selection; truncated output explicitly marks truncation and reports the true total.
--output jsonl emits one span per line with a documented first-line trace header; piping to head stays EPIPE-clean and yields valid JSON per line.
- Human tree output respects
--depth/--max-spans and indicates elision (e.g. … 4,873 more spans).
- Defaults are backward-compatible (no flags → current full output); flags documented in
--help with an example.
- Contract tests cover truncation markers and jsonl validity.
Summary
traceroot traces gettakes exactly one input — the trace id — and offers no way to bound what comes back. Under--jsonthe entire trace, every span included, is serialized as a single line (src/commands/traces/get.ts:51, one-line-per-document by design insrc/output.ts:53-55). The human tree renderer recursively prints every span with no depth or count cap (src/render/tree.ts:81-105). There is no--max-spans,--depth,--errors-only, or field selection.For a small trace this is fine. For a several-thousand-span agent trace it is a multi-megabyte single line — a context bomb for the very consumer the CLI targets: a coding agent piping
traces get --jsoninto its own context. And it gets strictly worse the moment span input/output becomes fetchable throughget(the backend already supports afieldsprojection): today's unbounded output is span skeletons; tomorrow's is skeletons plus every prompt and completion in the trace.Current behavior
traceroot traces get <id> --json→ one line containing the full trace document. Output size is linear in span count with no ceiling.traces exportdisk round-trip.grep,head) cannot subset it; the only recourse isjqover the whole document, which materializes all of it anyway.Proposal
--max-spans <n>— cap emitted spans, with an explicit truncation marker and the true total count.--depth <n>— cap tree depth in both human and JSON output.--errors-only— only error-status spans plus their ancestor chain (the top debugging query).fieldsgroups so payload size is opt-in.--output jsonl— one span per line (trace header first), making output streamable and greppable:traceroot traces get <id> --output jsonl | grep '"status":"error"'pays only for the spans that matter.Impact
traces get --jsonon a large trace can consume a huge share of an agent's context window (or exceed a tool-output cap) for a task that needed three error spans.get— without it, that needed feature becomes a bigger context bomb.jsonlcloses that cheaply.Acceptance criteria
traces getsupports at least a span-count cap, an errors-only filter, and field selection; truncated output explicitly marks truncation and reports the true total.--output jsonlemits one span per line with a documented first-line trace header; piping toheadstays EPIPE-clean and yields valid JSON per line.--depth/--max-spansand indicates elision (e.g.… 4,873 more spans).--helpwith an example.