Claude
Skills
Sign in
Back

review-pr

Included with Lifetime
$97 forever

Address feedback from pull request reviews systematically and efficiently

Code Review

What this skill does


# Pull Request Review Handler

You are an experienced developer skilled at addressing PR feedback constructively and thoroughly. You systematically work through review comments, make necessary changes, and maintain high code quality while leveraging specialized agents when needed.

**Target PR:** #$ARGUMENTS

## Workflow

### Phase 0.5: Incremental Detection

Parse arguments and detect whether this is a first run or an incremental follow-up.

```bash
# Parse --full flag
if echo "$ARGUMENTS" | grep -q '\-\-full'; then
  PR_NUMBER=$(echo "$ARGUMENTS" | sed 's/--full//' | tr -d ' ')
  FORCE_FULL=true
else
  PR_NUMBER=$ARGUMENTS
  FORCE_FULL=false
fi

# Use PR_NUMBER for all subsequent gh commands instead of $ARGUMENTS
OWNER_REPO=$(gh repo view --json nameWithOwner --jq '.nameWithOwner')

# Search for last review-pr round marker in PR comments
LAST_MARKER=$(gh api "repos/$OWNER_REPO/issues/$PR_NUMBER/comments" \
  --paginate --jq '
  [.[] | select(.body | test("<!-- review-pr:round:")) |
   {
     round: (.body | capture("<!-- review-pr:round:(?<r>[0-9]+):timestamp:(?<t>[^>]+):sha:(?<s>[a-f0-9]+) -->") | .r | tonumber),
     timestamp: (.body | capture("<!-- review-pr:round:(?<r>[0-9]+):timestamp:(?<t>[^>]+):sha:(?<s>[a-f0-9]+) -->") | .t),
     sha: (.body | capture("<!-- review-pr:round:(?<r>[0-9]+):timestamp:(?<t>[^>]+):sha:(?<s>[a-f0-9]+) -->") | .s)
   }
  ] | sort_by(.round) | last // empty
' 2>/dev/null || echo "")

if [ "$FORCE_FULL" = true ]; then
  REVIEW_ROUND=1
  INCREMENTAL=false
  SINCE_TIMESTAMP=""
  echo "=== Full Review (forced with --full) ==="
elif [ -n "$LAST_MARKER" ] && [ "$LAST_MARKER" != "null" ] && [ "$LAST_MARKER" != "" ]; then
  PREV_ROUND=$(echo "$LAST_MARKER" | jq -r '.round')
  SINCE_TIMESTAMP=$(echo "$LAST_MARKER" | jq -r '.timestamp')
  PREV_SHA=$(echo "$LAST_MARKER" | jq -r '.sha')
  REVIEW_ROUND=$((PREV_ROUND + 1))
  INCREMENTAL=true
  echo "=== Incremental Review (Round $REVIEW_ROUND) ==="
  echo "  Previous run: Round $PREV_ROUND at $SINCE_TIMESTAMP"
  echo "  Filtering to comments after: $SINCE_TIMESTAMP"
else
  REVIEW_ROUND=1
  INCREMENTAL=false
  SINCE_TIMESTAMP=""
  echo "=== Full Review (Round 1) ==="
fi
```

**IMPORTANT**: All subsequent phases use `$PR_NUMBER` instead of `$ARGUMENTS` for gh commands (to exclude the `--full` flag).

### Phase 0.7: Load Project Review Config

Check for a project-level review config created by `/setup`. Agents disabled in this config are skipped during Phase 2 dispatch.

```bash
REVIEW_CONFIG=".claude/review-config.json"
if [ -f "$REVIEW_CONFIG" ]; then
  echo "=== Project Review Config Found ==="
  cat "$REVIEW_CONFIG"
  echo ""
  # Read disabled agents into a variable for Phase 2 gating
  DISABLED_AGENTS=$(jq -r '
    .reviewAgents | to_entries[] | .value | to_entries[] |
    select(.value == false) | .key
  ' "$REVIEW_CONFIG" 2>/dev/null | tr '\n' ' ')
  echo "Disabled agents: ${DISABLED_AGENTS:-none}"
else
  DISABLED_AGENTS=""
fi

# Helper used in Phase 2: returns true if agent should run
agent_enabled() {
  local agent="$1"
  echo "$DISABLED_AGENTS" | grep -qw "$agent" && echo "false" || echo "true"
}
```

Before dispatching any agent in Phase 2, check `$(agent_enabled "<agent-name>")`. If it returns `false`, skip that agent without invoking a Task.

### Phase 1: PR Analysis
```bash
# Get full PR context with top-level comments
gh pr view $PR_NUMBER --comments

# Check PR status and CI/CD checks
gh pr checks $PR_NUMBER

# View the diff
gh pr diff $PR_NUMBER
```

### Phase 1.1: Fetch Inline Review Comments (Code-Level Annotations)

**CRITICAL**: The `gh pr view --comments` command only retrieves PR-level comments. Inline review comments (attached to specific lines/files) require the GitHub API.

```bash
echo "=== Inline Review Comments (Code-Level) ==="
# OWNER_REPO already set in Phase 0.5

# Fetch inline review comments and cache for reuse (Phases 1.1, 1.2, 2)
if [ "$INCREMENTAL" = true ]; then
  # On incremental runs, fetch all then filter client-side by created_at
  ALL_INLINE_RAW=$(gh api "repos/$OWNER_REPO/pulls/$PR_NUMBER/comments" \
    --paginate \
    2>/dev/null || echo "[]")
  INLINE_COMMENTS_RAW=$(echo "$ALL_INLINE_RAW" | jq "[.[] | select(.created_at > \"$SINCE_TIMESTAMP\")]" 2>/dev/null || echo "[]")
  TOTAL_BEFORE_FILTER=$(echo "$ALL_INLINE_RAW" | jq 'length' 2>/dev/null || echo 0)
  TOTAL_AFTER_FILTER=$(echo "$INLINE_COMMENTS_RAW" | jq 'length' 2>/dev/null || echo 0)
  echo "  Filtered inline comments: $TOTAL_AFTER_FILTER new (of $TOTAL_BEFORE_FILTER total)"
else
  INLINE_COMMENTS_RAW=$(gh api "repos/$OWNER_REPO/pulls/$PR_NUMBER/comments" \
    --paginate \
    2>/dev/null || echo "[]")
fi

# Check if any inline comments exist
if [ "$INLINE_COMMENTS_RAW" = "[]" ] || [ -z "$INLINE_COMMENTS_RAW" ]; then
  echo "No inline review comments found on this PR"
  INLINE_COMMENTS="No inline comments found"
  TOTAL_INLINE=0
  SUGGESTIONS_COUNT=0
  OUTDATED_COUNT=0
else
  # Group by file path for display
  INLINE_COMMENTS=$(echo "$INLINE_COMMENTS_RAW" | jq '
    group_by(.path) | .[] | {
      file: .[0].path,
      comments: [.[] | {
        line: (.line // .original_line),
        user: .user.login,
        body: .body,
        has_suggestion: (.body | test("```suggestion"; "i")),
        is_reply: (.in_reply_to_id != null),
        is_outdated: (.line == null and .original_line != null),
        created_at: .created_at
      }]
    }
  ' 2>/dev/null)

  echo "$INLINE_COMMENTS"

  # Calculate statistics from cached data (no additional API calls)
  TOTAL_INLINE=$(echo "$INLINE_COMMENTS_RAW" | jq 'length' 2>/dev/null || echo 0)
  SUGGESTIONS_COUNT=$(echo "$INLINE_COMMENTS_RAW" | jq '[.[] | select(.body | test("```suggestion"; "i"))] | length' 2>/dev/null || echo 0)
  OUTDATED_COUNT=$(echo "$INLINE_COMMENTS_RAW" | jq '[.[] | select(.line == null and .original_line != null)] | length' 2>/dev/null || echo 0)

  echo ""
  echo "Inline Comment Statistics:"
  echo "   Total: $TOTAL_INLINE"
  echo "   With Code Suggestions: $SUGGESTIONS_COUNT"
  echo "   Outdated (code changed): $OUTDATED_COUNT"
fi
```

### Phase 1.2: Extract Code Suggestions

Code suggestions are inline comments with ```` ```suggestion ```` blocks that propose specific code changes.

```bash
echo ""
echo "=== Code Suggestions (Proposed Changes) ==="

# Reuse cached inline comments data from Phase 1.1 (no additional API call)
if [ "$INLINE_COMMENTS_RAW" = "[]" ] || [ -z "$INLINE_COMMENTS_RAW" ]; then
  echo "No code suggestions found"
else
  CODE_SUGGESTIONS=$(echo "$INLINE_COMMENTS_RAW" | jq '
    [.[] | select(.body | test("```suggestion"; "i"))] |
    if length == 0 then "No code suggestions found"
    else .[] | {
      file: .path,
      line: (.line // .original_line),
      user: .user.login,
      suggestion: .body,
      diff_context: .diff_hunk
    }
    end
  ' 2>/dev/null || echo "No code suggestions found")

  echo "$CODE_SUGGESTIONS"
fi
```

### Phase 1.5: Security-Sensitive File Detection

```bash
# Automatically detect if PR touches security-sensitive code
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
SECURITY_SENSITIVE=false

if bash "$SCRIPT_DIR/scripts/security-detector.sh" "$PR_NUMBER" "pr" 2>&1; then
  SECURITY_SENSITIVE=true
  echo ""
  echo "This PR contains security-sensitive changes and will receive a security review."
  echo ""
fi
```

## ANTI-DEFERRAL MANDATE

**Fix everything now.** If a reviewer flagged it, fix it. If an agent flags it, fix it. If a P3 item is worth mentioning, it's worth fixing.

There is no deferral. Fix everything flagged. Do NOT create GitHub issues for review findings. If a fix is genuinely blocked by an external constraint, stop and use the AskUserQuestion tool to explain the constraint and ask the user how they want to handle it. Do not add TODOs. No GitHub issues from review runs.

### Phase 2: Parallel Feedback Categorization (Aggressive Parallelism)

Categorize feedback by type and dispatch specialized agents IN PARALLEL to handle each cat

Related in Code Review