| name | loop |
| description | Gate-driven retry loop — re-run an agent until a shell gate command passes (e.g. PR checks green, tests passing). Use with /loop when a machine-checked condition decides done-ness, not the model's say-so. |
Loop
Use /loop when a machine-checked gate decides done-ness: a test command, a
build, gh pr checks, a deploy health probe. The agent keeps working until the
gate exits 0, the iteration cap is hit, or the circuit breaker trips. The gate —
never the model's claim — decides when to stop.
When to use
- "PR checks are failing — keep fixing until green":
/loop --gate "gh pr checks 123 --watch" "investigate and fix the failing checks"
(use --watch for PR gates: plain gh pr checks exits non-zero for pending
checks too — exit 8 — and pending is not a failure to fix)
- "Iterate until the tests pass":
/loop --gate "npm test" "make the suite green"
- "Keep going until the task is done" with no shell gate:
/loop "migrate all tests to vitest" (plain mode)
Do not use when
- No plan exists yet — use
/ralplan first
- You just want a recurring read-only check (no fixing) — use
/schedule
- Work has independent parallel lanes — use
/team
Input
/loop "<task>" — plain mode: same-session persistence loop, no gate.
/loop --gate "<shell cmd>" "<task>" — gate mode: the shell command is run
after every fix attempt; exit 0 = done, non-zero = keep fixing. --max N
overrides the iteration cap (default 10).
Steps
Mode 1 — plain agent loop
- Register the loop FIRST — run
omp ralph start "<task>" --max-iterations N.
This is the same machinery as /ralph: the agent-stop hook re-prompts until
you emit the completion sentinel or hit the cap. Skipping registration leaves
the loop invisible to omp ralph status/cancel. (Gate mode below does NOT
register ralph state — the gate command itself is the tracker.)
- Work the task slice by slice, verifying each slice (see
/ralph).
- When acceptance criteria are genuinely met — with fresh evidence — end the
loop (
omp ralph cancel).
Mode 2 — gate-script loop
- Validate the gate first — run the gate command once yourself before
looping. If it errors for environmental reasons (missing tool, auth, wrong
cwd), fix that NOW, not inside the loop. Note the current output: that is the
failure signature you are fixing. Make sure the gate distinguishes pending
from failed — e.g.
gh pr checks without --watch exits 8 while checks
are still running; a gate that treats "in progress" as "broken" will spawn
speculative fixes against a moving target.
- Pick the driver by gate cost:
- Fast gate (seconds:
npm test, tsc, pytest) → loop in-session:
run gate → exit 0: report PASS with evidence, stop. Non-zero: read the
failure output, make ONE focused fix, re-run the gate. Repeat up to the cap.
- Slow gate (minutes: CI,
gh pr checks --watch, deploy probes) → don't
burn the session polling. Choose one:
- 2a. Managed schedule (default) — register a bounded job:
omp schedule add --id loop-<slug> --cron "*/15 * * * *" \
--max-runs <cap> --ttl-hours 72 --timeout 900000 \
--prompt "Run: <gate>. If it looks stale (previous SHA right after a push), use gh run list and wait for the new run before judging. If it exits 0: report PASS in the run summary and stop — do NOT remove the schedule from inside the run. If it fails: <task> — make one focused fix, commit AND PUSH it to the PR branch, then stop." \
--allow-all-tools --cwd <repo>
--max-runs IS the iteration cap (scheduled ticks are stateless — the
3× circuit breaker below only works in-session, so keep <cap> small,
e.g. 4–8). Pass --ttl-hours explicitly: with --max-runs alone the
job gets NO expiry backstop. Set --timeout to cover a full
watch-fix-push cycle — ticks killed at the 5-min default still
increment runCount, silently eating the cap. Confirm with the user
before --allow-all-tools (unattended full access). Inspect ticks
with omp schedule status loop-<slug>. When a PASS summary surfaces
(run results appear at the next session start), remove the job from
an interactive session: omp schedule remove loop-<slug>. Do not have
the tick self-remove — the runner rewrites the job record after the
child deletes it, leaving a stale active entry.
Circuit breaker
If the same failure signature (same failing check / same test / same error)
appears 3 times after 3 different fix attempts, stop. Report:
- What was tried
- Why each attempt failed
- What information is missing
Do not keep trying the same approach. Escalate the blocker.
This breaker only works where one mind sees every iteration — the in-session
drivers. Scheduled ticks (2a/2b) are stateless fresh sessions: there
--max-runs (2a) or the wrapper's counter file (2b) is the only cap, so set
it deliberately.
Scope freeze
Fix only what the gate complains about. If you discover unrelated broken work:
note it under "Known gaps", do not chase it — unless it blocks the gate, in
which case stop and report.
Rules
- The gate decides done-ness — never declare PASS without a fresh gate exit 0
- Never modify the gate itself — not the gate script, the tests it runs, the
CI workflow, or the assertions — to make it pass. That falsifies the signal.
If you believe the gate is genuinely broken (not just failing), STOP and
report the broken gate with evidence instead of weakening it.
- Prompt rules alone do not stop gate-gaming — a determined agent with write
access can still rewrite the referee (observed in testing, twice). Prefer
gates outside the agent's write reach (external CI on a protected branch, a
read-only-mounted check). Whatever the gate, a PASS from a loop that ran with
write access is not proof until a human or a fresh reviewer session inspects
the final diff — include that review in your definition of done.
- No substitute gates — if the gate command itself cannot run (auth, missing
tool, network), report BLOCKED with the error. A different check that happens
to pass is not gate evidence (observed in testing: an unattended tick
declared PASS from local checks when
gh auth was unavailable).
- One focused fix per iteration; don't batch speculative changes
- Fixes against a remote gate (PR checks, deploy) must be committed AND pushed —
a local commit never moves the remote gate
- Right after a push,
gh pr checks --watch can briefly show the PREVIOUS run;
if the result looks stale, check gh run list and wait for the new run
- Read the gate output — don't assume green means pass
- Every schedule/wrapper you create gets removed when the loop ends
Final checklist
Before claiming done:
Output
Done — gate status and what was fixed per iteration
Evidence — final passing gate output (and failing outputs along the way)
Known gaps — anything intentionally left or discovered but out of scope
Cost/token note
Gate loops can drive many tool calls and long outputs. Use omp cost [--today]
for local hook-ledger estimates only; it is not provider billing. Prefer 2b's
gate-first wrapper for long CI watches so green ticks cost no tokens.