Keep a coding agent working on a long-running objective in a loop until a stop condition is met.
You hand agent-loop an objective and it drives a coding-agent CLI (such as
claude or codex) to work on it, iteration after iteration, committing
progress along the way — until it reaches a cap or a stop condition you defined.
It's built for the unattended case: kick it off, walk away, and come back to a
trail of small commits instead of one giant one.
A lot of real work is "keep going until X." Get the test suite green. Push
coverage past a threshold. Burn down a list of lint failures. Repeatedly act
like a first-time user and fix whatever trips you up. Doing that by hand means
sitting there typing "continue" into an agent over and over. agent-loop turns
that pattern into one command with explicit, enforced stop conditions so it
can't run away from you.
agent-loop is a single bash script with no dependencies beyond bash, git,
and whichever agent CLI you point it at. It targets macOS's default bash 3.2.
# Grab the script and make it executable
chmod +x agent-loop
# Put it on your PATH (pick a directory that's already on PATH)
mv agent-loop /usr/local/bin/agent-loop
# Verify
agent-loop --helpYou'll also need a coding-agent CLI. agent-loop auto-detects claude (run as
claude -p) or codex (run as codex exec); otherwise pass your own with
--agent. The constructed prompt is delivered to the agent on stdin, so any
command that accepts a prompt on stdin works.
agent-loop --objective "<text>" [stop control...] [options]
| Flag | Meaning |
|---|---|
--objective "<text>" |
Required. What the agent should work toward. |
--agent "<cmd>" |
Agent CLI to invoke. Prompt is piped to it on stdin. Defaults to claude -p, then codex exec. |
--max-iters N |
Stop after N iterations. |
--max-minutes N |
Stop once N minutes of wall-clock time have elapsed. |
--until "<cmd>" |
Stop when <cmd> exits 0. Checked after each iteration. |
--commit |
After each iteration, run git add -A && git commit if there are changes. |
-h, --help |
Show help. |
--version |
Show version. |
At least one of --max-iters, --max-minutes, or --until is required —
without a stop control the loop could run forever, so agent-loop refuses to
start.
Iterate until coverage clears 90%, committing each step, with a hard cap of 40 iterations as a backstop:
agent-loop \
--objective "Raise unit-test coverage of the src/ module toward 90%. Add meaningful tests for real behavior; do not pad numbers with trivial assertions." \
--commit \
--until "pytest --cov=src --cov-fail-under=90 -q" \
--max-iters 40agent-loop \
--objective "Behave like a brand-new user running this project for the first time. Follow the README from scratch, find the first thing that is confusing, broken, or undocumented, fix it (code or docs), then start over as a fresh user and repeat." \
--commit \
--max-minutes 180agent-loop \
--objective "Fix every flake8 violation in the repo without changing behavior." \
--agent "claude -p --dangerously-skip-permissions" \
--until "flake8 . -q" \
--max-minutes 60 \
--commitEach iteration agent-loop:
- Builds a prompt = your objective plus a standing instruction to make one concrete, self-contained increment of progress, run the relevant checks, and commit.
- Runs the agent, piping that prompt to the agent command on stdin.
- Optionally commits (
--commit): if the working tree has changes, it runsgit add -A && git commit. This is a safety net on top of any commits the agent makes itself — if the agent already committed, there's nothing left to commit and the step is a no-op. - Prints a status line: the iteration number as a cycling moon glyph
(🌑🌒🌓🌔🌕🌖🌗🌘), the number of new commits since the run started
(computed from a
git rev-list --countdelta), and elapsed wall-clock time.
Between iterations it checks the stop controls: --max-minutes and
--max-iters are evaluated before starting the next iteration, and --until is
evaluated after each iteration. When any condition is met the loop ends and
agent-loop prints a final summary (iterations, commits, elapsed time, and what
stopped it). Pressing Ctrl-C is handled cleanly — it prints the same summary
before exiting. Because the checks happen between iterations, a single
long-running iteration can overshoot a time cap; the cap is enforced at the next
boundary.
Functional v0. The loop, prompt construction, agent invocation, auto-commit,
moon-phase status line, all three stop controls, and clean Ctrl-C handling all
work today as described above.
What's honestly not here yet:
- Token / cost budgets. There's no
--max-tokensor--max-costcontrol. Enforcing one properly requires the agent CLI to report token usage in a parseable way, and that varies by tool — so it's a roadmap item rather than a promise. Today the practical stop controls are--max-iters,--max-minutes, and--until, which is what this README documents.
Compared to ad-hoc "just keep telling the agent to keep going" loops, the difference is discipline: stop conditions are explicit and mandatory (you can't accidentally start an unbounded run), progress is checkpointed into small reviewable commits, and you get a consistent per-iteration status line plus a final summary instead of an undifferentiated wall of agent output.
MIT — see LICENSE.