| name | speckit-review-pr |
| description | Post a PR review with inline comments for findings requiring human judgment — one-way doors, concurrency risks, architectural decisions, and project-specific patterns. |
User Input
$ARGUMENTS
You MUST consider the user input before proceeding (if not empty).
Modes
- Post mode (default) — analyze the diff, post findings as a GitHub PR review with inline comments.
- Dry-run mode — if
$ARGUMENTS contains --dry-run, analyze and print findings to terminal without posting to GitHub.
Pre-Flight: Pack Engine Check
Step 4 delegates to the shared pack-execution engine installed with the speckit-review skill:
if test -f ".claude/skills/speckit-review/reference/pack-execution.md"; then echo "pack-execution: EXISTS"; else echo "pack-execution: MISSING"; fi
If MISSING, display this error and STOP:
ERROR: Required pack-execution engine not found.
Missing: .claude/skills/speckit-review/reference/pack-execution.md
/speckit-review-pr runs review packs via the engine shipped with the
speckit-review skill. Install both skills together (run setup.sh), then re-run.
Step 1: Resolve PR
Determine the PR to review:
- If
$ARGUMENTS contains pr:<number> or a GitHub PR URL (https://github.com/.../pull/<number>), extract the PR number.
- Otherwise, auto-detect from the current branch:
gh pr view --json number,url,headRefName,baseRefName,headRefOid,state 2>/dev/null
- If no open PR is found, abort: "No open PR found for the current branch. Push the branch and open a PR first, or pass
pr:<number> explicitly."
- If the PR state is not
OPEN, abort: "PR # is . Can only review open PRs."
Capture: PR_NUMBER, PR_URL, HEAD_SHA, BASE_REF.
Also resolve the repo identifier:
gh repo view --json nameWithOwner --jq '.nameWithOwner'
Step 2: Fetch the diff
Fetch the PR diff (this is the FINAL state post-Marge — things already fixed won't appear):
gh pr diff $PR_NUMBER
And the file list:
gh pr diff $PR_NUMBER --name-only
If the diff is empty, abort: "PR #$PR_NUMBER has no changes. Nothing to review."
Step 3: Load context sources
Read the following files if they exist:
.specify/memory/constitution.md — project principles
CLAUDE.md at repo root — project guidelines
Step 4: Run the pack engine (human-judgment lens)
Read and follow .claude/skills/speckit-review/reference/pack-execution.md — the shared engine that discovers packs, runs them sequentially with corroborate/refute, runs script packs, and aggregates. Provide it:
- DIFF / FILE_LIST: the PR diff and file list from Step 2
- PER_PACK_INSTRUCTION: the blockquote below — it restricts every pack to human-judgment findings
- RUNNER_ENV:
SPECKIT_STAGE=review SPECKIT_REPO_ROOT="$(pwd)" SPECKIT_BASE_REF="<base ref>" SPECKIT_DIFF_FILES="$(gh pr diff <number> --name-only)" — substitute the LITERAL base ref and PR number captured in Step 1 (each Bash call is a fresh shell; $BASE_REF/$PR_NUMBER are not set there). The PR diff comes from gh, not local git, so the changed files are passed explicitly. Before running the engine's script-pack step, verify the substituted gh pr diff <number> --name-only output is non-empty — if it fails or is empty, abort rather than letting script packs silently pass on an empty file list.
- CONFIDENCE_RULE: drop findings with
confidence < 70
You are analyzing for findings that require HUMAN JUDGMENT. Mechanical issues (style, linting, common bugs with obvious fixes) are handled by Marge's auto-fix loop and MUST NOT be flagged. Focus exclusively on:
- One-way doors — irreversible changes (schema destruction, API breaks, permission changes, data deletion)
- Race conditions / concurrency — shared mutable state, TOCTOU, missing transactions, non-atomic operations
- Architectural decisions — new coupling, layer violations, abstraction boundary changes, dependency direction
- Project-specific patterns — violations of constitution or CLAUDE.md principles that require judgment (not mechanical fixes)
- Project continuity rules — findings from project packs (anything under
project/), tagged PROJECT_GATE (e.g. sibling-file sync). ALWAYS flag these, even if mechanical — they encode repo-specific continuity an out-of-band reviewer cannot otherwise see.
For packs that contain both mechanical and judgment rules, ONLY flag findings tagged NEEDS_HUMAN in the pack's rule definitions — EXCEPT PROJECT_GATE findings, which are always flagged. Skip all others.
Step 5: Map to PR severity
Map the pack-native severity to the three-tier PR comment scheme:
| Pack severity | PR comment severity | Condition |
|---|
| CRITICAL | CRITICAL | Always (one-way doors, security-critical) |
| HIGH + NEEDS_HUMAN | WARNING | Concurrency, architecture, testing judgment |
| MEDIUM + NEEDS_HUMAN | WARNING | Architecture, testing judgment |
| LOW + NEEDS_HUMAN | INFO | Project pattern observations |
PROJECT_GATE (any severity) | CRITICAL→CRITICAL, HIGH/MEDIUM→WARNING, LOW→INFO | Project continuity gates — always surfaced |
| Any other finding WITHOUT NEEDS_HUMAN, not from a keep-list source | Dropped | Marge handles these |
Findings from one-way-doors.md and concurrency.md packs, and ALL findings tagged PROJECT_GATE (every project pack — prose and script), are always kept regardless of the NEEDS_HUMAN tag — they encode repo-specific continuity an out-of-band reviewer cannot otherwise see.
Step 6: Check idempotency
Before posting, check if a prior review from this command exists:
gh api "repos/$REPO/pulls/$PR_NUMBER/reviews" --jq '[.[] | select(.body | contains("<!-- speckit-review-pr -->"))] | last | .body // empty'
Parse the sentinel: <!-- speckit-review-pr sha:<SHA> -->
- If a prior review exists with the same SHA as the current
HEAD_SHA: skip posting. Print: "Review already posted for commit <short SHA>. Push new commits to trigger a fresh review." Exit.
- If a prior review exists with a different SHA: proceed to post a new review. Note in the summary that this supersedes the prior review.
- If no prior review exists: proceed to post.
Step 7: Post PR review
If --dry-run: print findings to terminal in the same format as /speckit-review's Report step and exit. Do NOT post to GitHub.
If posting: build and submit a GitHub PR review.
Construct the JSON payload
The payload must conform to the GitHub Reviews API:
{
"event": "COMMENT",
"body": "<summary with sentinel>",
"commit_id": "<HEAD_SHA>",
"comments": [
{
"path": "<file path>",
"line": <line number in the final file>,
"side": "RIGHT",
"body": "<formatted inline comment>"
}
]
}
Summary body format
<!-- speckit-review-pr sha:<HEAD_SHA> -->
## speckit review — <N> findings requiring human attention
| Severity | Count |
|----------|-------|
| CRITICAL | <n> |
| WARNING | <n> |
| INFO | <n> |
**Risk assessment:** <one sentence characterizing the overall risk level of this PR>
<If CRITICAL findings exist:>
**One-way doors detected.** This PR contains irreversible changes that should be reviewed carefully before merging.
---
*Posted by `/speckit-review-pr` — re-run after pushing new commits for a fresh review.*
Inline comment body format
**[<SEVERITY>]** <category label>
<2-4 sentence explanation of WHY human attention is needed. Reference the specific code pattern detected and explain what could go wrong.>
<If a safe fix suggestion exists:>
```suggestion
<suggested code change>
Source: pack <pack filename> rule <rule ID>
Category labels: `One-Way Door`, `Concurrency Risk`, `Architecture Decision`, `Project Pattern`, `Project Gate` (for `PROJECT_GATE` findings).
### Submit
Cap at 25 inline comments. If more than 25 findings exist, keep the top 25 by severity (CRITICAL first), then confidence within severity. Note in the summary: "Showing 25 of <N> findings. Address critical and warning findings first."
Post via:
```bash
echo '$JSON_PAYLOAD' | gh api "repos/$REPO/pulls/$PR_NUMBER/reviews" --method POST --input -
Line number mapping
The line field must reference the line number in the final version of the file (the + side of the diff, side: RIGHT). If a finding references a line that is not part of the diff (pre-existing code not touched by this PR), fall back to a file-level comment by omitting the line and side fields (GitHub posts it as a general file comment).
Step 8: Report
Print a terminal summary:
## PR Review Posted — PR #<number>
Posted <N> inline comments:
CRITICAL: <n> (one-way doors)
WARNING: <n> (concurrency: <n>, architecture: <n>)
INFO: <n> (project patterns)
Review URL: <PR URL>
If zero findings requiring human judgment were found, post a brief summary-only review (no inline comments):
<!-- speckit-review-pr sha:<HEAD_SHA> -->
## speckit review — no findings requiring human attention
All mechanical issues have been handled by Marge's auto-fix loop. No one-way doors, concurrency risks, or architectural concerns detected in this diff.
---
*Posted by `/speckit-review-pr`*
Rules
- Never edit files or commit. This command is read-only + post-comments.
- Use
event: COMMENT, not REQUEST_CHANGES or APPROVE. This is informational, not a merge gate.
- Review only lines the diff touches. Pre-existing issues are out of scope.
- Maximum 25 inline comments per review.
- If
gh CLI is not authenticated, abort early: run gh auth status at start and fail fast.
- Do not duplicate findings that Marge already fixed — the diff is post-Marge, so fixed findings are not present.
Examples
/speckit-review-pr — Auto-detect PR from current branch, post review
/speckit-review-pr pr:42 — Review PR #42
/speckit-review-pr https://github.com/org/repo/pull/42 — Review by URL
/speckit-review-pr --dry-run — Analyze and print findings without posting to GitHub
/speckit-review-pr pr:42 --dry-run — Dry-run review of PR #42