/kosuke:adversarial-review
/kosuke:adversarial-review has two or more AI models review every change on your branch. A model that did not raise a MAJOR or CRITICAL finding checks it against the code. A judge settles disputes. MINOR findings are confirmed without a critic or judge. You get a report of the findings that hold up and a verdict, and the pull request gets a label and a comment. It changes nothing unless you add --fix.
After a finished review, the next one reviews only what changed since. The verdict still covers the whole branch.
When to use it
Run it before you ask for review or merge a change that matters. It is most useful with models from two providers, such as a Claude model and a GPT model.
- The branch needs changes over its Target Branch. Commits and uncommitted changes to tracked files both count. A new file counts too, unless .gitignore ignores it.
- Each model you name must come from a provider the session's Assignee can run. See AI providers.
- Every model runs on its provider's Credential Owner for the session, the Assignee's Subscription or the workspace's Credentials, so each one you add costs usage.
- For the comment, the branch needs an open pull request with the reviewed code pushed. Without one, the review labels the chat session, and the label reaches the pull request when it opens.
Run it
Type /kosuke:adversarial-review, or $kosuke:adversarial-review in a Codex session.
The Review & QA button in the chat runs only the checks that have not passed: /kosuke:adversarial-review --fix, then /kosuke:automated-qa --fix for the items not yet passed, which waits in Up next until the review's Turn ends. Once both have passed, it runs both again and asks which QA sections to test. Its menu runs either one alone. The button names no models, so the agent picks them.
| Argument | What it does | Default |
|---|---|---|
--models <name>-<effort> ... | The models that review. Name two or more, or auto. | auto: the agent picks them. |
--restart | Reviews the whole branch again, as a first review does. Findings number from F1 again. | Off. A review after a finished one covers what changed since. |
--fix | Fixes selected MAJOR and CRITICAL findings and batches cheap MINOR fixes. Expensive MINOR findings stay open. | Off. The review only reports. |
--fix F1 F3 | Selects only the findings you name. The MINOR cost rule still applies. | Off |
Write each model as a name, a dash and an effort, such as opus5-xhigh. Without an effort, it uses high.
| Name | Model |
|---|---|
opus, opus5 | Claude Opus |
sonnet, sonnet5.5 | Claude Sonnet 5.5 |
fable, fable5 | Claude Fable |
haiku, haiku5.5 | Claude Haiku 5.5 |
astra, sol, luna | The GPT model with that name |
gpt-..., claude-... | The model whose full name matches |
With auto, the agent picks one model from each provider the session can run, up to three, and before the first run lists them in the chat, one line per model: provider, model name and effort. It picks from current models only, never at max or ultra effort, and weighs cost against what the change needs: lighter models for a small change, each provider's strongest for a large or risky one. A rerun of a review cut off on the same code keeps that review's models. It keeps them only while they are all available and follow these rules, and picks again otherwise. When only one provider is available, two of its models review, and the agent adds to that list that the full adversarial review needs at least three connected AI providers.
The efforts are low, medium, high, xhigh, max and ultra. When a model lacks the effort you asked for, ultra becomes max, and max becomes xhigh. Before the first run, the agent shows the model each name resolved to. It asks you when a name matches several models or none, or when fewer than two different models remain.
/kosuke:adversarial-review
/kosuke:adversarial-review --models opus5-xhigh astra-medium
/kosuke:adversarial-review --models opus sonnet sol-high
/kosuke:adversarial-review --models opus5-xhigh astra-medium --fix F1 F3
/kosuke:adversarial-review --restart

What it does
- It captures what changed since the last finished review, or the whole change on a first review. It reads what the change is for from your messages, the commits and the pull request.
- Each model reviews those changes once for correctness, architecture, code quality and whether it does what you asked.
- Findings that describe the same defect are merged and numbered
F1,F2and so on. When the changes touch a finding the last review left open, another model checks whether it is gone. - A critic checks each MAJOR and CRITICAL finding against the code. MINOR findings are confirmed without debate. The critic is a model that did not raise the finding, when you named enough models.
- When the critic disagrees, a judge from another model decides.
- With
--fix, the agent fixes the selected MAJOR and CRITICAL findings. Another model checks each fix. A failed fix returns to its fixer once in the same round. Cheap MINOR findings get one batch without verification. Expensive MINOR findings stay open. - It publishes the verdict, labels the chat session and the pull request, and posts a comment on the pull request.
Each Delegated Run shows as its own row in the chat, named by its stage and model, such as review-astra@3f9a1c2e or critic-opus@3f9a1c2e, then the model and effort it runs. A verify0- row checks a finding the last review left open. The part after @ changes whenever what the reviewers read changes, such as the code, what it is for or the earlier findings.
When nothing changed since the last finished review, --fix fixes its findings without reviewing again, even after earlier fixes. When the code changed, it reviews the changes first, then fixes. F1 F3 name the same findings either way. With --restart, --fix F1 F3 asks you first, because the findings number from F1 again. It asks too when a full review carries no findings from the last one, for the same reason.
The fixes follow your Commits preference, set in Your account and preferences. With Automatic, the agent commits each group of fixes and pushes. With Manual, the fixes stay uncommitted for you to review.
Fix retries and MINOR findings
A first NOT_HELD result returns the quoted code and reason to the same phase's fixer. The fixer can fix the defect or dispute the verdict with quoted code. A judge decides a dispute without a critic. When available, that judge uses a model different from both the fixer and verifier. A judge that sides with the fixer makes the fix hold.
After a retry, the verifier re-checks only the returned findings. A second NOT_HELD, or a judge that sides with the verifier, opens a successor finding for you. It starts no third automatic fix. A skipped retry also leaves the defect for you.
A cheap MINOR fix stays in one file, changes a few lines, and needs no new test. All cheap MINOR fixes share one batch in the last wave of each fix round. The agent commits the batch and starts no verifier for it. Every other MINOR finding stays open, even when you name it with --fix F1.
The report and pull request comment list Fixed without verification and MINOR left open separately. Neither group prevents a Ship verdict.
What you get
The report is an Artifact named adversarial-review.html, titled Adversarial review: <branch> and headed Adversarial review v3. A branch has one: every review publishes into it, so you open the same report each time. From v2 on, the Artifacts tab shows the version under the title, after the type, such as Mockup · v2. A new review raises the version by one, including a --fix that reviews code changed since the last review. A --fix that finds nothing changed and a reopened review keep it. --restart starts it over at v1. It updates while the review runs. It shows the models, every finding with its state and severity, and the tokens and cost of each run. The reply lists every open finding, most severe first, with its claim and a suggested fix, then the verdict.

| Verdict | Label | Meaning |
|---|---|---|
| Ship | review: passed | No blocking or unresolved finding remains. Confirmed MINOR findings may stay open. Committed cheap MINOR batches count as fixed without verification. |
| Ship with open items | review: open items | No confirmed critical or major finding is left unfixed or unaccepted. A contested or inconclusive finding remains, or a major or critical fix has no completed check. |
| Do not ship | review: failed | A confirmed critical or major finding is neither fixed nor accepted by you. |
| Incomplete | None | The review stopped early. Fewer than two models were left, the turn reached its limit of 40 runs, or you stopped it. |
The labels use the same words as the QA labels, qa: passed and qa: failed, because both sit on the same pull request. The verdict is the review's alone: a pull request is ready only when QA has passed too. Pull requests reviewed before these labels were renamed carry review: ship and review: do not ship. review: ship still counts as review: passed when a pull request is marked ready, and the next review replaces either one.
| Severity | Meaning |
|---|---|
| Critical | Data loss, a security or access breach, or a broken core flow. |
| Major | Another wrong result, a reliability or performance failure, or a design defect with a real maintenance cost. |
| Minor | A local issue with limited impact, such as naming or copy. |
| Finding state | Meaning |
|---|---|
| Confirmed | The critic agreed, the judge upheld it, or it is MINOR and needs no critic. |
| Killed | The judge rejected it. |
| Inconclusive | The judge could not settle it. |
| Contested | The critic disagreed and no judge ruled. |
Leaving a finding as it is
A confirmed finding you decide to leave as it is can be accepted. Pick the option Leave it as it is when the agent asks what to do about a finding, or tell it in the chat, such as "leave F8, I accept the risk". The agent records your words and the finding gets the status Accepted by you.
An accepted finding no longer counts against the verdict, whatever its severity. With every critical and major finding fixed or accepted, the verdict is Ship with open items, or Ship when nothing else is open. The verdict's reason names each accepted finding. The report shows the finding with your words as the reason, and the pull request comment lists it under Accepted by the member. The finding stays in the code, so the report never calls it fixed.
Accepting is not declining. A finding you leave out of --fix, such as by naming only F1 F3, is Declined by you. That says nothing about the risk. A critical or major finding still counts against the verdict until you accept it. If you change your mind about an accepted finding, ask for the fix with --fix F8.
The agent puts the verdict's label on the chat session as a Session Label. It replaces only the standard review labels, which are the three verdict labels above, review: skipped, review: ship and review: do not ship. Your custom labels stay, including other review: labels. New project labels use green for Ship, yellow for Ship with open items and red for Do not ship. Existing project label colors stay as you set them. When the open pull request holds the reviewed code, the agent labels it and removes every other review: label there. Without a pull request, Kosuke adds the session's label to the pull request when it opens. It then posts a comment headed Review: <label> at <commit>. The comment states the scope, names the models, says whether fixes ran, names the report's version and links to the report, which opens its latest version, and lists the fixed findings, the open ones and the ones you accepted. Each run posts a new comment.
The skill uses kosuke sessions labels edit to save the session verdict from the sandbox.
There is no label and no comment when the verdict is Incomplete, when tracked files have uncommitted changes, or, after --fix, while a phase's fixes are not committed. With a pull request open, unpushed commits and newer commits on GitHub also leave it unlabelled. So does a commit made after the code the review covered.
Reviews after the first
Once a review finishes, the next /kosuke:adversarial-review on the branch covers only what changed since. That means new commits, uncommitted changes, new files .gitignore does not ignore, and how you resolved conflicts when you merged the Target Branch. It leaves out the code the merge brought in from the Target Branch. The report and the pull request comment state the scope, such as Incremental from review 4 at abc1234.
The verdict still covers the whole branch. Findings the last review left open still count against it.
Findings keep their IDs
Every finding of the last review carries over with the same ID, in its own group in the report. Accepted findings stay accepted. New findings number on from the highest ID. So --fix F3 names the same finding in every review of the branch.
Findings fixed by hand
When the new changes touch a finding the last review left open, a model checks whether the problem is gone. A full review checks every open finding. The check runs on a model that did not raise or fix the finding, from another model family. If the problem is gone, the report marks the finding "Fixed by hand", and it stops counting against the verdict. If it is still there, the finding stays open. When the review has no such model, the finding stays open and the report names the missing check.
Undone fixes
When the changes undo an earlier fix, a reviewer raises the problem again as a new finding. It names the finding it reopens. Once it is confirmed under the severity rule, the earlier fix no longer counts, and the new finding carries the problem.
Nothing new
When nothing changed since the last finished review, no model runs. The reply says so, repeats that review's verdict and suggests --restart. The label and the comment stay as they are.
After a merge conflict
When the code from the last review cannot replay onto the new merge base, the review stays incremental. It reads the conflicted files and files your branch changes that the Target Branch also changed since the previous merge base. It also keeps your later branch changes in scope. The report states this narrower scope and why. Coverage and open findings carry over for the rest.
When a review covers the whole branch
A review covers the whole branch, and the report and comment say why, in these cases:
- It is the branch's first finished review, or you added
--restart. - A rebase or a force-push removed the reviewed commit from the branch.
- The reviewed commit is not in the sandbox's copy of the repository, such as a commit an earlier sandbox never pushed.
- The code the last review covered, or its merge base, is not in the sandbox's copy of the repository.
- The last review did not record which commit it covered.
- The last review's state did not come back on a new sandbox. See Limits.
- The last finished review was reopened, by
--fixor by your answer to its question, and stopped before it finished again. A review from before incremental reviews counts as reopened when it stopped during its fixes. - The last
--restartreview did not finish with a verdict other than Incomplete.
A full review still carries the last review's findings with their IDs. The exceptions are --restart, a first review, a state that did not come back, a reopened review that did not finish again, and an unfinished --restart review.
Coverage gaps
The next review starts from the last code a model read. With --fix, that includes each round of fixes a model checked and each committed cheap MINOR batch. The batch is an explicit exception; the report does not claim a verifier read it. When no check of a round finished, or the code changed after the review read it, the report and the comment name the gap. The next review covers those changes.
A review that stopped at the limit of 40 runs ends Incomplete, and no review continues from it. Run it again on the same code, and it reuses the reviews that finished.
On a new sandbox
When the session gets a new sandbox, Kosuke writes back the last finished review of the branch from this chat session. The next review continues from it, and an answer to a question the review asked still reopens it.
Limits
- A new sandbox gets back the review, not the commits. Kosuke writes back only reviews published in this chat session.
- A reviewed commit that was never pushed is gone with the old sandbox. The next review then covers the whole branch.
- A report too large to also hold the review's state leaves the state out, and says so. A new sandbox then runs a full review.
- The runs of an old sandbox do not come back. A review cut off at the run limit starts its runs again on a new sandbox.