Self-improving loops
Produce and review isn't enough. What separates a loop that converges from one that doesn't is what you do with what you learned.
I’ve been using agents to write code for me for a while now: programs that take a task and write the code on their own. And there’s something that bothers me every time I review a PR, the bundle of changes the agent proposes and that someone has to approve before it goes into the project. I correct the same things again. I take out the any, a TypeScript wildcard type that switches off the language’s checks. I rename variables and ask for tests on the edge case that was missed, the odd case nobody thought of. I send it back to be fixed (we call that a kickback) and the next one comes with the same corrections. The agent produces, I review, and the next task starts as if none of that happened.
The problem doesn’t seem to be the agent: what isn’t closing is the workflow, the chain of steps that goes from the task to approved code.
The loop we leave half-finished
The typical flow I see goes like this. You give a prompt, the written instruction with the task. The agent produces. You review. If something’s wrong, you send it back. If it’s good, you ship. It looks like a closed loop.
But I think it closes too early. What’s missing is what happens after review: feeding what you learned back into the system.
I think of it as four steps: observe, produce, review, improve. That fourth one is almost never built out. Without it, the system repeats the same mistakes with the same confidence and doesn’t converge: it never reaches the point where it stops making them. Or at least I haven’t seen it get there on its own yet.
The question I ask myself after every review is what the system learned once a person corrected the result. If the answer is “nothing,” the workflow is still incomplete.
What I built in Bille (and what’s still missing)
In Bille, the project I’ve been working on, I tried to close that gap. I’m not saying it’s solved. I’m still figuring out what works.
The base flow I wrote about elsewhere. Tasks live in Linear, the tool where I keep the tickets, with the “Ready For Claw” label. A coder agent, the agent that writes the code, picks up the task, codes, runs lint and typecheck (two automatic checks, one for style and one for types) and the tests, and opens a PR if everything passes. A reviewer, another agent, reads the diff, the list of lines that changed, looks for bugs and architecture issues, and kickbacks to the coder if it finds something. Three kickbacks without resolution and it notifies me. That part was already there.
What I added later is different. Every attempt gets written to an Obsidian note, the app where I keep my notes: what was done, what failed, what the reviewer decided, how many kickbacks so far. The agent starts every task with no memory. The note is what gives it back.
And there’s one more step that matters most to me. After I review a PR, a Learning Flow runs, an automatic process that takes my review comments, analyzes them, and updates CODING_PREFERENCES.md, the file with my coding preferences. It’s not a raw list of comments but an attempt to turn “I removed the any again” into something the next coder reads before writing a line.
Does the number of kickbacks go down? Sometimes. Sometimes not. When it doesn’t, the limit of three forces me to step in. I think that’s fine. I’d rather that than a loop spinning in circles without telling me.
Taste documents
The Obsidian notes are task memory. Taste documents are something else. That’s what I call style guides, the documents that say how things get written or coded in a given place, when they evolve with real work.
In code, CODING_PREFERENCES.md isn’t a copy-paste of generic TypeScript rules. It feeds off my reviews. If I always remove any, that should be written down for the next agent. If I always ask for edge case tests, same thing.
For writing I do the same with this blog. I have a style guide I update after every merge, every time a post goes onto the site. I compare what the agent wrote with what I actually published. If I always rewrite paragraphs that start with “Furthermore,” that goes into the guide. Next time, hopefully, the agent already knows.
A static style guide gets you started. A living one, I think, is what stops the loop from feeling like pure automation.
The analogy I use with friends: it’s like an intern who gradually learns how you take your coffee, instead of one who brings you a cortado every month when you want a lagrima. Feedback has to go somewhere that persists. Otherwise you’re spending the same effort on every review.
It’s not automatic
What interests me here isn’t just the mechanism, but that the improvement step doesn’t come from any tool. I haven’t seen a feature in Cursor, the AI code editor, that updates your preferences after every kickback. There’s no Linear checkbox that says “learn from this comment.” You have to build it on top of the tools you already use.
And it’s easy to skip because the other three parts already work. Produce, review and ship is a wheel that turns on its own. The problem is it can turn without going anywhere. Each rotation looks the same as the last if nobody writes the lesson somewhere the next agent will read.
And it’s not just code: any workflow where a person corrects what an AI produced has the same gap. Marketing copy, design, product specs. If the correction doesn’t flow back into the system, the system doesn’t learn.
What I still need to figure out
I’m still figuring out what works and what doesn’t. The Bille system is young. The taste documents change with each iteration. Sometimes the Learning Flow suggests something I don’t want in the guide and I edit it by hand. Sometimes I update the guide myself because it was faster.
I still haven’t worked out when it makes sense to automate the improvement step and when to do it manually. For now I use this rule: if I corrected it twice in separate reviews, I write it down somewhere. If it only happened once, maybe not.
If you’re using agents and feel like you correct the same things over and over, look at where those corrections end up. If every review is an isolated event, the loop isn’t closing.
I’m going to keep iterating the flow in Bille: writing lessons into CODING_PREFERENCES.md, Obsidian notes, blog guides, and seeing if over time I stop removing the same any on PR number twelve. I don’t know if it’s enough, but it’s the one step I can’t skip if I want this to scale without becoming the permanent bottleneck.