Verify Circuit-Breaker
The verify circuit-breaker is one of Forge's four enforced controls. It bounds the iterations of the implement loop: after a change fails verification too many times in a row, the breaker opens, returns a non-zero exit, and forces an escalation to a human instead of retrying forever.
forge verify
forge verify runs the project's configured test/lint command plus spec scenario coverage, and prints a report ending in a verdict:
Verdict: PASSor
Verdict: FAILBare forge verify is read-only
Run without --change, forge verify is a reporter. It returns exit 0 even on FAIL — it tells you what happened but does not gate. This is backward compatible: existing scripts and workflows see no behavior change.
Opting into the breaker with --change
forge verify --change <c> opts into the circuit-breaker. Now Forge tracks consecutive verify failures for that change:
- At a threshold (default 3, override with
--max-failures N), it printsCIRCUIT OPENand returns a non-zero exit. This is the enforced "stop looping and escalate to a human." - A passing verify resets the streak to
0. forge verify --reset-breaker --change <c>clears the breaker after a human has intervened.
Progression (exit codes matter)
$ forge verify --change checkout # attempt 1
Verdict: FAIL
Breaker: 1/3 consecutive failures for change "checkout" — fix the smallest cause and re-run.
# exit 0
$ forge verify --change checkout # attempt 2
Verdict: FAIL
Breaker: 2/3 consecutive failures for change "checkout" — fix the smallest cause and re-run.
# exit 0
$ forge verify --change checkout # attempt 3
Verdict: FAIL
Breaker: CIRCUIT OPEN — 3 consecutive verify failures for change "checkout".
# exit 1 → any gate/loop halts; escalate to a humanNotice that attempts 1 and 2 return exit 0: the breaker warns while the streak builds, but only refuses at the threshold. Once open, the non-zero exit propagates — any gate or loop wired to the exit code halts.
Clearing the breaker
After a human looks at the failure and does something about it, clear the streak so the loop can resume:
forge verify --reset-breaker --change checkoutA subsequent passing verify would also reset it, but --reset-breaker is the explicit "I intervened" signal.
Persisted state
The breaker's state lives on disk, so it survives context compaction, restarts, and is visible to teammates:
# .forge/changes/checkout/verify-attempts.yaml
consecutive_failures: 3
open: true
last_verdict: FAIL
total_attempts: 7Because the file is git-friendly, the breaker state is part of the change's history, not a volatile in-memory counter.
Why it matters
In Fowler's harness model, the highest-ROI control is the feedback loop — the Sensor that observes a run and corrects it. The circuit-breaker is the fuse on that loop. Without it, a well-meaning agent will happily "retry forever," burning iterations against a failure it cannot fix. The breaker converts an unbounded retry into a bounded one that ends in a human decision.
Complementary controls
The breaker bounds iterations. Its complement, the spend budget, bounds cost. Both emit into the session timeline so verdicts and breaker state are auditable.
Next steps
- The enforcement doctrine — where the breaker sits among the four controls.
- Spend budget — the sibling gate that bounds cost instead of iterations.
- The guardrails gate — the control that blocks dangerous actions.
- Session timeline — where breaker verdicts land, attributed and auditable.
- Connect a live agent — wiring a Stop hook that runs the breaker.