I pointed Claude Code at a backlog of 121 validated GitHub issues on a platform I'm building and let it run. About thirty hours later it had shipped 56 of them to production — nineteen batches, twenty-two pull requests, every change test-driven, code-reviewed by a second agent, merged through CI, deployed, and verified against the live system before the next batch began. I was nearby for most of it. I was needed for almost none of it.
This is a case study on the loop, not the product. The product is incidental; the method is the project.
Why It Exists
A coding agent with a single task is a solved problem. A coding agent with a backlog is not, because everything that makes long-running agents fail is structural, not intellectual: context windows fill up and get compacted, sessions crash, the model forgets what it shipped an hour ago, and — left to its own devices — it either stops politely after one task or barrels ahead without ever checking that anything actually works.
The loop is an answer to four specific failure modes. Each one got a mechanism, not a prompt.
The Amnesia Problem: State Lives on Disk
The cardinal rule: no loop state in the model's memory, ever. The conversation is a cache that gets wiped without warning; anything that matters has to survive the wipe.
So the queue is just GitHub — every issue I'd triaged and approved carries a validated label, and the canonical queue is one gh issue list query away. Progress lives in a checkpoint file, a small JSON committed to disk and rewritten at every phase transition: which batch is in flight, which branch, which PR, which phase (implementing, verifying, deploying, live-verifying), which issues are done, plus one line of notes for whoever wakes up next. Session hooks re-inject the checkpoint and queue counts every time a session starts or the context gets compacted.
The effect is that the agent can be killed at any moment — laptop restart, context wipe, API outage — and the next session reads the checkpoint, reconciles it against reality (git log, open PRs, deploy status, because the world may have moved), and resumes mid-phase. Over the thirty hours the context was compacted many times. The loop never noticed.
The Stopping Problem: A Hook That Refuses
Agents are trained to wrap up. Ask one to "work through the backlog" and it will do a batch, write a lovely summary, and stop — because ending the turn is what it knows how to do.
The fix wasn't a sterner prompt. It was a Stop hook: a script that runs whenever the session tries to end, counts the queue, and blocks the stop while validated issues remain. Stopping becomes a privilege the environment grants, not a decision the model makes. A pause flag gives me the override — touch a file and the loop winds down at the next clean boundary, which is exactly how the run ended: "stop at the end of this batch, I need to restart my computer."
The Quality Problem: Trust Nothing, Verify Everything
Speed without verification is just a faster way to ship bugs, so every batch ran the same gauntlet:
- Batches of 2–5 issues sharing one subsystem, implemented by parallel subagents in isolated git worktrees so they can't trample each other.
- TDD, enforced: each implementer writes a failing test before any code, and each change then goes to a separate adversarial reviewer agent whose mandate includes reverting the implementation to prove the tests actually fail without it. Tests that pass against nothing are theater.
- A gated integration suite against throwaway Postgres and Redis containers, plus typechecks from a cold cache — incremental build state is a known liar.
- One PR per batch, CI green, squash-merge, deploy only the touched services.
- Live verification before any issue counts as done: health endpoints, migration logs, and a real behavior probe through the deployed system. An issue is not closed because the code merged; it's closed because production demonstrably does the new thing.
The adversarial reviewers earned their tokens. Among other catches, one found that a freshly refactored route registry would have returned 404 for every request after a planned database cutover, and another found a race in a rollback path — both fixed before merge, both invisible to the passing test suites.
The heaviest thing the loop did was a staged production database-role cutover so that row-level tenant isolation would be enforced by the database rather than merely defined in it — prepared across four batches, executed live with secrets handled out-of-band and a rollback one variable-flip away, then soak-verified. That's not a change I expected to delegate. It went fine.
The Judgment Problem: Two Strikes and Move On
An autonomous loop's worst failure mode is silent thrashing — burning a night retrying the same doomed issue. The policy is mechanical: an issue gets at most two implementation attempts. After the second failure it's ejected from the batch, labeled burndown-blocked, and annotated with both attempts' failures and hypotheses for a human to read. A blocked issue never stalls its batch siblings, and the loop never retries one without new human input. Over this run, nothing hit strike two — but the policy existing is why I could sleep.
What the Loop Couldn't Do
Honesty section. The one production incident during the run was caught by me, not the loop: a frontend deploy shipped a blank page because a server-only module rode a barrel import into the browser bundle and crashed at startup. Every signal the loop checked — HTTP 200s, fresh asset hashes — said the deploy was fine, because none of them proved the app rendered. The fix took minutes; the lesson became a mechanism, like everything else: a real-browser mount check is now a mandatory gate before and after every frontend deploy.
Some walls are intentional. Publishing to npm requires a 2FA code only I have, so that work queues up politely for a human. And the backlog itself was human-curated — every issue in the queue was one I'd validated first. The loop decides how; it does not get to decide what.
What to Copy
If you take one thing: long-running agents don't need better memories, they need externalized state and environmental enforcement. Put the queue in your issue tracker, the progress in a file, the discipline in hooks that block bad behavior, and the definition of done in production probes. The model is the least durable component in the system — design like it, and the loop gets to be ambitious precisely because no single session has to be.