Turn metrics

August 24, 2026 · View on GitHub

OMK records one JSON line per agent turn so harness changes can be measured instead of guessed.

CLI harness SOTA target

OMK targets state-of-the-art quality as a CLI coding-agent harness. SOTA is not verified. This is a product target, not a statement that the current release leads a benchmark or a named competitor cohort.

The target covers the harness layer:

DimensionPrimary measure
Task successsolved tasks and pass rate
Cost efficiencymodel cost and tokens per solved task
Latencywall-clock p50/p95 per solved task
Context efficiencyinput, cache, compaction, and tool-output tokens per solved task
Tool reliabilityfailure, retry, refusal, and intervention rates
Orchestrationcritical-path time, useful concurrency, and duplicate work
Recoveryinterrupted-run resume accuracy and repeated-run variance
Safetypolicy violations, unauthorized effects, and false-positive blocks
Maintainabilitycomplexity, module-size debt, and regression-gate health

No single feature count or self-score establishes leadership. OMK reports a dimension-specific result unless a preregistered aggregation defines an overall score.

Controlled comparison contract

A comparative harness run MUST hold the same model, same provider and model configuration, same task and revision, same budget, equivalent tool permissions, and comparable container, hardware, region, and concurrency constant. The harness is the treatment variable. If a factor cannot be held constant, the report must label the result non-comparative.

Every comparative report must include:

  • the date, harness versions, and named comparison cohort, with its inclusion rule frozen before execution;
  • immutable model, provider, container, environment, and configuration identities;
  • the task manifest, seeds, public prompt or sanitized prompt digest, budgets, run order, and stop policy;
  • sanitized per-task outcomes plus cost, token, latency, retry, and intervention data;
  • the confidence interval, significance threshold, minimum effect, and statistical test chosen before inspecting the result;
  • the exact commands and immutable manifests needed for reproducible evidence.

Use paired A/B measurements. Randomize or interleave pair order when provider or machine drift can bias one side. Do not combine values produced by different methods, working directories, task revisions, or warm/cold conditions. A roadmap projection remains a hypothesis even when its inputs are measured.

Evidence privacy

Benchmark evidence is private by default. Public artifacts may contain public or synthetic task identifiers, version and image digests, allowlisted runtime metadata, sanitized outcomes, and aggregate statistics. They must not contain credentials, private prompts, proprietary source, raw tool arguments or output, environment values, personal data, or absolute user paths.

Keep restricted raw evidence local or in an access-controlled store with an explicit owner and retention period. Normalize paths, redact content, scan for secrets and PII, and obtain human approval before publication. Digests and public task manifests preserve reproducibility without disclosing restricted content.

A public “SOTA,” “best,” “leading,” or “#1” claim requires a dated controlled comparison that places OMK on the relevant quality/cost/latency frontier without violating declared safety and regression floors. Until then, use “targets state-of-the-art quality.”

Harbor's Terminal-Bench runner and the SWE-bench containerized harness are reference evaluation surfaces. Their presence or a selected task list is infrastructure, not a benchmark result.

This is separate from the two things that already existed:

SurfacePurpose
core/run-journal.tsHash-chained integrity log (run started/finished/recovered, tool timeout). Answers "was this run tampered with or abandoned".
core/telemetry.tsInstall-time opt-in flag. Nothing else.
core/turn-metrics.tsPerformance and quality: cost, latency, tool failure rates, cache effectiveness.

Where it goes

<cwd>/.omk/metrics/turns.jsonl, append-only, rotated once past 8 MB (turns.jsonl.1), file mode 600.

VariableEffect
OMK_TURN_METRICS=0Disable recording entirely.
OMK_TURN_METRICS_DIRWrite somewhere else.

Reading it

omk stats                    # aggregate report for the current project
omk stats --dir <path>       # a different metrics directory
omk stats --json             # machine-readable summary
Turn metrics — 412 turns across 27 session(s)
  models        anthropic/claude-sonnet-4-5
  turn duration p50 4.2s · p95 31.8s
  input 91,204 · output 22,880 · cacheRead 1,904,551 · cacheWrite 88,100
  cache read share 95.4% of prompt-side usage
  cost          \$4.8812
  compactions 6 · failovers 1 · ctx plan hit 41.2%

  tool                 calls   fail%     p50     p95    total
  bash                   688    4.2%   210ms    3.1s     4.1m
  edit                   201    9.0%    38ms   140ms    12.4s

What is recorded

Counts, durations, ids, and error classes:

{
  "schemaVersion": "omk-turn-metrics-1",
  "sessionId": "…", "turnIndex": 12,
  "provider": "anthropic", "model": "claude-sonnet-4-5",
  "startedAtEpochMs": 1, "endedAtEpochMs": 2, "durationMs": 1,
  "usage": { "input": 100, "output": 20, "cacheRead": 900, "cacheWrite": 10, "costUsd": 0.0125 },
  "stopReason": "toolUse",
  "toolCalls": [{ "name": "bash", "durationMs": 120, "ok": false, "error": "exit 1" }],
  "toolCallCount": 1, "toolFailureCount": 1
}

Never recorded: prompt text, tool arguments, tool output, file contents, or environment values. Tool error strings are whitespace-collapsed and truncated to 200 characters — enough to tell failure modes apart, too short to carry a payload.

Metrics are advisory. A failed write is counted and dropped; it can never make a turn fail.

Capability baseline

Runtime metrics tell you what a session cost, not whether the harness can solve tasks. For that, scripts/tb-mini-suite.mjs selects a deterministic, difficulty-balanced Terminal-Bench 2.1 subset so scores are comparable across runs:

node scripts/tb-mini-suite.mjs             # human-readable selection
node scripts/tb-mini-suite.mjs --json      # feed a runner
node scripts/tb-mini-suite.mjs --seed 7    # a different fixed subset

Selection is a pure function of (tasks directory, seed, size): the same inputs always produce the same task list, which is the whole point of using it as a regression gate. Selection alone is not a capability result. The scoring run itself requires Docker, harbor, and real model spend — it is deliberately not wired into npm run check. Any comparison produced from it must follow the controlled comparison contract above.