Skip to content
Download PDF

Harness Metrics ​

A harness you can't measure is a harness you can't tune. forge metrics aggregates the state the enforced gates already record — across every change, active and archived — so you can see whether the harness is doing its job.

No extra instrumentation: the numbers come from the session timeline, the circuit-breaker state, the budget ledger, and secscan waivers.

Usage ​

sh
forge metrics            # readable rollup
forge metrics --json     # stable machine output for dashboards / CI
Harness metrics (2 change(s): 1 active, 1 archived)

Verify      2 run(s), 1 failed  (50% pass)
Breaker     0 change(s) with an OPEN breaker, 0 attempt(s), 0.0 avg/change
Budget      1200 tokens, 7 tool-call(s), 0 change(s) exceeded a ceiling
Secscan     0 waived finding(s)
Timeline    5 event(s)  (verify 2, budget 1, note 1, tool 1)
Contributors  Ana, Claude (agent), María (backend)

What each line tells you ​

LineReads onWhat a bad number means
Verifytimeline verify eventsA low pass rate means the agent is shipping work that doesn't hold up — tighten the spec or the tests, not the breaker
Breakerverify-attempts.yamlConstantly opening → the threshold is too tight, or changes are being scoped too large and the loop thrashes
Budgetbudget.yamlRegular ceiling breaches → the ceilings are wrong, or the work per change is too big
Secscanwaiver ledgerWaivers piling up → findings are being acknowledged rather than fixed
Timeline / Contributorssession logVolume and who produced it; useful on a shared repo

Read the rollup, not the single change

One change tells you about that change. The rollup tells you about the harness. Look at it after a batch of work, and tune thresholds from the trend — not from the last thing that annoyed you.

Degradation ​

Every per-change read is best-effort: a corrupt or missing state file zeroes that one dimension and the report still renders. Only a missing .forge/changes directory is an error — an empty one is a valid zero report. With no recorded runs, the verify line reads no runs recorded rather than 0% pass, which would look like failure instead of "no data yet".

See also ​