Skip to content

Instantly share code, notes, and snippets.

@claudiosanches
Created July 29, 2026 23:18
Show Gist options
  • Select an option

  • Save claudiosanches/ae37eb5c6367e0581f39cc3f8cfb909c to your computer and use it in GitHub Desktop.

Select an option

Save claudiosanches/ae37eb5c6367e0581f39cc3f8cfb909c to your computer and use it in GitHub Desktop.
Claude Code - Panel Review (Multiple Agents)
name panel-review
description Multi-agent code review — run four independent reviewers in parallel (Claude Code, OpenAI Codex, Google Antigravity/agy, GitHub Copilot), then cross-verify their findings against the real code and produce one consolidated, de-duplicated report ranked by severity. Use when the user asks to review the current branch/PR/diff with the panel, e.g. "panel review", "run the reviewers", "review with codex/agy/copilot", "/panel-review". Accepts an optional target: a base ref, a PR number, --staged, --uncommitted, or specific paths.

Panel review

Overview

Review a change with four independent reviewers running in parallel, then reconcile their output. Different engines catch different bugs and each hallucinates differently, so the value is in the cross-verification: every finding is checked against the actual code before it reaches the report, and agreement across tools raises confidence.

The four reviewers:

Reviewer How it runs Model Sees the repo? Notes
Claude Code a review subagent (Agent tool) current session model yes can read the whole repo, can run tests
OpenAI Codex codex review (CLI) Codex default yes computes its own diff; may run the test suite
GitHub Copilot copilot -p (CLI) claude-sonnet-4.6 (high) yes buffers its verdict to the very end; usually the slowest
Google Antigravity agy -p (CLI) Gemini no headless has no tool access — feed the diff inline; weight it lowest

You (Claude Code) are both the fourth reviewer and the orchestrator/synthesizer.

Weighting: only three of the four can actually open a file. agy reviews the patch in isolation, so it cannot confirm that a symbol exists or that a caller elsewhere breaks. Treat an agy-only finding as a lead to verify, never as evidence; and treat agy's "no issues" as weak evidence of anything.

Inputs

Optional argument:

  • (none) — auto-scope, see the ladder in Step 1.
  • <base-ref> — review git diff --merge-base <base-ref> HEAD (e.g. main, develop).
  • <PR-number> or a PR URL — review that PR's diff (gh pr diff <n>).
  • --staged — staged changes only.
  • --uncommitted — working tree (tracked edits + untracked files), ignoring committed history.
  • one or more paths — restrict the review to those paths.

Procedure

Step 0 — Fix the review directory (do this first, and never use mktemp)

Every Bash tool call runs in a fresh shell: REVIEW_DIR="$(mktemp -d)" set in one call is gone in the next, and the reviewer commands would write to /diff.patch. Use a path that any shell can recompute, inside the git dir so it is automatically ignored:

REVIEW_DIR="$(git rev-parse --absolute-git-dir)/panel-review"; mkdir -p "$REVIEW_DIR"

Use --absolute-git-dir, not --git-dir: the latter returns a bare relative .git, which resolves against whatever directory the command happens to be in and breaks any reviewer that cds.

Re-declare that exact line at the top of every subsequent Bash call. Do not rely on it persisting.

Step 1 — Scope the change

Resolve a base ref defensively. The obvious one-liner is broken — in a pipeline the exit status comes from sed, not symbolic-ref, so || echo main never fires and BASE silently becomes empty, producing fatal: ambiguous argument ''. A repo with no origin at all is common (worktrees, local experiments, fresh git init). Resolve it stepwise and verify:

BASE="${1:-}"
if [ -z "$BASE" ]; then
  BASE="$(git symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null | sed 's@^origin/@@')"
fi
for c in "$BASE" main master develop; do
  [ -n "$c" ] && git rev-parse --verify --quiet "$c" >/dev/null && { BASE="$c"; break; }
done
echo "base: ${BASE:-<none>}"

Then pick the diff by a fallback ladder, because "no committed work" almost never means "nothing to review" — it usually means the work is still in the working tree:

# 1. committed branch work vs base
[ -n "$BASE" ] && git diff --merge-base "$BASE" HEAD > "$REVIEW_DIR/diff.patch"
# 2. nothing committed? fall back to the working tree (staged + unstaged, tracked)
[ -s "$REVIEW_DIR/diff.patch" ] || git diff HEAD > "$REVIEW_DIR/diff.patch"
# 3. ALWAYS append untracked files — `git diff` never shows them, and a brand-new
#    file is exactly where bugs hide. `--no-index` emits a proper "new file" patch
#    without touching the index (`git add -N` would mutate the user's repo).
git ls-files --others --exclude-standard -z | while IFS= read -r -d '' f; do
  git diff --no-index /dev/null "$f" >> "$REVIEW_DIR/diff.patch" 2>/dev/null || true
done
git diff --stat HEAD > "$REVIEW_DIR/files.txt" 2>/dev/null
wc -c < "$REVIEW_DIR/diff.patch"

State which rung you landed on in the final report — "reviewed uncommitted working tree, not committed history" is information the user needs to trust the result. Only stop if the patch is still empty after rung 3.

Then note what the change does. That one-paragraph summary goes into the brief so reviewers get intent, not just a patch.

Write the shared brief to $REVIEW_DIR/brief.md using Reviewer brief below.

Step 2 — Launch all four reviewers in parallel

Start the three CLI reviewers as background Bash jobs (each to its own file), and in the same turn spawn the Claude reviewer subagent. Do not block between them. Verify the CLIs first with command -v agy codex copilot.

REVIEW_DIR="$(git rev-parse --absolute-git-dir)/panel-review"   # re-declare in every call

# OpenAI Codex — dedicated `review` subcommand.
#   `--base <ref>` for committed work, `--uncommitted` for working-tree work.
#   NOTE: `--base` and a custom [PROMPT] are MUTUALLY EXCLUSIVE — one or the other.
#   With either flag you get Codex's built-in review instructions and the brief is ignored;
#   that is fine, they are good. Match the flag to the rung Step 1 landed on.
codex review --uncommitted > "$REVIEW_DIR/codex.md" 2>&1

# GitHub Copilot — runs in the repo. `--allow-all-tools` is REQUIRED non-interactively.
copilot -p "$(cat "$REVIEW_DIR/brief.md"; echo; echo "The unified diff under review is at $REVIEW_DIR/diff.patch. Read it and the surrounding files before reviewing.")" \
  --allow-all-tools --add-dir "$PWD" > "$REVIEW_DIR/copilot.md" 2>&1

# Google Antigravity — headless has NO tool access, so inline the diff.
# Do NOT pass --dangerously-skip-permissions (the auto-mode classifier rejects it).
agy -p "$(cat "$REVIEW_DIR/brief.md"; echo; echo '## Diff to review'; echo '```diff'; cat "$REVIEW_DIR/diff.patch"; echo '```')" \
  --print-timeout 4m > "$REVIEW_DIR/agy.md" 2>&1

For the Claude reviewer, use the Agent tool (code-reviewer if available, else general-purpose) with the brief plus "read $REVIEW_DIR/diff.patch and the surrounding repo; run cargo check/the project's verify command to confirm compile-level claims; return findings in the required format." Tell it to verify rather than speculate — it is the only reviewer you can instruct.

Robustness: if a CLI is missing or errors (command not found, auth failure, non-zero exit), keep going with the reviewers that worked and record which one dropped out — never silently proceed as if all four ran.

Step 3 — Collect

Poll until each background job finishes; don't judge progress by file size.

  • Output size is not progress. Copilot streams a tool-call trace and buffers its actual verdict to the end — a file that sat at 562 bytes for minutes was mid-review, not hung. Check liveness with pgrep -af copilot (or the job's exit record) before declaring a reviewer dead.
  • A tiny file is not a failure. A 17-byte agy.md reading No issues found. is a complete, valid review. Read it before concluding anything.
  • Codex output is a full transcript (tens of KB even for a 30-line diff), and it may run the test suite — worth capturing, since "32 tests passed" is real evidence. Its findings are the prose block after the last bare codex line: awk '/^codex$/{n=NR} END{print n}' then print from there. Codex sometimes repeats that final paragraph verbatim; de-duplicate it.

Parse each into {severity, file, line, summary, rationale, suggested_fix, source_tool}.

Step 4 — Cross-verify, then de-duplicate

This is the point of the skill. For every finding, before it can appear in the report:

  1. Verify against the real code. Open the cited file:line and confirm the problem is actually there. Aggressively check any claim that a symbol / field / method / API / column doesn't exist or is deprecated — reviewers hallucinate these. Confirm against the real source (and the dependency/schema/API version in use), not the reviewer's assertion.
  2. Trace the control flow before believing a "wrong state" claim. State that looks wrong at the assignment is often correct two hops later — e.g. a handler setting screen = Chat while clearing active can still land on the home screen, because the render match falls through on active = None. Follow the path to where it is consumed; do not judge the assignment alone.
  3. Assign a verdict: CONFIRMED (verified real), PLAUSIBLE (can't fully confirm without running it, but the reasoning holds), or REFUTED (checked — it's wrong; drop it, and note why).
  4. De-duplicate across tools: findings at the same location about the same defect merge into one, listing every tool that raised it. Multi-tool agreement is a strong confidence signal — but see the weighting note: agreement between two tools that both only read the patch is weak.
  5. Rank by severity (blocker → high → medium → low), then by cross-tool agreement.

Drop pure style/formatting nits the project's linter already enforces.

A unanimous "no issues" is a real result — report it as such. Do not manufacture findings to justify the run, and do not upgrade a stylistic preference into a defect to fill the table.

Step 5 — Report

## Panel review — <scope> (<n> files)
Scope: <which rung — committed vs base / uncommitted working tree / PR #n>
Reviewers: Claude ✓  Codex ✓  Antigravity ✓  Copilot ✗ (not installed)

| # | Sev | Location | Issue | Found by | Verdict |
|---|-----|----------|-------|----------|---------|
| 1 | High | src/x.php:42 | <one line> | codex, agy | CONFIRMED |

### Details
1. **<title>** — src/x.php:42 — *CONFIRMED* (codex, agy)
   <what's wrong, the failure scenario, and the fix>

### Refuted / dropped
- <claim> — REFUTED: <why it's wrong> (raised by <tool>)

### Coverage notes
- Any reviewer that didn't run, and anything the panel likely under-covered.

Lead with confirmed, highest-severity findings. Keep the table tight; reasoning goes in the details. If nothing survived verification, say so plainly.

Reviewer brief

Give every reviewer the same brief (write it to $REVIEW_DIR/brief.md), filling the bracketed parts:

You are one of four independent code reviewers. Review ONLY the change below for real defects.

## What changed
[one-paragraph summary of intent + the list from files.txt]

## What to look for
Correctness bugs, security issues, data loss, race conditions, resource leaks, broken error handling,
API/contract misuse, and missed edge cases in the CHANGED code. Also call out high-value
simplifications or reuse. Ignore pure style/formatting the linter handles.

## Rules
- Only flag issues you can tie to specific changed lines.
- If you are not certain a symbol, field, method, API, or column exists, SAY SO — do not assume it
  doesn't. Baseless "X doesn't exist / is deprecated" claims are worse than no finding.
- Before claiming state is set wrongly, trace where that state is consumed — the assignment alone
  does not tell you where the user lands.
- "No issues found." is a perfectly good answer. Do not invent findings to seem thorough.
- Verification commands in this repo: [test / typecheck / lint commands].

## Output format
For each finding, one block:
SEVERITY: blocker | high | medium | low
LOCATION: <path>:<line>
ISSUE: <one line>
WHY: <concrete failure scenario, or why it's wrong>
FIX: <short suggested fix>

If you find nothing, say "No issues found."

Tool invocation reference (verify against your installed CLI versions)

  • agyagy -p "<prompt>" --print-timeout 4m. Binary at ~/.local/bin/agy. Headless mode has no file/tool access, so the diff must be inlined; it cannot verify anything about the wider repo. Never pass --dangerously-skip-permissions. Buffers output to the end. On a small inlined diff it can finish in seconds — speed varies with diff size, so bound it but don't assume it is the laggard.
  • codexcodex review --base <branch> for committed work, codex review --uncommitted for staged/unstaged/untracked. --base and a custom [PROMPT] are mutually exclusive. Output is a full transcript; findings are the block after the last bare codex line.
  • copilotcopilot -p "<prompt>" --allow-all-tools --add-dir <repo>. --allow-all-tools is required non-interactively. Model configured to claude-sonnet-4.6 (high); add --model to override. Streams a progress trace and buffers the verdict to the end — often the slowest of the four.

If any command's flags differ in your environment, fix them here — this section is the single place the invocations live.

Gotchas

  • Never mktemp. Shell state does not survive between Bash tool calls; derive REVIEW_DIR from git rev-parse --absolute-git-dir and re-declare it in every call.
  • Empty diff ≠ nothing to review. Walk the Step 1 ladder before giving up, and always append untracked files — otherwise a branch whose whole contribution is new files gets a clean bill of health without a single line being read.
  • Verify, don't trust. The whole point is Step 4. The biggest failure mode is passing through a confident but wrong "this field/function doesn't exist" finding.
  • No silent drops. If a reviewer didn't run, the report must say so; three-of-four is fine if stated.
  • Don't confuse buffering with hanging, or a short answer with a failed one. Check the process.
  • Keep the diff bounded. For very large changes, review the highest-risk paths (or split the run); inlining a huge diff into agy can exceed its prompt budget.
  • Parallel, not serial. Launch all four before waiting on any — the CLIs are the slow part.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment