Skip to content

JSLEEKR/agent-trace-debugger

Repository files navigation

agent-trace-debugger

Debug, diff, and replay AI agent traces

TypeScript Tests License npm

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.


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
✏️ Trace Collector Auto-instrument OpenAI and Anthropic SDKs, or build spans manually with the fluent SpanBuilder API
📦 SQLite + FTS5 Store Persistent storage with full-text search across all span inputs and outputs
🔄 Step-by-Step Replay Walk through any trace span-by-span with breadcrumb navigation
🔍 Trace Diff LCS-based structural alignment, content diffs, metrics diffs, and automatic divergence detection
📊 Multi-Trace Compare Compare N traces to find the cheapest, fastest, and best run
🔎 Full-Text Search FTS5-powered search across span names, inputs, and outputs
📈 Aggregated Stats Cost, tokens, latency, and per-model breakdown across all recorded traces
📤 Export (HTML/MD/JSON) Export traces as self-contained HTML, Markdown for GitHub, or raw JSON
🏷️ Tags Attach arbitrary string tags to traces for grouping and filtering
💬 Annotations Attach free-text notes to any span for post-hoc commentary
💰 Cost Alerts Budget monitoring with warning/exceeded callbacks, checked automatically after each trace
🔧 Tool Result Capture Auto-close pending tool spans when results appear, or record results manually
Parallel Spans Trace concurrent tool calls with isolated async contexts via startParallelSpans()
🔌 Generic Adapter wrapFunction() instruments any async function without an SDK-specific adapter
🗑️ Maintenance Prune old or errored traces with cleanup, reclaim space with vacuum
💻 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, and message_delta events 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.

License

MIT

Releases

No releases published

Packages

 
 
 

Contributors