There’s a category of task every engineer keeps putting off. Not hard, exactly — tedious. Chase down the twenty flaky tests dragging out CI, migrate the last of the call sites off a deprecated helper, work through a backlog of lint warnings nobody’s touched since the rule got tightened. Nothing about it needs real judgment. It just needs someone to sit with it long enough to grind through the list, and that’s precisely the kind of work nobody wants to spend an evening on.
That’s the shape of task I want to talk about — not as a one-off prompt, but run as an actual unattended loop, using the two tools I reach for most: Codex CLI’s /goal and Claude Code’s /loop. Here’s how the mechanism works in both, and what it takes to point one at real work without coming back to a mess.
A loop is not a longer prompt
A normal prompt to a coding agent is one round trip. You ask, it answers, and you’re the one who checks whether it’s right. If the fix is wrong, you’re the one who has to notice and ask again.
A loop runs a standing cycle instead: plan, act, verify, iterate. It keeps going until a real stopping condition fires, not until the conversation happens to end. That’s the whole shift, and it sounds small until you’ve watched it hold state across an interruption — you close the terminal, come back an hour later, and the work picks up exactly where it left off instead of starting over from a blank context window.
Two tools, the same idea underneath
Codex CLI ships this as /goal. Internally it tracks the goal as a persistent object with real states — active, paused, complete, or budget-limited — and every cycle runs through plan, act, test, review, and iterate. You can interrupt a run and the goal survives; resume it later and it continues from where it stopped. Continuation only happens at safe boundaries — end of a turn, nothing queued, the thread idle — so it isn’t a runaway while(true), it’s a supervised cycle that just doesn’t need you present for every step.
Claude Code’s /loop does the equivalent job from a different angle. Give it a fixed interval and it fires on a schedule; give it no interval and it self-paces, deciding whether the next iteration is worth running and scheduling its own wakeup. I’ve used the self-pacing version to keep working a task across a merge, a build, and a deploy that hit an auth wall partway through — it did what it could, told me exactly what was blocking it, and picked back up the moment I’d cleared the blocker, instead of silently retrying a step that had no chance of succeeding until I acted.
Both tools are doing the same underlying thing: replacing a single round trip with a supervised cycle that has real stopping conditions and survives you looking away.
The work is in the contract, not the command
Ask either tool to “clean up the flaky tests” and you get one of two outcomes: it runs until the budget is gone, or it makes a pile of unrelated changes that technically count as cleanup. Neither is what you wanted, and neither is the loop’s fault — it’s the instruction’s.
A goal that’s going to run unattended for hours needs five things pinned down before you start it. A verification command that proves a fix works — not “it looks right,” but a specific test passing, or a specific check returning clean. A write scope naming exactly which files it’s allowed to touch, with everything else read-only. A stop condition stating plainly what “done” means. A pause condition for what makes it stop and wait for you — too many failed attempts in a row, something outside scope, a decision that isn’t the agent’s to make. And a task with real edges, not “clean up the codebase.”
If you can’t fill in all five before you walk away, you’re not ready to walk away. That’s not caution for its own sake — it’s the difference between a loop that finishes with something useful and one that spends your evening’s compute on nothing.
Ground rules before you stop watching
A few habits are worth keeping regardless of which tool or which task. Work on a branch, never on main — if the run goes sideways, you delete the branch and lose nothing. Run it inside a sandbox so file and network access stay contained to the project. Pipe the session to a log file so there’s a full record waiting for you:
codex --approval-mode full-auto 2>&1 | tee codex-session.log
Set an approval policy suited to unattended work, but don’t strip every guardrail just because you’re waving through routine prompts — keep the checks alive for anything that escalates beyond the task’s scope. And if your schedule allows it, check in partway through. The point of the feature is that you don’t have to, not that you’re locked out.
A concrete version of all this, for the flaky-test example: a verification command of “this specific test passes ten times in a row without flaking,” a write scope limited to the test files themselves and not the code under test, a stop condition of “every test in this list passes reliably or is flagged with a documented reason it can’t be fixed,” and a pause condition of “more than three tests need a change to non-test code to fix.” That’s a goal you can actually leave running.
Loops are for grind, not for judgment
The place this breaks is when the task isn’t actually verifiable — “make the API nicer,” “improve the error handling,” anything where “done” is a matter of taste rather than a check that passes or fails. A loop needs a real stopping condition, and if you can’t write one, the task wasn’t ready for a loop. That’s a sign to do it yourself, or to break it into a piece that is bounded enough to hand off.
The same logic applies to the last step of almost any unattended run, whatever the domain: merging to main, deploying, sending something, deleting data. A loop can produce a change that passes every test it wrote for itself and still be wrong in a way the loop had no way to see — because the check it wrote only proves what it thought to check. Keeping that last step gated behind a person isn’t overcaution. It’s the same split good teams already use even when they trust the grind-work completely: let the loop do the exhausting, verifiable part, and keep the part that needs judgment for someone who’s actually looking at it.
What you actually get back
Not a finished, deployed change — something more useful to start with. A log of everything the agent tried, a branch with the fixes attached to passing checks, and a written account of what it fixed and what it punted on because it hit the edge of its scope. You spend your attention on the part that needed it, instead of spending last night on the part that didn’t.