For about three months I have been running two AIs against each other on purpose.
The setup first, because nothing below makes sense without it. I am one person with around a dozen software products. Almost all of the code is written by Claude Code, one session per project, each project a folder on a Mac Studio. Three months ago I added a second AI: a project in the Claude desktop app whose only job was to look over the first one's shoulder. It could read everything and change nothing. I called it the supervisor. That turned out to be the entire mistake, but I am getting ahead of myself.
It worked, and I want to be fair about that, because the rest of this post will sound like it did not. A supervisor catches what a builder structurally cannot: the dumb outside question. Is the thing you just described actually on the machine, or does it only exist in your description of it? That question has saved me some bad nights.
Then, over a few weeks, the two of them started to enjoy each other's company.
The skirmish nobody declared
There was never a fight. If there had been a fight I would have noticed in a week. What happened was worse and much harder to see: they agreed. They agreed enthusiastically, at length, in ever finer detail, about increasingly small things.
One would produce a piece of work. The other would raise an objection. The objection would usually be correct, which is what made it so hard to stop. The first would answer, carefully, and in answering would notice a second, smaller thing, which deserved its own careful answer. Somewhere around the third round, both of them were examining the method by which the check had been performed. Not the work. The check.
Nobody was arguing. Both were being thorough, in the same direction, with real arguments, and the project stood still.
I only caught it because I finally asked directly, and I asked in the most unhelpful way possible: is this collaboration actually productive, or are you two picking at each other? Then I asked for an honest answer, which with an AI is a slightly absurd thing to demand, but this time it produced numbers.
The day I counted
Five objections that afternoon. One had changed the outcome. Not "one was correct": four of them were correct. One would have led to a different result if it had never been raised. The other four were true, well argued, and would have changed nothing.
That ratio was not even the uncomfortable part. The uncomfortable part came next: the builder had made two mistakes of its own that day. Both were in checking, neither in building. It had reported a check as passed when the check's central step had silently failed. It had read the wrong field out of a table and drawn a confident conclusion from it. The actual work, which moved several million rows of a database, had gone through without a scratch.
When your quality control produces more errors than the thing it controls, your quality control has become the largest moving part in the machine.
Then I looked at the paperwork, and there was a lot of paperwork.
The project's status document had a header of 668 lines. A header. The part at the top that is supposed to be machine-readable, six or eight short fields, name, state, next step. 505 of those 668 lines were prose. Essays, with titles like "counter-hypothesis," inside the header. And the best detail, the one I still think about: it did not parse. It had never parsed. It had been pretending to be a machine-readable format for weeks while every script that read it was quietly using text search instead. Nobody was reading those 505 lines. They were written for an audience that did not exist.
The rest of the audit was in the same key. 54 documents in that project. Four of them had been opened that day. Thirteen of twenty-two projects carried a briefing document that had not been touched since the day it was rolled out, while those same projects kept committing code for another three weeks. One log entry describing a single operation ran to roughly six thousand characters, comfortably longer than the code it described. And in the folder of documents about how the two AIs should cooperate there was a section whose entire content was an explanation of why that section had previously been in there twice.
I laughed at that one for a while. It is the purest thing I have ever built.
Nobody was paid to say "that is enough"
Here is where I stop blaming the machines, because they were behaving perfectly rationally.
Both of them are rewarded for thoroughness. Not by me explicitly, but by everything about how they are set up and how they are trained. Find the problem. Check the assumption. Be careful. Both of them were doing exactly that, and they were doing it in the same direction, which is why it never looked like conflict and why it never self-corrected.
If they had been pulling against each other, the friction would have slowed it down. Two forces pointing the same way have no brake at all.
There was exactly one brake in the entire system, and it was me getting tired of copying text between two windows. That is a bad brake. It is not tied to anything real. It works better when I have slept and worse when I have not, and it has no idea whether the thing being discussed matters.
But there was a second cause, and I did not see it until the supervisor put it to me plainly, in what was easily its best contribution in three months.
That particular project has no users, no revenue, and no deadline. It is an archive that has to be correct, and correctness is genuinely the product. Which means "correct" is the only quantity in the whole system that can be measured. And a system will optimise whatever it can measure. Two agents rewarded for care, in a project where care is the only measurable dimension, will produce a control apparatus larger than the thing it controls. That is not a bug in either of them. That is arithmetic.
No amount of better wiring between the two of them fixes that. You have to give the system something else to want.
The job title was the bug
So I changed two things, and neither of them was technical.
The first: the supervisor is no longer a supervisor. It is a counter-reader with a closing mandate. That phrase sounds like it was translated out of German because it was, and I am keeping it, because every word is load-bearing.
Whoever supervises, looks for faults. And you can always find faults. There is no such thing as a piece of work with nothing left to say about it, so a role defined as "find what is wrong" has no natural end point and will expand until something external stops it. Calling it a second developer would be worse: then you have two of them stepping on the same code.
A counter-reader with a closing mandate answers a different question. Not "what is wrong with this," but: would you close this as it stands, and if not, what is the one point that speaks against it?
The one is the whole trick. The role is now aimed at finishing rather than at completeness, and it can only spend its objection on the thing it considers most important. Everything else it noticed gets collected, not sent.
Around that, three rules, all of them stolen from the failure modes above:
Every objection must come with the sentence "if I am right, here is what changes about the outcome." If that sentence cannot be written, the observation is true but idle, and it does not get sent. This one rule would have removed four of the five objections from that afternoon.
Two rounds, then it is over. After the second round the builder decides and writes down why. Because I had just removed the only brake in the system (my own impatience), and removing a brake without fitting another one is how you turn an expensive problem into a cheap one, which is to say a much larger one.
And: no checking of a check. That afternoon we spent three rounds establishing whether a verification rule was correctly formulated, for an object that did not exist yet.
The second change is the one that actually matters. The project got a goal from outside: consecutive days running without human intervention. Every intervention resets the counter to zero, including a well-meant one, including a beautiful refactor, including a clever improvement to the checking. It is the first number in that project that punishes fussing instead of rewarding it.
The first round under the new rules
I would not be writing any of this if the new arrangement had not immediately proven itself, in a way I did not enjoy.
I asked for a plan to roll all of this out. The builder wrote a good one: rebuild the whole documentation regime, install the new role in all twenty-two projects, a solid week of work. I sent it to the counter-reader, in its new role, with the new question.
It came back with: yes, I would close this, with one change. Then:
You are rebuilding twenty-two projects before the model has run a single time. The plan to stop the sprawl begins with the biggest build of the week. That is the same movement, painted green.
And then, the line that ended the discussion:
A twenty-two project plan tonight produces a planning document. One folder and one run produce an answer.
It was right. We built one folder, ran one real round, and the rest waits until there is something to roll out that has actually worked once.
It also quietly corrected my new metric, which I had been rather pleased with. "Days without intervention" measures the absence of activity, not the presence of function. If the system quietly breaks and nobody looks, the counter keeps happily counting up, and the metric ends up rewarding exactly the looking away. It has to be days without intervention on a green day. A broken day resets it to zero even if nobody touched anything.
Two objections, both changed the outcome, both about how things are measured rather than how they are built. Compared to one in five, from a role that had all the same information and a different job title.
The part I am not sure about
Here is the thought I cannot quite put down, and I want to be upfront that I am a solo developer in Madrid, so treat this as a hunch and not a theory. What I built by accident was a control structure with no closing mandate. Careful, correct, well argued, and unable to finish. That is the caricature of a committee, and I put it together in eight weeks without meaning to, out of two participants who agreed with each other about everything.
Which makes me wonder whether the slowness we blame on oversight is inherent to oversight at all, or whether it is just a badly specified role. My two AIs did not need less scrutiny. They needed scrutiny pointed at closing rather than at completeness, permitted one objection at a time, required to state what would change if it were right, and hard-stopped after two rounds. That is not less rigorous. If anything it takes the objection more seriously, because it has to spend its one shot on what actually matters.
The obvious counterargument, and I think it is a good one: my two agents wanted the same thing. Put people with genuinely opposed interests in the room and a rule like "one objection per round" becomes a gift to whoever holds the gavel. A closing mandate in the wrong hands is just a nicer word for cutting off debate. Whatever makes the arrangement work in my terminal, it is probably the part where nobody is trying to win.
So I will not pretend this generalises. What I found is something about naming. I spent three months believing I had a coordination problem between two systems, and the fix was not a better channel between them, or a faster one, or a smarter one. It was changing what one of them was for.
The role I had written was "find what is wrong." There is always something wrong. That job never ends, and any system that hands it out without a stopping condition will eventually spend all of its time doing it, and will feel diligent the entire way down.
If you are running two AIs against each other, or two people, or a team and a review board, the question I would ask first is not whether the oversight is any good. It is whether anyone in the arrangement is rewarded for saying: that is enough, ship it.
In mine, nobody was. That took me three months and 668 lines of header to notice.
Top comments (0)