| 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. |
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.
Optional argument:
- (none) — auto-scope, see the ladder in Step 1.
<base-ref>— reviewgit 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.
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.
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.
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>&1For 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.
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.mdreadingNo 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
codexline: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}.
This is the point of the skill. For every finding, before it can appear in the report:
- Verify against the real code. Open the cited
file:lineand 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. - 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 = Chatwhile clearingactivecan still land on the home screen, because the render match falls through onactive = None. Follow the path to where it is consumed; do not judge the assignment alone. - Assign a verdict:
CONFIRMED(verified real),PLAUSIBLE(can't fully confirm without running it, but the reasoning holds), orREFUTED(checked — it's wrong; drop it, and note why). - 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.
- 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.
## 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.
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."- agy —
agy -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. - codex —
codex review --base <branch>for committed work,codex review --uncommittedfor staged/unstaged/untracked.--baseand a custom[PROMPT]are mutually exclusive. Output is a full transcript; findings are the block after the last barecodexline. - copilot —
copilot -p "<prompt>" --allow-all-tools --add-dir <repo>.--allow-all-toolsis required non-interactively. Model configured to claude-sonnet-4.6 (high); add--modelto 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.
- Never
mktemp. Shell state does not survive between Bash tool calls; deriveREVIEW_DIRfromgit rev-parse --absolute-git-dirand 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
agycan exceed its prompt budget. - Parallel, not serial. Launch all four before waiting on any — the CLIs are the slow part.