PR Review Toolkit
Augments the external pr-review-toolkit plugin with scope-drift detection (compare stated intent to actual diff) and a Fix-First output format (AUTO-FIXED vs NEEDS INPUT). Ported from garrytan/gstack review skill.
Tags
README
pr-review-toolkit
Augments the external pr-review-toolkit plugin (from claude-plugins-official) with two capabilities ported from garrytan/gstack's review skill:
- Scope-drift detection - before code-quality review, compare stated intent against the actual diff. Classify every plan item as DONE / PARTIAL / NOT DONE / CHANGED. Flag out-of-scope changes. Gate only on HIGH-impact findings.
- Fix-First output format - split review findings into two buckets.
AUTO-FIXEDfindings are applied by the reviewer and reported.NEEDS INPUTfindings are batched into a single user question. No more 30-item nit checklists.
These run alongside the external plugin's specialist agents (code-reviewer, silent-failure-hunter, pr-test-analyzer, type-design-analyzer, comment-analyzer, code-simplifier). Scope-drift runs first; Fix-First governs the output of the specialists and the final summary.
What It Does
skills/scope-drift/SKILL.md
A playbook the agent follows at the start of any PR review:
- Pull intent from PR body, closed issue, commit messages, and any plan file in the repo
- Extract up to 50 actionable items
- Walk the diff and classify each item against the code that actually shipped
- Walk the diff in reverse to flag changes that map to no stated item
- Rate impact HIGH / MEDIUM / LOW
- Gate only on HIGH items via a single
AskUserQuestion - Emit a
plan-delivery-gaplearning line for HIGH findings
rules/fix-first-review.md
A global review format rule:
- Every finding is either
AUTO-FIXED(mechanical, applied immediately) orNEEDS INPUT(taste, batched) - Fix-First heuristic: five one-line checks that decide the bucket
- Severity is not a bucket (it belongs inside each bucket)
- Explicit opt-out conditions (architectural review, no-edit-access reviews)
Manual Installation
# Skill
mkdir -p ~/.claude/skills/scope-drift
cp skills/scope-drift/SKILL.md ~/.claude/skills/scope-drift/SKILL.md
# Rule
mkdir -p ~/.claude/rules
cp rules/fix-first-review.md ~/.claude/rules/fix-first-review.md
Files
| File | Target | Description |
|---|---|---|
skills/scope-drift/SKILL.md |
~/.claude/skills/scope-drift/SKILL.md |
Intent-versus-diff audit skill |
rules/fix-first-review.md |
~/.claude/rules/fix-first-review.md |
Two-bucket output format rule |
Relationship to the External Plugin
The external pr-review-toolkit@claude-plugins-official plugin provides the /pr-review-toolkit:review-pr command and six specialist agents. This CCGM module does not replace it; it installs additional guidance that the agent reads at session start (the rule) or invokes on demand (the skill).
When running /pr-review-toolkit:review-pr, the agent should:
- Invoke the
scope-driftskill first - Run the external plugin's specialists
- Format the combined output per
fix-first-review.md
Source
Copycat port of items 5 and 6 from ~/code/plans/ccgm-copycat-analysis/gstack.md. Issue #293.
Will install
| Path | Action | Target | Type |
|---|---|---|---|
skills/scope-drift/SKILL.md | → | skills/scope-drift/SKILL.md | skill |
rules/fix-first-review.md | → | rules/fix-first-review.md | rule |
Dependencies
No dependencies.
Required by
Included in presets
Install this module
Agent prompt
Recommended for agent users -- hands the whole install off to your assistant.
Fetch https://cd23a9be.ccgm-site.pages.dev/modules/pr-review-toolkit.md and install this module into my Claude Code setup.
Native plugin marketplace
One command via the native plugin marketplace -- additive, does not merge settings.json.
claude plugin install pr-review-toolkit@ccgm
The marketplace path is additive, not a replacement: it installs commands, agents, and skills as native plugin components, but it does not perform the bash installer's deep settings.json merge, and it does not write the always-loaded global CLAUDE.md context. Rules are only injected via an opt-in SessionStart hook rather than being auto-loaded. Use the bash installer when those pieces matter to you.
Files
rule (1)
rules/fix-first-review.md
# Fix-First Review Output
**Iron Law:** MECHANICAL FIXES ARE APPLIED BY THE REVIEWER. TASTE CALLS ARE BATCHED INTO ONE QUESTION.
Violating the letter of this rule is violating the spirit of this rule. A review that returns a checklist of 30 nits and asks the author to process each one has failed. A review that silently rewrites the intent of the code has also failed. Fix-First formalizes the line between them.
**Announce at start:** "I'm using the Fix-First review format. Mechanical findings auto-applied; taste calls batched."
## Scope
This rule governs the output format of any PR review produced by:
- The external `pr-review-toolkit` plugin's `/review-pr` command
- The `scope-drift` skill in this module
- Any CCGM command or skill that reviews a diff and proposes fixes
It does NOT govern debugging output, architecture discussions, or free-form code commentary. Those are conversations; reviews are decision support.
## The Two Buckets
Every finding lands in exactly one of two buckets.
### `**AUTO-FIXED:**` - Reviewer applied, reports what changed
Findings where:
- The fix is mechanical or obvious
- There is exactly one reasonable way to resolve it
- The change cannot plausibly break behavior
- No subjective judgment is required
Examples:
- Unused import removed
- `const` inferred where `let` had no reassignment
- Missing semicolon, trailing comma, or prettier/linter-driven formatting
- Typo in a string literal or comment
- Dead code reachable only by a branch that was already deleted
- TODO comment referring to a closed ticket
- `console.log` left behind from debugging
- `any` replaced with the obvious inferred type when the context makes it unambiguous
- Reserved-keyword identifier in a migration quoted
For each AUTO-FIXED finding, apply the edit, then record:
```
- {file}:{line} - {what was changed} - applied
```
Attach a unified diff at the bottom of the report if the auto-fix edits are numerous.
### `**NEEDS INPUT:**` - Batched into one user question
Findings where:
- Multiple valid resolutions exist
- The fix implies a product, architecture, or UX decision
- Behavior could change in a way the author did not intend
- A tradeoff (performance vs clarity, flexibility vs simplicity) is in play
- The finding is a suspicion, not a confirmed bug
Examples:
- An API contract change that affects callers
- A function longer than comfortable but with a plausible reason to stay monolithic
- A choice between two valid error-handling strategies
- A new dependency added to solve a problem that could be solved with the standard library
- A naming choice that is not wrong but is unusual for the codebase
- An apparent race condition that may or may not actually be reachable
- Missing tests for a branch where the correct assertion is unclear
Do NOT ask separate questions for each NEEDS INPUT finding. Group them into one `AskUserQuestion` call with the findings as options or numbered items.
Record each as:
```
- {file}:{line} - {finding} - {why it needs input} - {proposed direction}
```
Then issue the single batched question.
## Fix-First Heuristic
When deciding which bucket a finding lands in, run this check:
1. **Can I state the fix in one unambiguous sentence?** If no, NEEDS INPUT.
2. **Does the fix change observable behavior?** If yes, NEEDS INPUT.
3. **Would two competent engineers write the same fix?** If no, NEEDS INPUT.
4. **Is the fix larger than ~5 lines?** If yes, lean NEEDS INPUT (show the diff, let the author decide).
5. **Does the codebase have an established pattern for this case?** If yes, AUTO-FIX to match. If no, NEEDS INPUT.
When in doubt, NEEDS INPUT. A surprise auto-fix is more costly than one extra question.
## Output Template
Every review that uses this format produces output shaped like:
```markdown
## Review Summary
**Scope**: {scope-drift verdict from scope-drift skill, if used}
**Specialists run**: {code-reviewer, silent-failure-hunter, ...}
### AUTO-FIXED ({count})
- {file}:{line} - {change} - applied
- {file}:{line} - {change} - applied
- ...
### NEEDS INPUT ({count})
Batched question follows. Please answer once:
1. {file}:{line} - {finding} - {proposed direction}
2. {file}:{line} - {finding} - {proposed direction}
3. ...
### Strengths (optional)
- {what is well done in this PR}
### Next Step
{If AUTO-FIXED count > 0: "Review the applied edits in the attached diff."}
{If NEEDS INPUT count > 0: "Answer the batched question to proceed."}
{If both are zero: "No changes requested. Ready to merge."}
```
## Severity Is Not a Bucket
Do NOT split the output into Critical / Important / Suggestion tiers the way the external `pr-review-toolkit` default prompt does. Severity belongs inside each bucket:
- An AUTO-FIXED finding can be critical (e.g., a reserved keyword causing a migration failure) or cosmetic (trailing whitespace). Either way, reviewer applies it.
- A NEEDS INPUT finding can be critical (e.g., potential race) or cosmetic (naming preference). Either way, reviewer asks.
The bucket is about who acts; severity is about how much it matters. Keep them orthogonal and you get concise, actionable reviews.
## When Fix-First Does Not Apply
- Initial architectural review where no code exists yet (all findings are NEEDS INPUT by construction).
- Reviews of work the reviewer did not write and does not have edit access to.
- Reviews where the author explicitly said "just comment, do not edit."
In those cases, state upfront that Fix-First is suspended and fall back to the plugin's default format.
## Source
Adapted from garrytan/gstack's `review/checklist.md` Fix-First Heuristic.
skill (1)
skills/scope-drift/SKILL.md
---
name: scope-drift
description: Before reviewing code quality, compare stated intent (PR body, commit messages, TODOs, plan files) against the actual diff. Classify every plan item as DONE / PARTIAL / NOT DONE / CHANGED and flag out-of-scope changes. Use at the start of any PR review or before claiming a task complete.
disable-model-invocation: false
---
# Scope Drift Detection
An intent-versus-diff audit that runs **before** code-quality review. Answers one question: did this change do what it said it would do, and only that?
Scope drift is the primary failure mode for multi-agent workflows. Agents routinely "while I was in there" into adjacent files, silently defer stated requirements, or reshape the plan without surfacing the change. This skill makes that observable.
## When to Run
- At the start of any PR review, before running specialist agents
- Before claiming a task is DONE
- When a diff feels larger than the task description suggests
- When multiple plan items were in flight and you want to confirm which actually shipped
Skip only when the change is a trivial single-line fix with no plan file or PR body.
## Inputs
Collect every available statement of intent. Use whichever sources exist:
1. **PR body** - `gh pr view --json body,title` for title and description
2. **Issue body** - `gh issue view {num}` for any issue the PR closes
3. **Commit messages** - `git log origin/main..HEAD --pretty=format:"%s%n%b"`
4. **Plan file** - any `plans/**/plan.md`, `TODOS.md`, `TODO.md`, `ROADMAP.md`, or similar referenced in the PR or living in the repo root
5. **Task description** - whatever the user or parent agent handed to this agent
If none exist, state that explicitly and proceed with a one-line reconstructed intent based on the first commit message.
## Extraction: Actionable Items
From the combined intent sources, extract up to **50** actionable items. An actionable item is one the PR either must do or must not do.
Look for:
- Markdown checkboxes (`- [ ]` or `- [x]`)
- Numbered steps in plan files
- Imperative sentences in the PR body ("adds X", "removes Y", "renames Z")
- Explicit acceptance criteria sections
- Items in a "Scope" or "Deliverables" list
- Issue titles and labels that imply a verb-object pair
Normalize each to a single short line, for example:
- `Add scope-drift skill to pr-review-toolkit`
- `Update module.json with new file entries`
- `Do NOT touch other modules`
- `Keep edits minimal`
If the combined intent produces more than 50 items, note the count and work with the top 50 by apparent priority (explicit scope > deliverables > nice-to-haves).
## Classification
For each actionable item, classify against the actual diff. Use `git diff origin/main...HEAD --stat` and `git diff origin/main...HEAD` on relevant files.
| Status | Meaning |
|--------|---------|
| **DONE** | Item is fully implemented in the diff, with evidence (file, approximate line) |
| **PARTIAL** | Item is started but not complete. Name what is missing. |
| **NOT DONE** | Item is absent from the diff entirely |
| **CHANGED** | Item's implementation diverged from its description. Name what changed. |
Record evidence as `path/to/file.ext:line` pointers so the next reviewer can verify without re-running the diff.
## Out-of-Scope Changes
Walk the diff in the opposite direction: every changed file that does NOT map to an actionable item is a scope drift candidate.
For each candidate, decide:
- **Justified** - Small, mechanical, obviously required by a stated item (e.g., import reorder, generated file, formatting that the linter enforces). Record and move on.
- **Drift** - Not implied by any stated item. Flag it. Include the file, the nature of the change in one line, and why it seems unrelated.
Do NOT remove drift changes automatically. The author may have a reason. Surface them for a decision.
## Impact Rating
Rate every PARTIAL, NOT DONE, CHANGED, and DRIFT finding as HIGH / MEDIUM / LOW impact.
- **HIGH** - Would change review outcome, risk merging wrong code, or miss a hard requirement (security, migration, API contract, stated "must have")
- **MEDIUM** - Worth raising but merge can proceed with acknowledgement
- **LOW** - Informational; author may choose to defer
## Output Format
Produce one section at the top of the review report:
```markdown
## Scope Drift Audit
**Intent sources**: {PR body | issue #N | commit messages | plans/foo/plan.md}
**Items extracted**: {count}
### Plan Completion
- [DONE] {item} - {evidence: path:line}
- [PARTIAL] {item} - {what is missing} - {path:line}
- [NOT DONE] {item} - {impact: HIGH/MED/LOW}
- [CHANGED] {item} - {what diverged} - {path:line}
### Out-of-Scope Changes
- [DRIFT, HIGH] {file} - {one-line description of change} - {why it appears unrelated}
- [DRIFT, LOW] {file} - {one-line description} - {likely benign reason}
### Verdict
- In scope: {count} items DONE + {count} justified supporting changes
- Gaps: {count} PARTIAL + {count} NOT DONE
- Drift: {count} HIGH + {count} LOW
```
## Gating
Gate the review only on HIGH-impact findings. For each HIGH gap or drift, issue a single `AskUserQuestion` (batched) before continuing to code-quality review. Present options:
- Accept the gap / drift and continue
- Block the review until the item is addressed
- Mark the plan item as explicitly descoped (update PR body)
LOW and MEDIUM findings are informational. Record them in the report and proceed.
## Learning Log
For every HIGH-impact gap or drift, emit a one-line learning entry that a future reviewer can use:
```
plan-delivery-gap: {repo}#{pr} - {item or drift} - {cause hypothesis}
```
Example causes: "agent lost track after rebase", "scope unclear from PR body", "added dependency without explicit approval".
These feed the self-improving loop. The CCGM `self-improving` module's MEMORY files are the current store.
## Integration With Existing Review
Scope-drift runs **before** the existing specialist agents (`code-reviewer`, `silent-failure-hunter`, etc.) from the external `pr-review-toolkit` plugin. Its output is a prerequisite, not a replacement.
Flow:
1. Run scope-drift audit.
2. If any HIGH gating question is answered "block", stop and surface to user.
3. Otherwise proceed to specialist reviews with the audit attached as context.
4. Final review report starts with the Scope Drift Audit section, then the specialist findings in Fix-First format (see `rules/fix-first-review.md`).
## Anti-Patterns
- Running code-quality review first and adding scope-drift as an afterthought. Order matters: if scope is wrong, code quality is noise.
- Auto-removing drift changes. Surface, do not delete.
- Extracting fewer than 5 items from a multi-file PR. Usually means the intent sources were not read carefully enough.
- Treating every formatting nit as drift. Mechanical and generated changes are justified.
- Gating on LOW findings. That defeats the purpose.
## Source
Ported from the Scope Drift + Plan Completion Audit section of garrytan/gstack's `review/SKILL.md`. Adapted to CCGM voice and the external `pr-review-toolkit` plugin's agent-based review flow.