Two loops and a human An engineer described a six-week experiment running coding agents on real projects, settling on a two-loop architecture — a daily/weekly/monthly slow loop and a short-lived fast loop — with a single human approval gate between them. The design keeps prompts as reviewed files in the repo, has jobs propose verdict tables with hashes rather than per-item questions, and gates merges on a standing approval, no new commits, green CI, and a clean security pass. The slow loop has run unattended since mid-September, while the fast loop ran for about ten days in September and is no longer active. Six weeks of running coding agents on real projects, and what the design looks like now Status, stated up front. The slow loop in this piece has run unattended since mid-September: daily digest, weekly sweep, monthly dreaming, each ending in a pull request a human approves. The fast loop has run too, on one project, for about ten days in September, and taught most of what follows. It is not running today. Every project has since moved to a different orchestrator, and the headless shape for it is undecided. I would rather say that than describe a diagram as live when it isn't. One person, several projects, and agents doing most of the typing. The failure mode isn't that the agents are bad at code. It's that they are confident, fast, and have no memory of last week. Left alone, they will re-derive a rule you already learned, write into a directory you meant to keep clean, call a half-finished job "complete", and do it all in well-formed prose. So the design question was never "how do I make the agent smarter". It was: where does judgment live, where does state live, and what is the one thing a human must do? The answer that held up is two loops with one gate between them. The human sits on the gate. Everything else is machinery to make the gate cheap. | Job | When | Proposes | The human does | |---|---|---|---| | Machine checks | daily | a status file: every check pass / fail / unknown; a missing check is unknown, never clean | reads it through the digest | | Daily digest | daily, on a hosted runner | one comment: open PRs each with a one-line mergeable-or-blocked verdict, decisions falling due, open blockers | answers batched decisions in one reply | | Weekly sweep | Sundays | drains the drop, routes notes, regenerates packs, refreshes the export, and proposes a verdict table for every aged follow-up | says go or go except … | | Monthly dreaming | 1st of the month | rewrites the distilled memory file and nothing else | approves one PR | Two design choices matter more than the schedule. Prompts are files. Every job's prompt lives in the repo and runs through the agent's command line, headless. Changing how the sweep behaves is a reviewed PR, with the same gate as code. Jobs propose tables, not questions. The first version of the sweep listed aged items and asked "close or park?" per item. That is a chore, and chores don't get done; the list grew to 22. The current version proposes a verdict per item with the evidence, prints a hash of the table, and the human answers once. The apply step refuses if the table changed after approval. Every "the system asks me the same thing every week" became a table with a hash. The hosting platform won't let an identity approve its own PR. That constraint became the design: A PR is mergeable when four things hold at the same commit: a standing approval from one of those two identities, no commits since it, CI green no checks at all is not green , and a clean security pass. One script prints that as one line, and the digest prints it for every open PR. "Is this ready?" stopped being a question. Two smaller rules carry weight. A scope ratchet : after the first review verdict, later commits may change what is already in the diff but not widen it, unless a human says so explicitly. And a bootstrap exception : a PR that changes the reviewer itself can't earn the reviewer's approval, so it takes a one-time exception only the human grants, recorded where it can't be lost. Out. The export is generated from a committed revision, never a working tree. That rule came from finding the export four days and 174 commits behind the main branch because it had been copied from someone's checkout. Each export carries a manifest the projects can read but not write; a project's copy of the rules is verified against it, so a project can't vouch for its own copy. Every number the verdict uses comes from files only the exporter wrote. Both of those came from review findings on the same PR, and the fix for the second was to delete the "grace period" that trusted the project's copy at all. In. The drop. One file per item, written as .