# trace-analyzer (/tools/trace-analyzer)



`@zumik/trace-analyzer` is the open-source JavaScript/TypeScript analyzer for Zumik workload traces. It turns a metadata-only trace bundle into a reuse waterfall and a [Workload Reuse Score](/concepts/workload-reuse-score) - the same numbers the hosted diagnostic produces, computed entirely on your machine. No raw prompt text is required or inspected.

It exists so the WRS logic is runnable without the Rust toolchain. It is the JavaScript companion to the [`zumik` CLI](/tools/cli); both share the scoring rules so the output agrees.

## Install [#install]

```bash
npm install -g @zumik/trace-analyzer
```

The package is `@zumik/trace-analyzer` `0.1.0` (Apache-2.0), ESM, with bundled types. The CLI binary is `zumik-trace-analyzer`.

## Use the CLI [#use-the-cli]

Capture a bundle with [`zumik proxy`](/tools/trace-capture-proxy) (or export one in the trace envelope format), then analyze it. It reads a file argument or stdin.

```bash
zumik-trace-analyzer workload.jsonl
cat workload.jsonl | zumik-trace-analyzer --json
```

It accepts both a JSON array of traces and JSONL (one trace per line - the format `zumik proxy` writes). Output is the reuse waterfall, the Workload Reuse Score with its band, and the lowest-complexity execution profile the evidence supports.

```text title="Output"
Workload Reuse Score: 71.0 / 100   (prioritize optimization pilot)
Recommended profile:  BYOC pilot worth evaluating
Traces analyzed:      512

Reuse waterfall:
  Total input tokens       9200000  100.0%  ████████████████████
  Eligible reuse           7360000   80.0%  ████████████████
  Candidate reuse          7360000   80.0%  ████████████████
  Realized reused          3680000   40.0%  ████████
  Missed opportunity       3680000   40.0%  ████████

Notes:
  - Of 7360000 candidate reusable tokens, 3680000 were captured (50% capture rate).
  - 3680000 tokens of reuse opportunity were missed; investigate prompt ordering and cache-key strategy before changing infrastructure.
```

Add `--json` for the full report object.

## Library API [#library-api]

Import the analyzer to compute the report in your own tooling.

```ts
import { parseTraces, buildReport } from "@zumik/trace-analyzer";

const report = buildReport(parseTraces(fileContents));
console.log(report.workload_reuse_score, report.recommended_profile);
```

`parseTraces(raw: string): Trace[]` detects the format: a leading `[` is a JSON array, anything else is parsed as JSONL one trace per line, so a partially-written capture still yields every complete line.

`buildReport(traces: Trace[]): DiagnosticReport` returns the full report:

```ts
interface DiagnosticReport {
  object: "diagnostic_report";
  trace_count: number;
  workload_reuse_score: number;
  band: "strong_fit" | "plausible_fit" | "limited_fit" | "weak_fit";
  recommended_action: string;
  components: WrsComponents;       // the six weighted components
  waterfall: ReuseWaterfall;       // total → eligible → candidate → realized → missed
  recommended_profile:
    | "optimize_prompt_construction"
    | "managed_provider_tuning"
    | "byok_migration"
    | "byoc_pilot_worth_evaluating";
  notes: string[];
}
```

The lower-level building blocks are exported too: `waterfallFromTraces`, `componentsFromTraces`, `score`, `band`, and `recommendedAction`, along with the `Trace`, `Observed`, `Schedule`, and `WrsComponents` types.

## The trace envelope [#the-trace-envelope]

A trace is the metadata-only subset the analyzer needs. It mirrors the Rust `Trace`, so a bundle written by `zumik proxy` parses here unchanged.

```ts
interface Trace {
  trace_id: string;
  privacy_mode: "metadata" | "tokenized" | "encrypted_full_fidelity" | "synthetic";
  prefix_family_id?: string | null;
  schedule?: {
    arrival_offset_ms?: number;
    session_id?: string | null;
    branch_id?: string | null;
    concurrency_group?: string | null;
  };
  observed: {
    resolved_target: string;
    ttft_ms: number;
    latency_ms: number;
    input_tokens: number;
    candidate_reuse_tokens: number;
    realized_reused_tokens: number;
    output_tokens: number;
    attempt_count: number;
  };
}
```

<Note>
  The report is valuable even when its conclusion is "BYOC is unnecessary" - an honest, common outcome. A strong score with most of the reuse already captured points at provider tuning, not a migration. Only a large *missed* gap on a strong-fit workload suggests evaluating BYOC. See [reuse metrics](/concepts/reuse-metrics).
</Note>

## See also [#see-also]

<CardGroup cols="2">
  <Card title="zumik CLI" icon="terminal" href="/tools/cli">
    The Rust CLI with the same score plus prompt linting and trace capture.
  </Card>

  <Card title="Trace-capture proxy" icon="server" href="/tools/trace-capture-proxy">
    How to produce a trace bundle to feed this analyzer.
  </Card>
</CardGroup>
