The loop that built itself
This is the story of how issue-lifecycle grew from a set of rails into swamp-go-brr — the prequel to the cage, the brain, and the ledger.
I set out to stop babysitting an agent. The autonomous developer arrived later, as a consequence rather than a plan.
The tools could write code. They could not be trusted to decide what to write, or to notice when they’d quietly wandered off the plan, or to remember that this exact mistake already cost me a Saturday last month. I wrote about the mismatch before — a Genesis Engine run with a two-week committee ritual bolted to it. This is the other half: what I actually built to run the engine.
Borrowed rails
The skeleton was borrowed. It came from Paul Stack’s Booking talk, passed through swamp-club’s version, and then I took it and made it my own. The shape is a state machine over an issue: file → triage → plan → review → approve → implement → review → resolve → complete. The whole point is the gates. The machine will not let the agent skip ahead to writing code before there is a plan a human approved. Approval is sacred; the agent never grants it to itself.
The first version, early April, was crude. It had one gate condition: no open CRITICAL findings. It worked the way a straitjacket works — the agent stayed on the rails, but the rails were all it had. It was a supervisor rather than a colleague, and its output came back correct-and-generic. Every issue started from zero, as if the last forty had never happened.
Teaching it to remember
The change that turned it from a straitjacket into something I’d actually want came in ora, the workspace where I build resinsim and DragonFruit. The change arrived as two methods that form a bookend.
The entry is record_prior_art. Before planning, the agent reads the repo’s own knowledge base — the ADRs, the patterns, the anti-patterns, the UAT scenarios that touch this code — and records what it found.
The exit is harvest. After the code is green and reviewed, the agent diffs everything that happened — the review findings it resolved by adding logic, the reproduction, the questions it had to ask me — against what it knew going in. The delta is new knowledge. It gets written back into the knowledge base as a dated file.
That diff is the whole game. I’ve written the mechanics up on their own, so I’ll keep it short here: the repo stops being only code. It starts carrying the methodology, the decisions, the things that were tried and thrown away, and the tests that pin the behaviour. The next issue reads it back as prior art. I stopped rediscovering the same lesson every third issue.
It grew by eating itself
Here’s the recursive part. issue-lifecycle is developed through issue-lifecycle. Every change to the tool is an issue driven through the tool, and every one leaves a harvested lesson that shapes the next change.
The tool’s own knowledge base is the proof. There’s an anti-pattern in there about changing the model without syncing the skill docs — harvested the first time I did exactly that. There’s a decision record arguing for a small dedicated recorder method instead of loosening an existing gate — because loosening the gate would have silently wiped data a later phase reads. There’s a doc-drift guard that fails the test suite until every method is documented, which I wrote after the docs drifted from the model once too often.
None of those are things I’d have designed up front. They’re scar tissue, harvested. The changelog reads like compound interest.
The changes, in order
The shape of the tool now is a stack of those lessons:
- A TDD sub-loop came first. The agent does not get to write production code until it has written the failing tests and had them reviewed. The agent writes RED en masse, then drives GREEN and REFACTOR against a frozen suite. It’s the one place I let the machine approve itself — a clean test-review exit — because “the tests are good” is checkable in a way “the plan is right” is not.
- A real gate replaced the crude one. The old “no CRITICAL” softened too much; the current gate needs full review coverage AND zero CRITICAL AND zero HIGH. The gate has three conditions, and all of them are mechanical.
- Plan discipline followed. A skimmable plan format lets me read the thing in forty lines. It also carries the rules the agent kept needing: integrate with the existing code instead of building a parallel path; do not add backward-compat shims for code that has no users yet; refactor in place instead of deferring to “later”. All of those are from watching it do the wrong, plausible thing.
- Human-factors doctrine rounds it out — the stuff you only learn by running it eighty times on real work. Never chain through a human gate in one shell block — pause before the gate rather than after it. Run the review fan-out inline rather than as subagents, because a permission prompt with nothing to read is a bad gate. The code review happens before the PR rather than as the PR. Each issue gets its own jj workspace, and the workspace is forgotten once the work merges.
It pays rent on real work
This was never a demo. resinsim is my own resin-print simulator, built from the ground up this way. DragonFruit is a resin slicer I work on. Eighty-odd issues went through the loop between April and July.
The one I keep pointing at is an issue on resinsim to ingest real force data off an Athena printer. The harvest wrote a knowledge-base entry recording that my own peel model is wrong at the base — simulated peak force at layer 15, measured peak at layer 0, shape correlation 0.82 but a single gain fit gives an R² of basically zero. It is a genuine “my physics is off here” finding, distilled by the tool from its own run. Hours later I pulled that entry back out to argue the model with the people who own the hardware. The loop earned its keep the same day.
On DragonFruit, a July issue read four ADRs a different run had harvested back in April, and drove idle CPU from 25% down to under 9%. April’s run left notes; July’s run read them and left better ones.
The machine ports itself
In June it got recursive in the literal sense. I drove the port of issue-lifecycle to strict-typed Python — issue-lifecycle-py — through issue-lifecycle itself. When it finished, I harvested the port’s own decisions, and then filed the next port with one line: “with all that knowledge, port good-planning too.” The knowledge that came out of the first lifecycle went in as the recorded prior art of the second. The snake ate its tail, and the tail was nutritious.
Taking the human out
By June the tool did almost everything. The autonomous loop already iterated on review findings on its own — round after round, until zero blocking. What I still held were two gates: approving the plan, and accepting the resolutions.
So the question that had been circling landed. If the principles are captured in the knowledge base, and the behaviour is pinned by tests, and the review loop already runs itself — what is my gate actually protecting? Is it correctness? The tests do that. Is it convention? The knowledge base does that.
That question is swamp-go-brr. On the 3rd of June I filed it — using issue-lifecycle, of course — to design an autonomous version of the same discipline, with the human out of execution. It takes a person’s input, researches it, plans the tasks on a merkle DAG, spawns subagents to implement them, websearches for existing test code to port as the harness, and runs to completion. That is everything the lifecycle already did, minus me.
What the plan told me
The plan for gobrr surfaced, immediately, the real reason my gate existed. The reason was blast radius rather than correctness. An agent with capabilities, untrusted input, and the freedom to act is the lethal trifecta, and I had been the thing standing between it and the rest of the machine.
So I paused the brain and built the cage first: Firecracker microVMs, one per task, where the VM is the sandbox, so a leaf can run wide open because it cannot reach anything that matters. Then I built the brain: a driver-free DAG state machine that is, underneath, issue-lifecycle with the human replaced by a good-enough set of principles and tests. It harvests its own knowledge base — the same discipline, carried forward. While I built it, it was tracked as an issue-lifecycle instance. The tool was managing the birth of its own successor.
The honest part
Does it work without me? It does — sort of.
I ran the pilots you’d run — desired-state framing versus imperative, harder fixtures, a HumanEval pass, a weaker model on the leaves. They mostly tied. The record says so plainly: no clear win, hypothesis not supported. I was fine with that, because the tie said more about the fixtures than about the loop: the tasks were too easy to show a difference, and I knew I did not have the capacity to run a real coding benchmark. gobrr runs, it produces code, it verifies against a harness — and watching it work without me is honestly fun.
The conviction underneath is simpler than the autonomy question. The loop matters because it generates knowledge and decisions that can be reused and accumulated. Every issue leaves the repo knowing more than it did, and the next issue starts from there — whoever sits at the gate. gobrr is the wager that the gate can eventually be staffed by what the gate itself harvested. I have not won it yet, and I am not in a hurry. The line from “keep the agent honest” to “maybe the agent doesn’t need me” turned out to be one continuous curve, and every point on it was harvested from the point before.
The loop built itself. Whether it can build without me is the next issue, and I get to watch. I’ll drive it through the loop.
