Skip to content
Download PDF

Bounded Autonomous Run ​

forge run executes an agent loop repeatedly and stops it the moment an enforced gate opens, escalating to a human instead of retrying forever.

sh
forge run --cmd 'claude -p "work the next task in tasks.md"'          # dry run
forge run --cmd '…' --max-iterations 3 --yes                          # execute

Two things to understand before using it ​

Forge has no model

Forge cannot write code. It has no LLM, no inference, no agent of its own. The loop orchestrates an executor you supply via --cmd — an agent CLI invocation — and enforces the harness gates between its iterations. Forge is the harness here, not the agent.

A deliberate exception to the doctrine

Everywhere else, forge is a configurator, not a step-firer: it prepares gates and evidence, and the agent host drives the loop. forge run is the one command that drives the loop itself. That exception is opt-in and bounded on purpose — read the safety posture below before using it.

Safety posture ​

PropertyBehavior
DefaultDry run. Without --yes it prints the plan and executes nothing
Iteration cap--max-iterations, default 5, hard ceiling 50
Already-open gateRefuses to start — zero executor invocations
Gate opens mid-runStops immediately, names the gate, exits non-zero
Gate check errorsStops. An unreadable gate is never assumed closed
Iterations exhaustedStops and escalates — finishing the cap is not success
Executor failsStops and escalates

Only one outcome is a clean exit: the executor signalling it is done. Every other ending prints escalate: a human should review before continuing and returns a non-zero exit code.

The plan output ​

$ forge run --change add-billing --cmd 'my-agent --once' --max-iterations 3
Plan: up to 3 iteration(s) on change "add-billing"
  executor: sh -c "my-agent --once"
  gates:    verify circuit-breaker, spend budget, secscan
  stop:     any gate opening halts the loop and escalates to a human

dry run: nothing executed (pass --yes to run)

The gates ​

Each is checked once before the first iteration and again after every one. All three are read-only here — the loop records no gate state of its own.

GateOpens when
verify circuit-breakerthe change's consecutive-failure streak has tripped
spend budgeta --max-tokens / --max-tool-calls ceiling is crossed
secscanthe change has unwaived high-severity findings

The budget gate short-circuits closed when no ceiling is configured, so it can never open by accident.

$ forge run --change add-billing --cmd '…' --yes
run: STOPPED after 0 iteration(s) — gate-open
  gate:   verify circuit-breaker
  detail: circuit breaker open after 3 consecutive verify failures
escalate: a human should review before continuing

Zero iterations. Starting an autonomous loop on top of an already-failing change is exactly the situation the breaker exists to prevent.

What it records ​

Every iteration appends an event to the change's session timeline, so a completed run is auditable after the fact: how many iterations ran, what each did, and which gate ended it.

Cost note ​

The secscan gate walks the working tree on the pre-flight check and after each iteration, so an N-iteration run pays N+1 scans. On a large repository, prefer a low --max-iterations.

See also ​