agent-trace-debugger
Chrome DevTools for AI agent pipelines - debug, replay, and diff agent executions
README
agent-trace-debugger
Debug, diff, and replay AI agent traces
Record every LLM call, tool invocation, and reasoning step your agent makes. Then diff two runs side-by-side to find exactly where behavior diverged.
</div>Why
Building AI agents is hard. Debugging them is harder.
- "It worked yesterday." -- LLM non-determinism means the same prompt can produce different tool calls, different reasoning chains, different outcomes. You need a way to see exactly what changed between two runs.
- "Which call is eating my budget?" -- A single agent run can make dozens of LLM calls across multiple models. Without per-span cost and token tracking, you are flying blind.
- "I can't reproduce the bug." -- Agent executions are ephemeral. Once the run is over, the intermediate steps are gone. You need a recording you can replay step by step.
Features
| | Feature | Description |
|---|---|---|
| :pencil2: | Trace Collector | Auto-instrument OpenAI and Anthropic SDKs, or build spans manually with the fluent SpanBuilder API |
| :package: | SQLite + FTS5 Store | Persistent storage with full-text search across all span inputs and outputs |
| :arrows_counterclockwise: | Step-by-Step Replay | Walk through any trace span-by-span with breadcrumb navigation |
| :mag: | Trace Diff | LCS-based structural alignment, content diffs, metrics diffs, and automatic divergence detection |
| :bar_chart: | Multi-Trace Compare | Compare N traces to find the cheapest, fastest, and best run |
| :mag_right: | Full-Text Search | FTS5-powered search across span names, inputs, and outputs |
| :chart_with_upwards_trend: | Aggregated Stats | Cost, tokens, latency, and per-model breakdown across all recorded traces |
| :outbox_tray: | Export (HTML/MD/JSON) | Export traces as self-contained HTML, Markdown for GitHub, or raw JSON |
| :label: | Tags | Attach arbitrary string tags to traces for grouping and filtering |
| :speech_balloon: | Annotations | Attach free-text notes to any span for post-hoc commentary |
| :moneybag: | Cost Alerts | Budget monitoring with warning/exceeded callbacks, checked automatically after each trace |
| :wrench: | Tool Result Capture | Auto-close pending tool spans when results appear, or record results manually |
| :fast_forward: | Parallel Spans | Trace concurrent tool calls with isolated async contexts via startParallelSpans() |
| :electric_plug: | Generic Adapter | wrapFunction() instruments any async function without an SDK-specific adapter |
| :wastebasket: | Maintenance | Prune old or errored traces with cleanup, reclaim space with vacuum |
| :computer: | CLI (15 commands) | list, show, record, replay, diff, compare, search, stats, export, tag, untag, tags, annotate, cleanup, vacuum |
Quick Start
npm install agent-trace-debugger
import { Tracer, FileExporter, SpanKind } from 'agent-trace-debugger';
// 1. Create a tracer with a file exporter
const tracer = new Tracer({
name: 'my-agent',
exporter: new FileExporter('./traces/run.json'),
});
// 2. Start a trace
const root = tracer.startTrace('agent-run');
// 3. Record spans
const span = tracer.startSpan('think', SpanKind.REASONING);
span.setOutput('I should search the database first.');
tracer.endSpan(span);
// 4. End and export
const trace = await tracer.endTrace();
Then inspect the trace from the command line:
npx trace-debugger show <trace-id>
npx trace-debugger replay <trace-id>
Collector SDK
Tracer
The Tracer manages the lifecycle of a single trace. It creates spans, tracks parent-child relationships via AsyncLocalStorage, and exports the finished trace.
import { Tracer, StoreExporter, SQLiteTraceStore } from 'agent-trace-debugger';
const store = new SQLiteTraceStore('./traces.db');
const tracer = new Tracer({
name: 'my-agent',
exporter: new StoreExporter(store),
});
const root = tracer.startTrace('run-42');
// Spans are automatically parented to the current context
const llmSpan = tracer.startSpan('gpt-4o-call', SpanKind.LLM_CALL);
llmSpan.setOutput('The answer is 42.');
llmSpan.setMetadata({
model: 'gpt-4o',
promptTokens: 150,
completionTokens: 12,
cost: 0.00093,
});
tracer.endSpan(llmSpan);
const trace = await tracer.endTrace();
SpanBuilder (Fluent API)
For lower-level control, use SpanBuilder directly:
import { SpanBuilder, SpanKind } from 'agent-trace-debugger';
const activeSpan = new SpanBuilder(traceId)
.named('search-documents')
.ofKind(SpanKind.TOOL_CALL)
.withInput(JSON.stringify({ query: 'quarterly revenue' }))
.childOf(parentSpanId)
.start();
// ... do work ...
activeSpan.setOutput(JSON.stringify(results));
activeSpan.setMetadata({ latency: 230 });
const span = activeSpan.end();
Parallel Spans
Trace concurrent work (e.g. multiple tool calls) with isolated async contexts so nested spans parent correctly:
const branches = tracer.startParallelSpans(
['search-docs', 'query-db', 'call-api'],
SpanKind.TOOL_CALL,
);
await Promise.all(
branches.map(({ span, run }) =>
run(async () => {
// Any startSpan() calls here will parent under this branch's span
const result = await doWork();
span.setOutput(result);
tracer.endSpan(span);
}),
),
);
Exporters
| Exporter | Description |
|---|---|
| FileExporter(path) | Writes the trace as a JSON file |
| StoreExporter(store) | Saves the trace into a SQLiteTraceStore |
| HtmlExporter(path) | Writes a self-contained HTML report with collapsible span tree |
| MarkdownExporter(path) | Writes a structured Markdown document |
SDK Integration
OpenAI Adapter
Automatically instruments client.chat.completions.create to capture every LLM call and tool invocation as spans. Supports both sync and streaming responses.
import { Tracer, StoreExporter, OpenAIAdapter } from 'agent-trace-debugger';
import OpenAI from 'openai';
const client = new OpenAI();
const tracer = new Tracer({ name: 'openai-agent', exporter: new StoreExporter(store) });
const root = tracer.startTrace('chat-session');
// Instrument the client
const adapter = new OpenAIAdapter(root.traceId);
adapter.instrument(client);
// All calls are now traced automatically
const response = await client.chat.completions.create({
model: 'gpt-4o',
messages: [{ role: 'user', content: 'What is 2+2?' }],
});
// ^ Creates an llm_call span with model, tokens, and cost metadata.
// If the response includes tool_calls, each one becomes a child tool_call span.
// Restore original method when done
adapter.restore(client);
await tracer.endTrace();
Anthropic Adapter
Automatically instruments client.messages.create to capture LLM calls and tool_use content blocks.
import { Tracer, StoreExporter, AnthropicAdapter } from 'agent-trace-debugger';
import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic();
const tracer = new Tracer({ name: 'claude-agent', exporter: new StoreExporter(store) });
const root = tracer.startTrace('claude-session');
// Instrument the client
const adapter = new AnthropicAdapter(root.traceId);
adapter.instrument(client);
// All calls are now traced automatically
const response = await client.messages.create({
model: 'claude-4-sonnet',
max_tokens: 1024,
messages: [{ role: 'user', content: 'Summarize this document.' }],
});
// ^ Creates an llm_call span with input/output tokens.
// tool_use content blocks become child tool_call spans.
adapter.restore(client);
await tracer.endTrace();
Generic Adapter
wrapFunction() instruments any async (or sync) function without requiring an SDK-specific adapter. It creates a span around each invocation, records input/output, and attaches it to the current trace context.
import { wrapFunction, SpanKind } from 'agent-trace-debugger';
import type { SpanTracker } from 'agent-trace-debugger';
const tracker: SpanTracker = {
traceId: root.traceId,
onSpanEnd: (span) => finishedSpans.push(span),
};
const tracedFetch = wrapFunction(fetchDocuments, tracker, {
name: 'fetch-documents',
kind: SpanKind.TOOL_CALL,
extractInput: (query) => JSON.stringify(query),
extractOutput: (result) => JSON.stringify(result),
extractUsage: (result) => ({ promptTokens: result.tokens }),
});
// Use it as a drop-in replacement -- spans are created automatically
const docs = await tracedFetch({ query: 'quarterly revenue' });
Streaming Support
Both adapters automatically handle streaming responses. When you pass stream: true to either SDK, the adapter accumulates chunks, reconstructs the full response, and records it as a single span.
- OpenAI: Accumulates streamed content deltas and extracts token usage from the final chunk
- Anthropic: Processes
message_start,content_block_delta, andmessage_deltaevents to reconstruct the complete message
When streaming responses do not include exact token counts, the built-in estimateTokens fallback provides approximate usage metrics so cost tracking remains functional.
Tool Result Capture
Both adapters automatically close pending tool-call spans when tool results appear in a subsequent API call. You can also record a result explicitly:
// Manually record the output of a tool call span
adapter.recordToolResult(toolCallId, resultContent);
Auto-detection: When the next LLM call contains a tool_result block (Anthropic) or a tool role message (OpenAI) referencing a previously opened tool span, the adapter matches it by ID and closes the span with the result automatically -- no manual wiring required.
Trace Replay
Step through a recorded trace span-by-span using the ReplayEngine or the CLI.
Programmatic API
import { ReplayEngine } from 'agent-trace-debugger';
const engine = new ReplayEngine(trace);
let frame = engine.current();
console.log(frame.span.name); // "agent-run"
console.log(frame.position); // "1/5"
console.log(frame.breadcrumb); // [{ spanId: "...", name: "agent-run" }]
frame = engine.next(); // advance to next span
frame = engine.prev(); // go back one span
frame = engine.jumpTo(spanId); // jump to specific span
engine.toStart(); // return to first span
engine.toEnd(); // jump to last span
CLI Replay
# Replay all steps sequentially
trace-debugger replay <trace-id>
# Jump to a specific step
trace-debugger replay <trace-id> --step 3
# Compact output (span name + position only, no input/output bodies)
trace-debugger replay <trace-id> --compact
Example output:
[1/5] agent-run (reasoning)
input: "What is the capital of France?"
output: "I should look this up."
[2/5] search-documents (tool_call)
input: {"query":"capital of France"}
output: {"result":"Paris"}
[3/5] gpt-4o-call (llm_call)
input: "Given the search result, answer the question."
output: "The capital of France is Paris."
...
The --budget flag on show and record prints a cost warning when the trace exceeds a threshold:
trace-debugger show <trace-id> --budget 0.10
trace-debugger record --file run.json --budget 0.05
Diff Analysis
This is the core feature. Compare two traces to understand exactly what changed and why.
The diff engine performs four analyses in a single analyze() call:
1. Structural Diff
LCS-based alignment detects added, removed, and reordered spans between two runs.
import { analyze } from 'agent-trace-debugger';
const result = analyze(traceA, traceB);
console.log(result.structuralDiff.added); // Span[] - spans only in B
console.log(result.structuralDiff.removed); // Span[] - spans only in A
console.log(result.structuralDiff.reordered); // [Span, Span][] - position changes
2. Content Diff
For each matched span pair, computes line-level diffs of input and output, classifying changes as minor (whitespace only) or major (substantive).
for (const diff of result.contentDiffs) {
console.log(diff.spanName); // "chat.completions.create"
console.log(diff.significance); // "major" | "minor"
console.log(diff.inputDiff); // unified diff string
console.log(diff.outputDiff); // unified diff string
}
3. Metrics Diff
Per-span and trace-level deltas for cost, latency, and token usage.
const metrics = result.metricsSummary;
console.log(metrics.costChangePercent); // -12.5 (percent)
console.log(metrics.latencyChangePercent); // +8.3
console.log(metrics.totalCostA); // 0.0234
console.log(metrics.totalCostB); // 0.0205
for (const s of metrics.perSpan) {
console.log(s.spanName, s.costDelta, s.latencyDelta, s.tokenDelta);
}
4. Divergence Finder
Walks matched pairs chronologically to find the first point of divergence, classifying it as:
llm_nondeterminism-- same input, different output (the LLM chose differently)input_change-- different input (caused by an upstream change)
if (result.divergencePoint) {
console.log(result.divergencePoint.type); // "llm_nondeterminism"
console.log(result.divergencePoint.cause); // human-readable explanation
console.log(result.divergencePoint.downstreamImpact); // 3 subsequent spans affected
}
Summary
Every diff result includes a human-readable summary string:
console.log(result.summary);
// "Structural changes: 1 added, 1 removed spans. 2 span(s) have major content
// differences. Divergence at "plan": llm_nondeterminism, affecting 3 downstream
// span(s). Cost decreased by 12.5%."
CLI
# Full diff between two traces
trace-debugger diff <trace-id-1> <trace-id-2>
# Short summary only
trace-debugger diff <trace-id-1> <trace-id-2> --format short
Multi-Trace Compare
Compare two or more traces at once to identify the cheapest, fastest, and overall best run.
import { analyze, generateCompareSummary } from 'agent-trace-debugger';
// Generate pairwise diffs between adjacent traces
const diffs = [
analyze(traceA, traceB),
analyze(traceB, traceC),
];
const summary = generateCompareSummary(diffs);
console.log(summary.runs[summary.cheapest].totalCost); // lowest cost
console.log(summary.runs[summary.fastest].totalLatency); // lowest latency
console.log(summary.runs[summary.bestRun].score); // best composite score
console.log(summary.text); // formatted comparison table
# CLI: compare 2 or more traces
trace-debugger compare <id1> <id2> [id3 ...]
Example output:
=== Trace Comparison Summary ===
Run | Cost | Latency (ms) | Score
--- | ---------- | ------------ | -----
0 | $0.0234 | 2340 | 0.026740
1 | $0.0205 | 1890 | 0.022390
2 | $0.0310 | 3100 | 0.034100
Cheapest: Run 1 ($0.0205)
Fastest: Run 1 (1890ms)
Most different: Run 2
Best run: Run 1 (lowest combined score)
Search & Stats
Full-Text Search
SQLite FTS5-powered search across span names, inputs, and outputs.
const store = new SQLiteTraceStore('./traces.db');
// Search all spans
const spans = store.searchSpans('quarterly revenue');
// Search within a specific trace
const spans = store.searchSpans('error', traceId);
# CLI search
trace-debugger search "quarterly revenue"
trace-debugger search "error" --kind llm_call --limit 20
Aggregated Statistics
import { aggregateStats } from 'agent-trace-debugger';
const stats = aggregateStats(store, { since: '2026-01-01', model: 'gpt-4o' });
console.log(stats.count); // 47 traces
console.log(stats.totalCost); // 1.23
console.log(stats.avgCost); // 0.026
console.log(stats.totalTokens); // 142000
console.log(stats.avgLatency); // 2340 ms
for (const [model, data] of stats.modelBreakdown) {
console.log(model, data.count, data.cost, data.tokens);
}
# CLI stats
trace-debugger stats
trace-debugger stats --since 2026-01-01 --model gpt-4o
Export Formats
Export any recorded trace to HTML, Markdown, or JSON for sharing and reporting.
# Export to self-contained HTML
trace-debugger export <trace-id> --format html --output report.html
# Export to Markdown (for GitHub issues/PRs)
trace-debugger export <trace-id> --format markdown --output trace.md
# Export to JSON (default)
trace-debugger export <trace-id> --format json --output trace.json
# Print to stdout (omit --output)
trace-debugger export <trace-id> --format json
| Format | Description |
|---|---|
| html | Self-contained HTML file with embedded CSS, collapsible span tree, and color-coded span kinds |
| markdown | Structured Markdown document suited for pasting into GitHub issues or pull requests |
| json | Raw JSON trace data |
Tags & Annotations
Tags
Attach arbitrary string tags to traces to group, filter, and organize runs.
// Attach tags at trace creation
const root = tracer.startTrace('agent-run', { tags: ['production', 'gpt-4o'] });
// Manage tags after the fact
store.addTag(traceId, 'reviewed');
store.removeTag(traceId, 'production');
// List all known tags with counts
const allTags = store.listTagsWithCounts();
// [{ tag: "production", count: 12 }, { tag: "reviewed", count: 5 }]
// Filter traces by tag
const traces = store.listTraces({ tags: ['reviewed'] });
trace-debugger tag <trace-id> production
trace-debugger untag <trace-id> production
trace-debugger tags
Annotations
Attach free-text notes to any span for post-hoc commentary, review, or debugging context.
// Add an annotation
store.addAnnotation(traceId, spanId, 'This retried due to rate limit', 'alice', new Date().toISOString());
// Retrieve annotations for a span
const annotations = store.getAnnotations(spanId);
// [{ text: "This retried due to rate limit", author: "alice", timestamp: "..." }]
trace-debugger annotate <trace-id> <span-id> "This span retried twice due to a rate limit."
trace-debugger annotate <trace-id> <span-id> "Looks correct" --author bob
Annotations are stored alongside the span and displayed in trace show output.
Cost Alerts
Monitor cumulative spend across traces and trigger callbacks when thresholds are crossed.
import { CostAlert, Tracer, StoreExporter, SQLiteTraceStore } from 'agent-trace-debugger';
const store = new SQLiteTraceStore('./traces.db');
const alert = new CostAlert({
budget: 5.00, // total budget in dollars
warningThreshold: 0.8, // fire onWarning at 80% of budget (default)
onWarning: (cumulative, budget) =>
console.warn(`Cost warning: $${cumulative.toFixed(4)} of $${budget.toFixed(2)} budget`),
onExceeded: (cumulative, budget) =>
console.error(`Budget exceeded: $${cumulative.toFixed(4)} > $${budget.toFixed(2)}`),
});
// Pass the alert to Tracer -- it auto-checks after every endTrace()
const tracer = new Tracer({
name: 'my-agent',
exporter: new StoreExporter(store),
costAlert: alert,
});
const root = tracer.startTrace('agent-run');
// ... record spans ...
await tracer.endTrace(); // CostAlert.check() is called automatically
// Query remaining budget programmatically
console.log(alert.getCumulativeCost()); // 3.42
console.log(alert.getRemainingBudget()); // 1.58
Maintenance
Keep the trace store lean by removing traces you no longer need and optimizing the database.
# Delete traces older than 30 days
trace-debugger cleanup --older-than 30d
# Delete all traces with error status
trace-debugger cleanup --status error
# Combine filters
trace-debugger cleanup --older-than 7d --status error
# Reclaim disk space after deletions (SQLite VACUUM)
trace-debugger vacuum
Monitor database size programmatically:
const store = new SQLiteTraceStore('./traces.db');
const bytes = store.getStorageSize();
console.log(`Store is ${(bytes / 1024 / 1024).toFixed(2)} MB`);
Examples
The examples/ directory contains three ready-to-run scripts:
| Script | Description |
|---|---|
| basic-usage.ts | Creates a tracer, records a few spans manually, and prints the finished trace |
| openai-agent.ts | Instruments an OpenAI client with OpenAIAdapter, runs a tool-use loop, and saves to SQLite |
| diff-two-runs.ts | Loads two traces from the store, calls analyze(), and prints the divergence report |
Run any example:
npx tsx examples/basic-usage.ts
npx tsx examples/openai-agent.ts
npx tsx examples/diff-two-runs.ts
Supported Models
Built-in cost calculation for the following models (per 1K tokens):
| Model | Prompt | Completion |
|---|---|---|
| claude-4-opus | $0.0150 | $0.0750 |
| claude-4-sonnet | $0.0030 | $0.0150 |
| claude-3.5-sonnet | $0.0030 | $0.0150 |
| claude-3.5-haiku | $0.0010 | $0.0050 |
| claude-3-opus | $0.0150 | $0.0750 |
| claude-3-sonnet | $0.0030 | $0.0150 |
| claude-3-haiku | $0.00025 | $0.00125 |
| gpt-4o | $0.0050 | $0.0150 |
| gpt-4o-mini | $0.00015 | $0.00060 |
| gpt-4-turbo | $0.0100 | $0.0300 |
| gemini-1.5-pro | $0.0035 | $0.0105 |
| gemini-1.5-flash | $0.000075 | $0.00030 |
| gemini-2.0-flash | $0.00010 | $0.00040 |
Custom models work with all features except automatic cost calculation. Token estimation uses model-aware character ratios (GPT ~4 chars/token, Claude ~3.5 chars/token) with a word-based fallback, returning the higher of the two estimates.
API Reference
Schema
| Export | Description |
|---|---|
| Trace | Trace type: id, name, startTime, endTime, rootSpanId, metadata, spans, tags |
| Span | Span type: id, traceId, parentSpanId, name, kind, status, startTime, endTime, input, output, metadata, children, annotations |
| SpanKind | Enum: llm_call, tool_call, reasoning, decision, custom |
| SpanStatus | Enum: ok, error |
| SpanMetadata | model, promptTokens, completionTokens, cost, latency, plus arbitrary keys |
| SpanAnnotation | text, author, timestamp |
| TraceFilter | Filter for listTraces: since, until, model, status, name, tags, limit, offset |
Collector
| Export | Description |
|---|---|
| Tracer | Main tracer class. startTrace(name?, { tags? }), startSpan(name, kind), endSpan(span), endTrace(), startParallelSpans(names, kind), getContext() |
| SpanBuilder | Fluent builder. named(), ofKind(), withInput(), childOf(), start() |
| ActiveSpan | Live span handle. setOutput(), setMetadata(), end(), getSpan(), plus id and traceId getters |
| TraceContext | Async context manager. currentSpan(), withSpan(span, fn) |
| CostAlert | Budget monitor. Constructor: { budget, warningThreshold?, onWarning?, onExceeded? }. Methods: check(trace), getCumulativeCost(), getRemainingBudget() |
Adapters
| Export | Description |
|---|---|
| OpenAIAdapter | Instruments client.chat.completions.create. Constructor: new OpenAIAdapter(traceId). Methods: instrument(client), restore(client), recordToolResult(id, result) |
| AnthropicAdapter | Instruments client.messages.create. Constructor: new AnthropicAdapter(traceId). Methods: instrument(client), restore(client), recordToolResult(id, result) |
| wrapFunction(fn, tracker, options?) | Generic adapter. Wraps any function as a traced span. Options: name, kind, extractInput, extractOutput, extractUsage |
| SpanTracker | Interface for wrapFunction: { traceId, onSpanEnd(span) } |
Exporters
| Export | Description |
|---|---|
| Exporter | Interface: export(trace, spans): Promise<void> |
| FileExporter | Writes trace as JSON to a file path |
| StoreExporter | Saves trace into a TraceStore |
| HtmlExporter | Writes self-contained HTML with collapsible span tree |
| MarkdownExporter | Writes structured Markdown document |
Store
| Export | Description |
|---|---|
| TraceStore | Interface: saveTrace(), getTrace(), listTraces(), searchSpans(), deleteTrace(), getStats(), close() |
| SQLiteTraceStore | Full implementation with additional methods: addTag(), removeTag(), listTags(), listTagsWithCounts(), addAnnotation(), getAnnotations(), cleanup(options), vacuum(), getStorageSize() |
| CleanupOptions | { olderThanDays?, status? } |
Diff
| Export | Description |
|---|---|
| analyze(traceA, traceB) | Returns DiffResult with structural, content, metrics diffs and divergence point |
| DiffResult | { structuralDiff, contentDiffs, metricsSummary, divergencePoint?, summary } |
| StructuralDiff | { matched, added, removed, reordered } |
| ContentDiff | Per-span input/output diffs with significance (major or minor) |
| MetricsSummary | { totalCostA, totalCostB, costChangePercent, totalLatencyA, totalLatencyB, latencyChangePercent, perSpan } |
| DivergencePoint | { type, spanA, spanB, cause, downstreamImpact } |
| generateCompareSummary(diffs) | Returns CompareSummary with runs, cheapest, fastest, mostDifferent, bestRun, text |
| alignTraces(spansA, spansB) | LCS-based span alignment returning matched, unmatchedA, unmatchedB |
| findDivergencePoint(matched) | Locate first divergence in matched span pairs |
Replay
| Export | Description |
|---|---|
| ReplayEngine | Constructor: new ReplayEngine(trace). Methods: current(), next(), prev(), jumpTo(spanId), toStart(), toEnd(). Property: total |
| ReplayFrame | { span, position, depth, breadcrumb } |
| ReplayCursor | Internal cursor tracking position state |
Stats
| Export | Description |
|---|---|
| aggregateStats(store, filter?) | Returns AggregatedStats: { count, totalCost, avgCost, totalTokens, avgLatency, modelBreakdown } |
| StatsFilter | { since?, model? } |
| ModelStats | { count, cost, tokens } |
Utilities
| Export | Description |
|---|---|
| calculateCost(model, promptTokens, completionTokens) | Returns cost in dollars or null for unsupported models |
| getSupportedModels() | Returns array of model names with built-in pricing |
| estimateTokens(text) | Character-based token estimate (~4 chars/token) |
| estimateTokensByWords(text) | Word-based token estimate (~1.3 tokens/word) |
| estimateTokensForModel(text, model) | Model-aware estimate returning the higher of char-based and word-based |
| generateTraceId() | Generate a unique trace ID |
| generateSpanId() | Generate a unique span ID |
CLI Commands
trace-debugger list [--since <date>] [--model <model>] [--status <status>] [--limit <n>]
trace-debugger show <id> [--budget <dollars>]
trace-debugger record --file <path> [--budget <dollars>]
trace-debugger replay <id> [--step <n>] [--compact]
trace-debugger diff <id1> <id2> [--format short|full]
trace-debugger compare <id1> <id2> [ids...] [--format short|full]
trace-debugger search <query> [--kind <kind>] [--limit <n>]
trace-debugger stats [--since <date>] [--model <model>]
trace-debugger export <id> [--format json|html|markdown] [--output <path>]
trace-debugger tag <id> <tag>
trace-debugger untag <id> <tag>
trace-debugger tags
trace-debugger annotate <trace-id> <span-id> "<text>" [--author <name>]
trace-debugger cleanup [--older-than <duration>] [--status <status>]
trace-debugger vacuum
Global option: --db <path> to specify a custom database file path.