Zumik
CLI & tools

trace-analyzer

The @zumik/trace-analyzer npm tool turns a metadata-only trace bundle into a reuse waterfall and Workload Reuse Score, with no Rust toolchain and no raw prompts.

@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 - 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; both share the scoring rules so the output agrees.

Install

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

Capture a bundle with zumik proxy (or export one in the trace envelope format), then analyze it. It reads a file argument or stdin.

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.

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

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

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:

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

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.

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;
  };
}

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.

See also

On this page