Delivery review (/check-delivery)
The code exists. That changes what a review is: the strongest available evidence is cheap to collect, so collecting it is mandatory rather than optional.
Sibling of /check-plan, which reviews the document before it is built. This
one reviews the delivery after. Where that skill's failure mode is a reviewer
inventing a file path, this one's is a reviewer inventing a behaviour.
Announce: "Reviewing the delivery: gates first, then the panel."
The one rule everything else serves: a claim about what the code does at runtime is not a finding until a command, a test, a compiler, or a named call site says so. Reading the changed lines is a lead. The gates have already run by the time any reviewer thinks; their output is in context and outranks any reading.
Hard rules
- Gates before agents. No reviewer is dispatched until the project's
verification gates have been discovered, run, and recorded. A required gate
that fails because of this change is a BLOCKER reported before dispatch, with
the real output quoted. See
references/gates.md. - Attribute before reporting. A gate that was already red on the base commit is a verification limitation, not a finding against this change. Prove it with a detached worktree at the base commit, never by stashing.
- Read-only against git, except the review log. Never stash, never commit,
never push, never switch branch, never
git add. The working tree may hold another session's uncommitted work, and a bare stash captures all of it. - Only you write, apart from confirmed fix agents. Reviewers return text.
Background subagents do keep
EditandWrite, so this is a deliberate rule and not a tool limitation: several agents editing one file concurrently corrupt it, and every finding must survive the Step 5 rejection pass before anything lands. Fix agents run only after the user has confirmed a numbered list. - Plan compliance is not correctness. A faithful implementation of a wrong plan scores full compliance. Step 2 caps the verdict when the plan was never independently reviewed.
- Missing evidence is a coverage limitation, not a defect. A reviewer that crashed, a gate that cannot run, a command that failed: report reduced confidence. Never convert a tool failure into a finding against the change.
- Returning PASS is a real result. Do not manufacture findings to justify having run. A clean change with green gates returns PASS, lists the commands and their output, and stops.
Step 0. Scope: the change, the plan, the scratch directory
Create a scratch directory for this run inside your session scratchpad. Every gate transcript and prompt file written by this skill goes there, never into the repository.
Find the plan
The document this delivery is measured against may be a plan (ordered tasks, a sequence someone executed) or a spec (goal, decisions, artifacts, surfaces, verification, no ordering). Either works: both state what was supposed to be true when this was done, which is the only property this review needs. Record which you got. Throughout the rest of this skill, the plan means whichever it was.
- If the user gives a file path, read the document from that file. Record the path; Step 2 needs it.
- Otherwise look in the conversation for an explicit plan or spec: structured, with numbered steps, task lists, stated decisions, or a heading that labels it as one. Do not treat casual conversation, commit messages, or ad-hoc instructions as the plan.
- If none is found, ask: "Which plan or spec should I check this implementation against? Paste it or give me a file path." Do not guess and do not infer one from context. A review against an imagined plan reports compliance with nothing.
- If the user declines to supply one, you may proceed without the plan
compliance perspective, and the verdict is capped at
CONCERNS. Say so in the report. Never silently substitute the diff's own intent for a plan.
Find the change
In order:
User-specified files, commit, or range: use exactly that.
Git repository: run
git log --oneline -10for recent history, then pick one scope and record which:Scope How you get it Uncommitted work git diff,git diff --cached, and every path fromgit ls-files --others --exclude-standardread in fullBranch versus base git diff <base>...HEADOne commit git show <sha>A newly created file that was never
git added has no diff:git diffandgit diff --cachedboth return nothing for it. Miss the untracked union and the panel reviews the change with a whole new file invisible, while every reviewer reports confidently on what it could see. Union it in every time the scope is uncommitted.Detect the base branch with
git rev-parse --abbrev-ref --symbolic-full-name @{u}. If that fails, trygit remote show origin | grep 'HEAD branch', then check whetherorigin/mainororigin/masterexists. If none work, ask.No git repository: ask the user for the list of files to review.
Edge cases, handled before anything else runs
Empty diff: "No changes detected, nothing to review." Stop.
More than 30 files changed: "This touches [N] files. To give a thorough review, can you narrow the scope? For example: specific directories, a commit range, or the most critical files." If the user declines, proceed with the first 30 files of the change, and record the truncation in the Scope section of the report. Never truncate silently.
Derive the list from the scope you recorded, the same way the attribution pre-check in
references/gates.mddoes:# uncommitted { git diff --name-only; git diff --cached --name-only; \ git ls-files --others --exclude-standard; } | sort -u | head -30 # branch versus base git diff --name-only <base>...HEAD | head -30 # one commit git diff --name-only <sha>^..<sha> | head -30Do not reach for
git log --name-onlyhere. That is repo-wide commit history, not this change: it can list files the change never touched, and it can never list an untracked file, so on an uncommitted scope it may share nothing at all with the set under review. The report would then say "30 of N files reviewed" while naming 30 unrelated files, which is worse than truncating, because it reads as coverage.Fewer than 5 lines changed in a single file: skip the panel. Run the gates anyway, because they are the point, then run one comprehensive reviewer using the single-agent template in
references/agent-prompts.md, then report.
Gather context once, for everyone
- The full diff.
- Full contents of changed files, not just diffs, for files with more than 20 changed lines or files directly implementing a plan item. Diff only for the rest. If the total would exceed roughly 50KB, prioritise plan-critical files and record which were truncated.
- The applicable
CLAUDE.md, root and nested, for every directory the change touches. Reviewers judge against these, not generic best practice.
Step 1. Run the gates
Do this before any reviewer is dispatched, and give the result to all of them.
Read references/gates.md and follow it: discover the gates in the documented
order, classify each required or advisory, run them, build the ledger, and
attribute every failure against the base commit before calling it a finding.
Two outcomes short-circuit the rest of the run:
- A required gate is red and was green at base. Report it as a BLOCKER now, quoting the real output, before dispatching anything. Reviewing code that does not compile wastes the panel and produces findings about a state nobody will ship. Ask whether to continue the review anyway; default to stopping.
- A required gate cannot run. Verdict
BLOCKED, reported as a coverage gap. Name what would unblock it.
Otherwise carry the ledger forward. It is the first thing pasted into every prompt in Steps 4 and 5.
Step 2. Plan compliance is not correctness
The plan compliance check silently inherits the plan's own correctness. If the plan was wrong, a faithful implementation of it scores full compliance and the output reads as assurance. The better the implementation, the more confident the wrong answer.
So before trusting compliance as a signal, find out whether the plan itself was ever reviewed.
If Step 0 found no plan at all, skip this step. There is no log to look for, and the cap Step 0 already applied stands unchanged. The rest of this step presumes a plan path exists.
Look for the review log written by /check-plan:
PLAN=<the plan path from Step 0>
LOG="$(dirname "$PLAN")/reviews/$(basename "$PLAN" .md)-review.md"
ls -la "$LOG" 2>/dev/null || echo "no review log: plan was never independently reviewed"
If the log exists, read it and carry it forward:
- Record the latest round's verdict. A plan that ended
BLOCKEDorREVISEwithout a later clean round is itself a finding here, at MAJOR or worse: the implementation was built from a document known to be defective. Naming the severity matters, because Step 6'sCONCERNSrow fires on any surviving MAJOR. Without it, a plan reviewed and found defective would carry no cap at all while a plan never reviewed carries one, and the worse state would return the more reassuring verdict. - Extract the log's Out of scope and any residual risk the review explicitly accepted. Those must not be re-reported as new defects by this run. Paste that list into every panel prompt under "already accepted, do not re-report".
- Extract the log's Coverage limitations. Anything the plan review could not verify is a place to look harder now that the code exists.
If the log does not exist, say so in the report, in these terms: "The plan
was never independently reviewed, so compliance with it is not evidence of
correctness." Then cap the verdict: an unreviewed plan can never yield PASS,
only CONCERNS at best, with the missing plan review named as the reason.
The cap is not a criticism of the implementation. It is an honest statement of
what this run can and cannot establish, and the remedy is one command:
/check-plan on the plan.
Step 3. Classify
- Risk class. High if the change touches money, auth, authorization, destructive operations, data migration, public APIs, concurrency, or an irreversible rollout. Otherwise medium, or low when local and reversible.
- High-risk surfaces touched. List them explicitly by file, from the risk classes above as they appear in this repository. A change to any of them makes the risk class high and puts the matching perspective in the panel, adversarial.
- Change kind. Code, configuration, infrastructure, documentation, copy. A documentation-only change drops the test coverage and performance perspectives rather than running them to produce a wall of "not applicable".
Risk class sets panel size and how many perspectives run adversarially. Both are
in references/agent-prompts.md.
Step 4. Dispatch the panel
Read references/agent-prompts.md. Pick perspectives from the menu for coverage
of what the change actually touches, assign each collaborative or adversarial
mode, and launch them in parallel in a single message.
Every agent gets, pasted in full and never referenced:
- The plan text, or an explicit statement that there is no plan.
- The full diff.
- Full contents of the key changed files.
- The gate ledger and the quoted output of every non-zero gate. This is what makes the evidence rule cheap to obey rather than aspirational.
- The applicable
CLAUDE.mdexcerpts. - The accepted residual risks from Step 2, or the note that there was no review log.
- Its mandate, its evidence rules, the scope rule, and the severity scale.
A subagent has none of your context. A reference to "the change" is a reference to nothing.
Step 5. Synthesize
Collect the panel, then work in this order. The order matters: rejection happens before deduplication so noise cannot survive by being reported twice.
1. Reject on scope. Accept a finding only when the evidence shows one of:
- the diff introduced it;
- the diff made it reachable or materially worse;
- it violates an acceptance criterion of the plan on a path this change touches;
- it is a required-gate failure caused by this change, per the attribution in the ledger.
Everything else is a limitation or an out-of-scope observation. It goes in the report under Out of scope and is never turned into recommended work and never handed to a fix agent. Reading unchanged code to prove an affected path was permitted; the unrelated defects noticed on the way did not thereby come into scope.
The per-agent guards are instincts. This is the enforcement, and it is the only place in the run that can tell whether "only flag issues in the changed code" was actually obeyed. Check it, do not assume it.
2. Reject on quality. Drop findings that are unsupported, that state taste as fact or style as requirement, that recite generic best practice with no demonstrated connection to this change, or that justify architecture by hypothetical future scale.
3. Check the evidence. Every surviving finding must name one of the five
evidence kinds and carry the thing itself: a command with its real output, a
named test and its assertion, compiler output, a file:line call site, or for
plan_text the quoted plan sentence plus the file:line that contradicts it.
The evidence must actually support the claim, not merely sit next to it. A
confident sentence is not evidence.
A behavioural claim resting only on a reading of the changed lines is capped at MAJOR. Do not promote it because it sounds serious; if it is serious it is worth one command to prove, and you can run that command now.
The cap is on behavioural claims only. A plan_text finding asserts nothing
about runtime, so it is not capped: a missing or half-done plan item can be a
BLOCKER on its own. Check the reverse abuse too, which is the likelier one: a
finding tagged plan_text whose text actually claims what the code will do when
it runs is a behavioural claim wearing the wrong label. Retag it, and if it then
has no command, test, compiler line or call site behind it, cap it at MAJOR.
4. Deduplicate. Same location and same nature of problem merge into one finding, keeping the strongest evidence and the highest severity. Do not merge two different problems that share a line: a naming issue and an authorization hole at the same line are two findings. Preserve genuine disagreements between reviewers rather than averaging them, and say so explicitly.
5. Preserve disagreement. Where two reviewers reached opposite conclusions on the same line, that disagreement is the most valuable signal in the run. Resolve it with evidence: run the thing that decides it. Say which way you resolved it and why. Never average two positions into a hedge, and never report the disagreement as if it had not happened.
6. Classify. BLOCKER, MAJOR or MINOR, per references/agent-prompts.md. The
same scale /check-plan uses, so a plan and its delivery speak one language.
Step 6. Verdict
| Verdict | When |
|---|---|
PASS |
Nothing survived above MINOR, every required gate is green and attributed, and the plan carried a clean /check-plan review. Report the commands and their output, list what was verified, and stop. |
CONCERNS |
At least one MAJOR survived, or a required gate could not be fully attributed, or the plan was never independently reviewed. Safe to release with named residual risk. Name the reason. |
FAIL |
Any surviving BLOCKER, including a required gate that this change turned red. |
BLOCKED |
A prerequisite is missing: a required gate cannot run, the environment is unavailable, or the change could not be reviewed at all. Reported as a coverage gap, never as a product defect. |
Precedence, because more than one row can be true at once. Take the most
severe that applies, in this order: BLOCKED, then FAIL, then CONCERNS,
then PASS. Without this the common case is ambiguous: a run with one surviving
MAJOR, green gates and a clean plan review satisfies the wording of both PASS
and CONCERNS, and two coordinators would report different verdicts for the
same evidence. A MINOR alone does not cost a PASS; a MAJOR does, because MAJOR
means someone must fix it before the next change touches that area.
BLOCKED and FAIL can also both apply, when one required gate turned red and
a different one could not run. BLOCKED wins: it says the review could not
establish what it set out to establish, which is a different message to the
reader than a defect that was found.
The no-plan case belongs to Step 0 and is not a BLOCKED trigger. If the user
was asked for a plan and declined, Step 0 already proceeds without the plan
compliance perspective and caps the verdict at CONCERNS. Only a change that
could not be reviewed at all reaches BLOCKED on that axis.
Two caps apply after the table, and both are honesty about what this run can establish rather than criticism of the code:
- No plan review log: the verdict cannot be
PASS.CONCERNSat best, with "the plan was never independently reviewed" named as the reason and/check-plannamed as the remedy. - No plan at all: the verdict cannot be
PASS, and the plan compliance perspective was not dispatched. Say both.
BLOCKED outranks the caps, consistent with the precedence order above: a gate
that cannot run is reported as BLOCKED rather than as CONCERNS, because the
two call for different actions.
Step 7. Fix, only after confirmation
Ask: "Want me to fix the BLOCKER findings?"
If yes:
- Present a numbered list of proposed fixes, each naming the file, the change, and the finding it closes. Nothing from Out of scope appears in this list, ever. A finding rejected at Step 5 does not come back as a fix because it was easy.
- Ask which to apply: all, specific numbers, or none. Wait for the answer.
- Only then dispatch one fix agent per approved fix, or per group of genuinely related fixes. Each gets the specific finding, the file contents, the exact change, and an instruction to make only that change and nothing else.
- Re-run the affected gates after the fixes land and report the new exit status. A fix that turns a gate red is worse than the finding it closed.
Do not dispatch fix agents without explicit approval. Code changes are harder to
reverse than document changes, and the confirmation gate is the safety mechanism
here, not tool restriction: background subagents do keep Edit and Write.
Never git add, never commit, never push. Leave the fixes in the working tree
for the user to stage, because the tree may hold another session's work and
staging by path can sweep it in.
Step 8. Log and report
Log. Append this round to
<plan-dir>/reviews/<plan-basename>-delivery-review.md, creating it if absent.
That is a sibling of /check-plan's <plan-basename>-review.md in the same
directory, so a plan accumulates its pre-build and post-build reviews side by
side. Rounds are separated by --- and appended at the end, never rewritten. If
there was no plan file, skip the log and say so.
---
## Delivery round {N} - {YYYY-MM-DD}
**Verdict:** {PASS | CONCERNS | FAIL | BLOCKED}
**Scope:** {uncommitted | base <branch> | commit <sha>}, {N} files
**Plan review:** {verdict from the /check-plan log, or "none, verdict capped"}
**Panel:** {perspectives, mode each}
### Gates
| Gate | Command | Source | Exit | Attribution | Limitation |
|---|---|---|---|---|---|
### Previous round tracking (round 2+)
| # | Finding | Status | Notes |
|---|---|---|---|
### Findings
#### [BLOCKER|MAJOR|MINOR] {title}
- Location, Evidence kind, Evidence, Introduced by, Impact, Required change
### Verified
{claims checked and found correct, naming what was run}
### Out of scope
{adjacent problems deliberately not made findings}
### Coverage limitations
{what could not be verified, and why}
On round two or later, read the existing log first and track what the previous round found: fixed, still open, or rejected with a reason. Paste that tracking table into every panel prompt, so reviewers spend the round on what actually moved instead of re-deriving the last round's findings and reporting them again as new.
Report. Briefly, in this order: the verdict; the gates and their exit status; the findings, most severe first, each with its evidence; where reviewers disagreed and how you resolved it; what was verified; what remains unverified; what was out of scope. Then the log path.
A PASS report is short and lists the commands that were run. That is the point
of running them.
What this is not
- Not
/code-review. That answers "is this code good"; this answers "does this delivery match its plan and is it safe to release". They overlap and do not replace each other. - Not
/security-review. A security perspective is in the menu, but a dedicated security review goes deeper than one panel seat. - Not a linter. The project's linter is one of the gates, and its real output is evidence here. Do not reimplement its judgments.
- Not browser QA. When a finding turns on what a page actually does in a browser, drive the browser or delegate to whatever skill this project uses for that, and cite what it returned. Do not reason about the DOM from the diff.
- Not a replacement for the plan review.
/check-planchecks whether the plan was right. This checks whether the code matches it. Compliance with an unreviewed plan is not correctness, which is why Step 6 caps the verdict.
Credits
The delivery half of a pair with /check-plan, written by the same method: keep
a working tool's architecture, graft another skill's evidence discipline onto it.
Adapted from recheck in the claude-replan
plugin (v1.1.0) by Jiri George Dolejs, MIT + Commons Clause. It was already
stronger than its sibling replan in several places, and those were kept
deliberately rather than rewritten: file:line demanded in every output format,
the per-agent anti-inflation guards, the three edge cases (empty diff stops, over
30 files asks the user to narrow and documents any truncation, under 5 lines
collapses to one reviewer), the deduplication rules including not merging two
different problems that share a line, fix application gated behind a numbered
list the user confirms, and the refusal to infer a plan from casual conversation
or commit messages. The text here has since been rewritten end to end; nothing
upstream loads at runtime.
Evidence discipline came from reading ln-12-delivery-reviewer in
levnikolaevich/claude-code-skills
(plugins/review-suite), never installed: gates before agents with its discovery
order, and the evidence hierarchy that ranks a reproduced run above any reading.
From neither source: Step 2, plan compliance is not correctness plus the
review-log handshake with /check-plan, which is what makes the two a pair
rather than two skills that ship together; the pre-deduplication rejection pass;
and the four verdicts. Attributing a failing gate against a detached worktree at
the base commit, never a stash, is there because the working tree may hold
another session's uncommitted work. The fifth evidence kind, plan_text, was
added after a smoke test showed the original four capped every plan-compliance
finding below blocking level, which left the primary perspective unable to block
anything.
2026-07-31: two things came out. An independent cross-model reviewer tier ran
Codex against the repository on an OpenRouter pin, with a same-model subagent as
fallback; it made the codex CLI, an OpenRouter account and a funded key
prerequisites for a clean run, and degraded quietly when any was missing. And a
four-level P0-P3 severity scale, whose top rung was defined against payment
surfaces enumerated in a project-scoped skill - meaningless in any other
repository. Severity is now BLOCKER / MAJOR / MINOR, the same scale /check-plan
uses.