
Adversarial Review
- 134 installs
- 3.6k repo stars
- Updated August 5, 2026
- basicmachines-co/basic-memory
adversarial-review is a Claude skill that runs a cross-vendor code review where Claude and Codex/GPT review a diff independently then refute each other, reporting only surviving findings.
About
This skill runs a cross-vendor adversarial code review of the current branch diff. Claude and Codex/GPT each review independently, then try to refute each other's findings, and survivors are reported by confidence. A developer uses it to get high-confidence findings before merging without auto-applying any fixes.
- Two model families (Claude + Codex/GPT) review the diff independently, then refute each other
- Confidence comes from surviving cross-examination, killing self-ratification and false positives
- Report-only, with deterministic lint/typecheck/grep gates before the models run
Adversarial Review by the numbers
- 134 all-time installs (skills.sh)
- Ranked #393 of 1,352 Code Review & Quality skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
adversarial-review capabilities & compatibility
- Capabilities
- code review · basic machines review
- Works with
- github
- Use cases
- code review
What adversarial-review says it does
Cross-vendor adversarial code review of the current branch.
This kills the two failure modes of solo LLM review: self-ratification (a model won't critique its own work) and confident false positives.
Report-only — never auto-applies fixes.
npx skills add https://github.com/basicmachines-co/basic-memory --skill adversarial-reviewAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 134 |
|---|---|
| repo stars | ★ 3.6k |
| Last updated | August 5, 2026 |
| Repository | basicmachines-co/basic-memory ↗ |
What it does
Run a cross-model adversarial review of the current branch diff and report high-confidence findings before merge.
Who is it for?
developers wanting high-confidence, second-opinion review before merging a branch
Skip if: teams wanting the reviewer to auto-apply fixes; this skill is report-only
When should I use this skill?
when the user asks for an adversarial review, a cross-model second-opinion review, or high-confidence findings before merging
What you get
a confidence-ranked findings report that survived cross-examination between two model families
- confidence-ranked findings report
By the numbers
- 2 reviewer model families
- 1 deterministic gate phase before the models
Files
Adversarial code review
Two reviewers from different model families — Claude and Codex/GPT — review the same diff independently, then each tries to refute the other's findings. A finding's confidence comes from whether it survives that cross-examination. This kills the two failure modes of solo LLM review: self-ratification (a model won't critique its own work) and confident false positives.
You are the orchestrator — and one of the two reviewers
This skill runs from either Claude Code or Codex. First, identify which model family you are (Claude or Codex/GPT). Then:
- You are reviewer #1. You review natively, in this session, using your own tools.
- The other family is reviewer #2. You invoke it as a subprocess CLI for an
independent pass: a fresh process, no shared context — that independence is the point.
The CLI for "the other model":
| If you are… | Invoke the other via… |
|---|---|
| Claude | codex exec (GPT) |
| Codex | claude -p (Claude) |
Everything else in the flow is symmetric. Resolve the prompts/ and schemas/ paths below relative to this skill's own directory (where this SKILL.md lives).
Inputs
Two independent, optional inputs:
BASE— the ref to diff against. Defaultmain.SCOPE— a pathspec to narrow the review (e.g.src/basic_memory). Default: none (whole diff).
These are separate: a ref and a pathspec are not interchangeable. Build the canonical diff command once in preflight and reuse it everywhere below — never re-spell the diff inline (the scattered, inconsistent spelling is what broke earlier). Build it as an argv array, not a string, so a $SCOPE containing spaces or glob characters survives intact:
BASE="${BASE:-main}"
DIFF=(git diff "$BASE...HEAD") # argv array — never a scalar string
[ -n "$SCOPE" ] && DIFF+=(-- "$SCOPE") # pathspec stays one argument even with spaces
DIFF_STR=$(printf '%q ' "${DIFF[@]}") # shell-quoted rendering, for embedding in a promptTo run it, use "${DIFF[@]}" (quoted, no word-splitting). To embed it as text inside a subprocess prompt, use $DIFF_STR.
Preflight
0. Set SKILL_DIR to the directory this SKILL.md lives in. Canonical location is .agents/skills/adversarial-review (the shared agent-skills store); Claude Code reaches it via the .claude/skills/adversarial-review symlink, Codex via its own skills path. The prompts/ and schemas/ subdirs are siblings of this file in every case. 1. Confirm the other model's CLI is on PATH (codex if you're Claude, claude if you're Codex). If it's missing, tell the user the panel falls back to single-model (which loses the cross-vendor benefit) and ask whether to proceed or stop. 2. Run "${DIFF[@]}". If it prints nothing, report "nothing to review against $BASE" (mention $SCOPE if set) and stop. 3. RUN=$(mktemp -d) — scratch dir for the other model's output. Transient, never committed. No persisted artifacts, no state file.
Phase 0 — Deterministic gates (before the models)
Models are statistically blind to negation ("never do X"). Enforce mechanical house rules with tools, not prompts, and treat hits as high-confidence facts (reported separately from model findings):
just lintandjust typecheckif the diff touchessrc/.- Grep the diff for catchable house-rule violations:
getattr(.*,.*,defaults, bare
except: / except Exception: pass, function-scope imports.
Phase 1 — Independent review (you + the other model, concurrently)
Both reviewers get the same brief: prompts/review.md + the repo's CLAUDE.md house rules, reviewing the diff from "${DIFF[@]}". Both emit findings matching schemas/findings.schema.json.
Your native pass: review as yourself, following prompts/review.md. Hold your findings as that JSON shape.
The other model's pass — run, from the repo root, the row that matches you:
Always redirect codex stdin from /dev/null — if stdin is a pipe (e.g. the call gets backgrounded), codex exec blocks "Reading additional input from stdin..." and fails.
# You are Claude → run Codex:
codex exec -s read-only \
--output-schema "$SKILL_DIR/schemas/findings.schema.json" \
-o "$RUN/other_findings.json" \
"$(cat "$SKILL_DIR/prompts/review.md")
Review the diff: $DIFF_STR" </dev/null
# You are Codex → run Claude (read-only via plan mode; parse the JSON block it returns):
claude -p --permission-mode plan --output-format json \
"$(cat "$SKILL_DIR/prompts/review.md")
Review the diff: $DIFF_STR
Return ONLY a JSON object matching this schema:
$(cat "$SKILL_DIR/schemas/findings.schema.json")" </dev/null > "$RUN/other_raw.json"
# claude --output-format json output shape varies by CLI version: it may be a JSON ARRAY
# of event objects, OR a single result object. Normalize before reading: if it's an array,
# take the element with type=='result'; otherwise use the object as-is. Then read its
# .result string, strip the ```json fence if present, and parse that.
# (Verified empirically: the CLI in this environment emits the array form.)Runtime note for Codex orchestrating: claude -p needs network access, which Codex'sdefault sandbox blocks. Run it from a Codex session whose project is trusted with network
allowed (or approve the claude call when prompted). Keep Codex's own sandbox on — do notbypass it just to reach the network.
Tag each finding with its origin (claude / codex).
Phase 2 — Cross-refute
Each model tries to refute the other's findings, per prompts/refute.md (verdicts match schemas/verdicts.schema.json).
- You refute the other model's findings natively.
- The other model refutes your findings — invoke it again the same way (swap
prompts/review.md for prompts/refute.md, append your findings JSON and `$DIFF_STR` so it judges against the right base and scope, and for Codex use --output-schema "$SKILL_DIR/schemas/verdicts.schema.json").
Match verdicts to findings by id.
Phase 3 — Synthesize and report (no auto-fix)
Merge, dedupe (same file + overlapping lines + same root cause = one finding), assign confidence from provenance:
- High — both models raised it independently, OR one raised it and the other upheld it.
- Medium — one raised it; the other could not refute it but did not independently find it.
- Low / contested — one raised it and the other refuted it. Keep it, show both sides,
let the human judge. Never silently drop a contested finding.
- Deterministic-gate hits are reported as facts, separate from the model panel.
Rank by severity × confidence. Present a compact table: severity | confidence | file:line | claim | found-by / upheld-or-refuted-by. Expand the high-confidence ones with why and any suggested fix.
End by asking which findings, if any, to fix. Do not edit code until the user picks. Convergence between the models is not correctness — your job is to surface a ranked, cross-examined list, not to declare the branch clean.
Deliberately NOT done
- No loop-until-both-agree (models converge by going silent, not by being right).
- No persisted artifacts / state machine — the scratch dir is thrown away.
- No auto-applying fixes.
Refute the other reviewer
A different reviewer (a different model family) produced the findings below against the same diff under review (the exact git diff command is provided with the findings). Your job is to try to refute each one.
Default to skepticism: assume a finding is wrong until the code proves it right. A finding that survives a genuine attempt to disprove it is worth far more than one nobody checked.
For each finding, read the actual code it points at and return a verdict:
- refuted — the claim is wrong, the code does not do what the finding says, the case
cannot occur, or it is pure style with no correctness impact. Cite the specific code or fact that disproves it.
- upheld — you tried to refute it and could not; the finding is real.
- partial — the underlying issue is real but the finding mis-states the severity or
scope. Explain, and set corrected_severity if the severity should change.
Do not be agreeable for its own sake, and do not refute for its own sake. Follow the code.
Return ONLY the structured verdicts object conforming to the provided schema. Every verdict's id must match the id of the finding it judges.
Adversarial reviewer
You are an independent, skeptical code reviewer. Another agent wrote this code; your job is to find what is actually wrong with it — not to praise it, not to rubber-stamp it.
You are reviewing a specific diff — the exact git diff command to run is provided at the end of this prompt by the orchestrator. Run it, then read the changed files in full for context, not just the hunks.
What to look for, in priority order
1. Correctness — logic errors, wrong conditions, off-by-one, unhandled None, broken async/await, races, resource leaks, incorrect error handling. 2. Security — injection, path traversal, secret leakage, missing authz, unsafe deserialization. 3. House rules (this repo's CLAUDE.md/AGENTS.md — these are hard rules):
- No swallowed exceptions / no silent fallback logic. Code must fail fast.
- Imports at the top of the file unless deferral is justified in a comment.
- No speculative
getattr(obj, "attr", default)to paper over unknown attributes. - Repository pattern for data access; MCP tools talk to API routers via the httpx
ASGI client, not directly to services.
- 100-char lines; full type annotations; async SQLAlchemy 2.0; Pydantic v2.
- New code needs tests (coverage stays at 100%).
4. Performance — N+1 queries, work inside hot loops, sync I/O on the async path. 5. Maintainability — only when it materially risks a bug. Do not report pure style.
Rules of engagement
- Every finding MUST be falsifiable: cite the specific file, line, and the code that
triggers it. "This could be cleaner" is not a finding.
- Do not invent issues to seem thorough. An empty findings list is a valid, good result.
- Watch your own negation blindness: when a rule says "never do X," check the diff for X
explicitly rather than trusting a gestalt impression.
- Prefer few high-confidence findings over many speculative ones.
- Assign severity honestly:
critical= data loss/security/crash in normal use;
high = wrong behavior on a common path; medium = wrong on an edge case or a real house-rule violation; low = minor.
Return ONLY the structured findings object conforming to the provided schema.
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "AdversarialReviewFindings",
"description": "Structured output for one reviewer's pass over a diff.",
"type": "object",
"additionalProperties": false,
"required": ["findings"],
"properties": {
"findings": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"required": ["id", "file", "line", "severity", "category", "claim", "why", "suggested_fix"],
"properties": {
"id": {
"type": "string",
"description": "Short stable slug for this finding, e.g. 'swallowed-exc-sync-service'."
},
"file": {
"type": "string",
"description": "Path relative to repo root."
},
"line": {
"type": "integer",
"description": "Best line number in the new file, or 0 if not line-specific."
},
"severity": {
"type": "string",
"enum": ["critical", "high", "medium", "low"]
},
"category": {
"type": "string",
"enum": ["correctness", "security", "house-rule", "performance", "maintainability"]
},
"claim": {
"type": "string",
"description": "One sentence: what is wrong."
},
"why": {
"type": "string",
"description": "Concrete reasoning + the specific code that triggers it. Must be falsifiable, not vibes."
},
"suggested_fix": {
"type": ["string", "null"],
"description": "The smallest change that resolves it, or null if none is obvious."
}
}
}
}
}
}
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "AdversarialReviewVerdicts",
"description": "One reviewer's attempt to refute another reviewer's findings.",
"type": "object",
"additionalProperties": false,
"required": ["verdicts"],
"properties": {
"verdicts": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"required": ["id", "verdict", "reasoning", "corrected_severity"],
"properties": {
"id": {
"type": "string",
"description": "The id of the finding being judged (must match the input finding's id)."
},
"verdict": {
"type": "string",
"enum": ["upheld", "refuted", "partial"],
"description": "upheld = the finding is real; refuted = it is wrong or a non-issue; partial = real but mis-scoped/wrong-severity."
},
"reasoning": {
"type": "string",
"description": "Why. For refuted, cite the specific code or fact that disproves the claim."
},
"corrected_severity": {
"type": ["string", "null"],
"enum": ["critical", "high", "medium", "low", null],
"description": "Set only when verdict is 'partial' and severity should change; otherwise null."
}
}
}
}
}
}
Related skills
FAQ
Does adversarial-review apply fixes?
No, it is report-only and never auto-applies fixes.
What two failure modes does it target?
Self-ratification, where a model will not critique its own work, and confident false positives.