Generative Adversarial Model (GAM)
GAM puts two models on one task: a generator that writes the code, and an adversarial reviewer from a different provider that can only argue with it. The reviewer cannot edit a single file. You start one with /gam.
Starting a pair
/gam rewrite the retry logic to use exponential backoff
The pair is one piece of work in two panes. In the agents list the reviewer sits
directly beneath its generator, hooked to it with a ↳, and the two
move between sections together rather than drifting apart as their statuses diverge.
Two panes open side by side. The left half is the generator, running your current model. The right half is the adversarial reviewer, which defaults to a different provider so it is not the same model marking its own homework: a Claude generator pairs with Codex, and a Codex or opencode generator pairs with Claude.
workspace .rudder-workspaces/retry ● Edit src/net/retry.ts +58 ● Bash npm test · 41 passed ▌ writing the jitter test…
read-only · cannot edit any file ● Read src/net/retry.ts ● Bash npm test -- jitter · 0 matched 41 passing tests do not touch the branch this task exists for.
You can name the reviewer instead of taking the default, and run the pair in your real checkout rather than an isolated workspace:
| you type | what you get |
|---|---|
| /gam <task> | Reviewer picked for you, from the other provider. |
| /gam codex <task> | Codex reviews, on its default model. |
| /gam codex gpt-5.5 <task> | A named provider and model. |
| /gam fable <task> | A bare model name works when Rudder recognises it. |
| /gam main <task> | The pair runs in your checkout instead of a workspace. |
| /gam codex gpt-5.5 main <task> | main works on either side of the model. The picker leaves your cursor after the model it inserted, which is where you would naturally type it. |
Ordinary task words are never mistaken for a model. /gam fix the auth
bug keeps every one of those words as the task, because fix is
not a model name.
How the reviewer steers the work
The reviewer is not a gate at the end. It reads the diff after every turn the generator takes, while the work is still in motion, and what it sends back becomes the generator's next instruction. A pair is a correction loop, not an inspection.
That is what the second model is for. Left alone, a coding agent drifts in ways it cannot see from the inside: it settles on the first approach that compiles, treats the happy path as the whole problem, marks a task done because the code it wrote runs, and never revisits the framing it chose in its first thirty seconds. None of that shows up as an error. It shows up as a confident summary.
So the reviewer is prompted to do the opposite of agreeing. Its instructions tell it to refute first: to hunt for what is wrong, missing, oversimplified or untested, and to check the generator's claims against the actual files rather than against its narrative. Concretely, each round it is asked to establish
| what it checks | the failure it is looking for |
|---|---|
| Does this do what was asked? | A subset delivered as the whole thing. It is handed your ORIGINAL task every round, so this is measured against what you wanted, not against what the last message was about. |
| Was it actually verified? | A check described as run. A Codex reviewer runs the tests itself rather than believing the transcript; a Claude reviewer reads the code and the test files instead (see what each reviewer can do). |
| What was not considered? | The edge the generator never looked at: the error path, the empty case, the concurrent one, the migration that has to happen first. |
| Is the approach right? | A solution that works and should not survive. Cheaper to say in round one than after the diff has grown around it. |
Objections come back as concrete, actionable requests naming a file and a symptom, and they arrive as the generator's next prompt. The generator does not have to be started over or re-briefed; it is mid-task, holding all its context, and it gets a specific correction at the moment it can still act on it cheaply. That is the whole mechanism: steering while the work is happening, rather than judging it once it is finished.
How the two halves talk
The reviewer is not a subagent. Neither model calls the other, and neither can see the other's conversation. They are two ordinary CLI processes in two panes, each holding its own session, exactly like any other agent Rudder runs. Rudder is the pipe between them.
There is no live connection either. The exchange happens at turn boundaries, and Rudder moves it by typing into panes and reading them back:
GENERATOR your model, writes, its own session
REVIEWER other provider, read-only, its own session
generator's turn ends
│ it says so itself, through its own Stop hook
│ or notify program. Rudder never guesses from
▼ the screen, so a half still thinking is safe.
rudder reads the workspace diff
rudder builds the packet
· your ORIGINAL task, every round
· the current diff
· the generator's last rebuttal, if it made one
│
▼ typed into the reviewer's pane, then Enter
REVIEWER reads it, runs its own checks, answers
reviewer's turn ends
│
▼ rudder reads the verdict off its visible screen
accept → the pair settles
revise → the objection is typed into the generator
│
▼
generator's next turn: same session, context intact
Three details are worth knowing, because they are what make the loop reliable:
| step | how it actually works |
|---|---|
| Whose turn it is | Rudder does not guess from the screen. Each CLI reports its own turn-end through its native hook, Claude's Stop hook or Codex's notify program, which writes a signal file Rudder watches. A half that is still thinking is never interrupted. |
| Delivering a message | Rudder types it into the receiving pane as a bracketed paste and presses Enter, exactly as if you had typed it yourself. This is why the generator keeps its context: it is mid-conversation, not restarted with a new brief. |
| Reading the answer | The verdict is read off the reviewer's visible screen, which is why it must arrive wrapped in sentinel lines. No parseable block means Rudder stops and asks you rather than guessing what the reviewer meant. |
Because each half is its own session, nothing leaks between them but the messages above. The reviewer never sees the generator's reasoning, and the generator never sees the reviewer's. That separation is not a policy Rudder asks them to respect; it is a property of running them as two processes that were never introduced.
Checking the generator complied
An objection is a message, not a command. The generator can read it, say
something agreeable, and change nothing. So each round the reviewer is handed three
things to judge that with: its own previous objection, quoted back
verbatim; whether the generator argued back, and what it said; and
the current diff. The contract then asks it, before anything else,
to state whether that objection was ADDRESSED, PARTLY
addressed, or IGNORED, citing the diff. An objection ignored twice is
grounds to escalate.
Silence is reported as silence. Most of the time the generator just complies without arguing, and the packet says so in as many words rather than leaving the section out, because an absent section reads as "nothing happened" when what actually happened is "it did not defend itself, so judge the code".
What each reviewer can actually do
The reviewer is read-only in all three cases, but they are not read-only in the same way, and only some of them can run your tests:
| reviewer | can run checks | how writes are prevented |
|---|---|---|
| Codex | Yes. It runs commands inside a read-only filesystem sandbox. | Refused by the runtime. |
| Claude | No. Its tools are Read, Grep, Glob and LS, so it reviews by reading the code and the tests rather than executing them. | No writing tool exists in its allowlist. |
| opencode | Yes. | By prompt and an approval gate, not by a sandbox. This is the weakest of the three. |
The default pairing is the strongest one: a Claude generator crosses to a Codex reviewer, which can run your checks and genuinely cannot write. Naming the reviewer yourself is how you choose otherwise, and worth knowing about before you do.
Why two models
A model reviewing its own work agrees with itself. It has already decided the approach was reasonable, and asking it to check that decision gets you a summary of the decision rather than a test of it.
So the two halves never share a conversation. Each keeps its own session, and the only things that cross between them are the original task, the diff, the reviewer's objections, and the generator's replies. The reviewer never sees the reasoning that produced the code, because a reviewer that has read the argument for a change is no longer independent of it.
The asymmetry is the other half of the idea. The reviewer has no write access at all, which means it cannot quietly fix what it dislikes and call the disagreement settled. It has to make its case in words, and the generator has to be persuaded.
What a round is
A round begins when the generator finishes a turn. Rudder then hands the reviewer a packet containing:
| what is in the packet | why |
|---|---|
| the original task | Every round is anchored on what you typed, never on the last thing the reviewer asked for, so a long argument cannot drift off the ask. |
| the current diff | The reviewer judges the code, not the generator's account of it. Very large diffs are truncated with a visible marker, and the reviewer is told not to object to what it cannot see. |
| the generator's last reply | Only when the generator pushed back, so the argument carries forward. |
The reviewer is told to refute first: to hunt for what is wrong, missing, oversimplified or untested, and to check claims against the actual files rather than the transcript. It ends its turn with a verdict.
The three verdicts
| verdict | what happens next |
|---|---|
| accept | The pair settles. Reserved for work that plainly satisfies the original task with no blocking defect the reviewer can demonstrate. |
| revise | The objection is delivered to the generator as a message and a new round starts. |
| escalate | The disagreement needs you: a scope dispute, two irreconcilable approaches, or a correct objection the generator keeps ignoring. |
When the generator disagrees
The generator is not required to obey. It is told explicitly not to comply silently with an objection it thinks is wrong, but to state why in one short paragraph and keep implementing. Rudder lifts that reply out and puts it in front of the reviewer on the next round.
This matters more than it sounds. A reviewer that gets its way automatically turns every weak objection into a code change, and the work drifts toward whatever the reviewer happened to notice. Giving the generator a way to win the argument is what keeps the pair converging instead of wandering.
When one model refuses a task or quietly does a subset of it, the other one often does not. The reviewer is reading the diff against the original ask, so it is well placed to notice a job reported as done that was not, and to say so.
When it stops
There is no round limit. A pair keeps going for as long as the argument is getting somewhere, because a fixed count would end a productive exchange mid-sentence and let an unproductive one run to the same number anyway.
What ends it is one of these:
| ending | what happened |
|---|---|
| accepted | The reviewer could not find a blocking defect to demonstrate. |
| escalated | The reviewer asked for you: a scope dispute, two irreconcilable approaches, or a correct objection the generator keeps ignoring. |
| stalled | The generator handed back the same diff AND the same rebuttal as the round before. It did nothing with the objection, so another round would ask the identical question and get the identical answer. A NEW argument counts as progress even with no code change: refusing to edit while explaining why is a legitimate move. |
| no verdict | The reviewer produced no readable verdict block at all. |
| the reviewer can no longer answer | It failed, you stopped it, you deleted its row, or its pane is gone. Each of these used to leave the pair spinning in silence with the generator parked and nothing on screen to explain it; the pair now ends and names the reason. |
Quitting Rudder kills both panes. Only a RUNNING agent is resumed on the way back in, so a reviewer that was idle between rounds returns without a pane and the pair cannot continue. It ends and says so rather than looking alive and doing nothing. The generator's work is untouched in its workspace either way; start a new pair if you want the argument to carry on.
The stall check is what makes an unbounded loop safe to run: it ends on lack of progress rather than on a count. There is a runaway guard far above any argument that is still moving, but reaching it means something went wrong that the stall check did not catch.
In every one of those cases both panes stay live and Rudder names the reason. Nothing is discarded and nothing is merged behind your back: the generator's work sits in its workspace exactly like any other agent's, and it lands when you press m.
A pair spends roughly twice what the same task costs alone per round, and takes longer in wall-clock time, because the reviewer reads a finished diff and the two halves cannot run at the same time. With no round limit that cost is bounded by convergence rather than by a number, so it earns its keep on work where being wrong is expensive, not on a rename.
Why this is worth the second model
The ceiling on a single coding agent is not model quality, and it moves less with each release than people expect. It is that a model cannot reliably audit its own work. The failure is rarely a crash: it is quiet. A subset delivered as the whole thing. A check described as run. A refusal dressed up as a completion. All three read identically to a summary, and all three are caught by reading the diff, which is the part you were hoping to do less of.
Rudder's answer everywhere else is isolation: work that cannot touch other work until you say so. A pair is that same idea pointed at judgment rather than at files. The reviewer cannot edit, comes from a different vendor, and is anchored on the task you actually typed, so its agreement is worth something. A model that could quietly fix what it disliked would never have to make its case, and you would never see the disagreement.
What it does not do is remove you from the loop. It costs about twice, it runs serially, and it is not a substitute for reading the diff before you press m. What it changes is how much you have to catch unaided: the obvious failures are argued out before they reach you, and the ones that survive arrive with a reviewer's objection and a generator's answer attached.