Fix PR Skill - Orchestrator
Orchestrator ONLY spawns Opus subagents and collects summaries. ALL work is delegated.
Critical Rules
- NEVER read files - subagents read files
- NEVER run commands - subagents run commands
- NEVER call gh API - subagents call gh API
- NEVER create commits - subagents create commits
- Orchestrator only: spawns agents, tracks todos, reports summaries
Git Safety Rules (CRITICAL)
This skill does NOT modify git history. Ever.
- NO
git rebase - rewrites history, causes divergence
- NO
git reset --hard - destroys uncommitted work
- NO
git push --force - overwrites remote history
- NO
git merge - user decides when to merge
git fetch - safe, read-only
git status - safe, read-only
git push - safe for new commits only (will fail if diverged)
If the branch needs to be rebased onto main, the user must do it manually BEFORE running /fix-pr.
Phase 1: Analysis Subagent
Spawn a single subagent to detect PRs and fetch/categorize comments:
Task(general-purpose, model: opus):
Analyze open PR and categorize comments.
---
## Tasks
1. **Check for open PR**:
```bash
gh pr list --head "$(git branch --show-current)" --state open --json number,title,url
-
For the PR found, fetch ALL comments with thread context:
bash
1gh api repos/{owner}/{repo}/pulls/{number}/comments --jq '.[] | {id, in_reply_to_id, path, line, body, user: .user.login}'
2gh api repos/{owner}/{repo}/pulls/{number}/reviews --jq '.[] | select(.body != "") | {user: .user.login, state, body}'
-
Build thread map: Group replies under parent comments to understand context.
-
Categorize EVERY comment:
- TO_FIX: Actionable changes (including ALL nitpicks)
- SKIP: Already resolved in thread, false positive, or owner overruled
- RESPOND: Questions that need explanation (not code changes)
- DEFER: Out of scope, requires broader refactoring → needs GitHub issue
-
Extract instructions:
- CodeRabbit (
coderabbitai[bot]): Look for <summary>Prompt for AI Agents</summary> section
- Claude Code Review (
claude[bot]): Use the full comment body as instruction
- Human reviewers: Use full comment body as instruction
yaml
1---
2PR_FOUND:
3 number: 42
4 branch: feature/xyz
5 url: [url]
6
7COMMENTS:
8 TO_FIX:
9 - id: "123456"
10 reviewer: coderabbitai[bot]
11 file: src/app/page.tsx
12 line: 45
13 instruction: "Add error handling for missing data..."
14 - id: "123457"
15 reviewer: wtrwts
16 file: src/components/Card.tsx
17 line: 80
18 instruction: "should be private"
19
20 SKIP:
21 - id: "123459"
22 reason: "Reply from owner: 'This is intentional'"
23
24 RESPOND:
25 - id: "123460"
26 reviewer: wtrwts
27 question: "Why did you choose approach A?"
28
29 DEFER:
30 - id: "123461"
31 reviewer: coderabbitai[bot]
32 reason: "Requires splitting the component - architectural change"
33 suggested_issue_title: "Refactor: Split Card component into focused components"
34
35SUMMARY:
36 total: 12
37 to_fix: 6
38 skip: 2
39 respond: 2
40 defer: 2
41---
---
## Phase 2: Create Todo List
Based on analysis results, create todo list:
```yaml
todos:
- content: "Analyze PR and categorize comments"
status: completed
- content: "Fix: error handling in page (coderabbitai)"
status: pending
- content: "Fix: make property private (wtrwts)"
status: pending
- content: "Skip: intentional pattern (reply to comment)"
status: pending
- content: "Respond: explain approach choice"
status: pending
- content: "Defer: create issue for component refactor"
status: pending
- content: "Verify builds"
status: pending
- content: "Push changes"
status: pending
Phase 3: Parallel Fix Subagents
Spawn parallel subagents for ALL TO_FIX comments in a SINGLE message:
Task(general-purpose, model: opus):
Fix PR review comment by invoking /task skill.
---
## Context
- PR: #42
- Comment ID: 123456
- Reviewer: coderabbitai[bot]
- File: src/app/page.tsx
- Line: 45
## Reviewer Instructions
[PASTE THE EXTRACTED INSTRUCTION HERE]
---
## Workflow
1. **Invoke the /task skill** to make the fix:
Skill(task)
Pass these details to /task:
- TASK: Fix the issue described in reviewer instructions above
- Commit message format:
```
fix(<scope>): <description>
Addresses PR #42 review comment:
- <reviewer>: "<brief summary>"
```
2. **After /task completes**, reply to the PR comment as a THREADED REPLY:
**CRITICAL: Use `--input -` with JSON to ensure `in_reply_to` is correctly passed as an integer. This creates a threaded reply, NOT a standalone comment.**
```bash
COMMIT_SHA=$(git rev-parse --short HEAD)
COMMENT_ID=123456 # The comment ID from analysis
# Create threaded reply using JSON input (most reliable method)
echo '{"body": "Fixed in '"$COMMIT_SHA"'", "in_reply_to": '"$COMMENT_ID"'}' | \
gh api repos/{owner}/{repo}/pulls/42/comments --method POST --input -
Verify the reply was threaded: Check the response includes "in_reply_to_id": 123456. If in_reply_to_id is null, the reply failed to thread.
yaml
1---
2STATUS: SUCCESS | FAILURE
3COMMENT_ID: "123456"
4COMMIT: abc1234
5FILES_CHANGED:
6 - [file1]
7REPLIED: true | false
8REPLY_THREADED: true | false
9ERRORS: [if FAILURE or REPLY_THREADED=false]
10---
**Spawn ALL fix subagents in parallel** (single message, multiple Task calls).
---
## Phase 4: Handle Skips, Responses, and Deferrals
Spawn a single subagent to handle non-fix items:
Task(general-purpose, model: opus):
Handle skipped comments, questions, and deferred items.
CRITICAL: Always create THREADED REPLIES using JSON input with in_reply_to as an integer.
For each skipped comment:
bash
1COMMENT_ID={comment_id} # The numeric comment ID
2
3echo '{"body": "Acknowledged - [reason from analysis]", "in_reply_to": '"$COMMENT_ID"'}' | \
4 gh api repos/{owner}/{repo}/pulls/{pr}/comments --method POST --input -
Skip reasons:
- "Already addressed in discussion above"
- "This is intentional because [reason]"
- "Keeping current approach per owner guidance"
For each question:
- Read the relevant code to understand context
- Formulate clear technical answer
- Reply as a THREADED REPLY:
bash
1COMMENT_ID={comment_id}
2
3echo '{"body": "[Technical explanation]", "in_reply_to": '"$COMMENT_ID"'}' | \
4 gh api repos/{owner}/{repo}/pulls/{pr}/comments --method POST --input -
For each deferred item:
bash
1gh issue create \
2 --title "[suggested_issue_title]" \
3 --body "## Context
4
5This issue was identified during PR #[number] review by @[reviewer].
6
7**Original comment:** [link]
8> [quote comment]
9
10## Problem
11[describe what needs to change]
12
13## Proposed Solution
14[concrete steps]
15
16## Related
17- PR #[number]
18---
19*Created from PR review comment*"
Then reply to original comment as a THREADED REPLY:
bash
1COMMENT_ID={comment_id}
2ISSUE_URL="[issue_url]"
3
4echo '{"body": "Created issue: '"$ISSUE_URL"'\n\nThis requires broader refactoring beyond this PR'\''s scope.", "in_reply_to": '"$COMMENT_ID"'}' | \
5 gh api repos/{owner}/{repo}/pulls/{pr}/comments --method POST --input -
yaml
1---
2SKIPPED:
3 - comment_id: "123458"
4 replied: true
5RESPONDED:
6 - comment_id: "123459"
7 replied: true
8DEFERRED:
9 - comment_id: "123460"
10 issue_created: "https://github.com/.../issues/99"
11 replied: true
12---
---
## Phase 5: Collect All Results
Use TaskOutput to wait for all subagents.
Aggregate:
- Fixes completed
- Commits created
- Comments replied to
- Issues created
---
## Phase 6: Verification Subagent
Spawn verification subagent:
Task(general-purpose, model: opus):
Verify all PR fixes are complete and working. DO NOT PUSH - push happens in Phase 7.
Tasks
-
Check git status:
-
Run TypeScript check:
-
Run lint:
-
Run build:
DO NOT push here. Push happens in Phase 7 after verification passes.
yaml
1---
2STATUS: VERIFIED | FAILED
3TYPESCRIPT: PASSED | FAILED
4LINT: PASSED | FAILED
5BUILD: PASSED | FAILED
6ERRORS: [if FAILED]
7---
**If verification fails, stop and report errors. Do not proceed to push.**
---
## Phase 7: Push & Re-Review Subagent
**Only run this phase if Phase 6 verification passed.**
Spawn push subagent to push all commits at once:
Task(general-purpose, model: opus):
Push all committed fixes. The push will automatically trigger new reviews from CodeRabbit and Claude via GitHub Actions.
Tasks
- Push all changes:
yaml
1---
2STATUS: PUSHED | FAILED
3ERRORS: [if FAILED]
4---
---
## Phase 8: Resolve Confirmed Threads
**Run this phase after AI reviewers have had time to re-check the fixes (typically 1-2 minutes after push).**
Spawn a subagent to find and resolve threads where the AI reviewer has confirmed the fix:
Task(general-purpose, model: opus):
Find review threads where CodeRabbit or Claude has confirmed the fix is good, and resolve those threads.
Tasks
1. Fetch all review threads for the PR using GraphQL
bash
1gh api graphql -f query='
2query {
3 repository(owner: "{owner}", name: "{repo}") {
4 pullRequest(number: {pr_number}) {
5 reviewThreads(first: 100) {
6 nodes {
7 id
8 isResolved
9 comments(last: 1) {
10 nodes {
11 author {
12 login
13 }
14 body
15 }
16 }
17 }
18 }
19 }
20 }
21}'
2. Identify threads to resolve
A thread should be resolved if ALL conditions are met:
- Thread is NOT already resolved (
isResolved: false)
- The LAST comment is from
coderabbitai[bot] OR claude[bot]
- The last comment body contains resolution indicators:
- "LGTM" (case-insensitive)
- "Looks good"
- "looks good now"
- "resolved"
- "fixed"
- "addressed"
- checkmark emoji
- "The issue has been"
- "correctly implemented"
- "properly addressed"
DO NOT resolve threads where:
- The last comment is from a human reviewer (they should resolve manually)
- The last comment contains questions or requests for further changes
- The AI reviewer is still asking for clarification
3. Resolve each confirmed thread
For each thread that should be resolved:
bash
1THREAD_ID="<thread_id_from_step_1>"
2gh api graphql -f query='
3mutation {
4 resolveReviewThread(input: {threadId: "'$THREAD_ID'"}) {
5 thread {
6 isResolved
7 }
8 }
9}'
yaml
1---
2STATUS: SUCCESS | PARTIAL | NO_THREADS
3THREADS_ANALYZED:
4 total: 15
5 already_resolved: 8
6 ai_confirmed: 5
7 human_pending: 2
8THREADS_RESOLVED:
9 - thread_id: "RT_..."
10 reviewer: coderabbitai[bot]
11 confirmation: "LGTM! The changes look good."
12 - thread_id: "RT_..."
13 reviewer: claude[bot]
14 confirmation: "Correctly implemented as suggested."
15NOT_RESOLVED:
16 - thread_id: "RT_..."
17 reason: "Last comment from human reviewer"
18 - thread_id: "RT_..."
19 reason: "AI reviewer still asking questions"
20ERRORS: [if any]
21---
**Note:** If AI reviewers haven't responded yet, this phase will find no threads to resolve. You can run `/fix-pr` again later to resolve threads once AI reviews complete.
---
## Phase 9: Report to User
Summarize all results:
```markdown
## PR Fixes Complete
### PR Processed
- PR #42: 5 comments addressed
### Summary
| Category | Count | Status |
|----------|-------|--------|
| Fixed | 5 | All committed |
| Skipped | 2 | Replied with reasons |
| Responded | 2 | Questions answered |
| Deferred | 1 | Issue #99 created |
### Commits
- abc1234: fix(app): add error handling
- def5678: refactor(component): make helper private
### Verification
- TypeScript: PASSED
- Lint: PASSED
- Build: PASSED
- Pushed: All changes pushed (auto-triggers new reviews)
### Threads Resolved
| Reviewer | Status |
|----------|--------|
| coderabbitai[bot] | Resolved (LGTM) |
| claude[bot] | Resolved (Fixed) |
| wtrwts | Pending (human reviewer) |
[If any failures, list specific errors]
Key Principles
- Orchestrator is minimal - only spawns and collects
- Analysis happens once - single subagent categorizes all comments from ALL reviewers
- Fixes are parallel - spawn all fix subagents simultaneously
- Post-processing is batched - single subagent handles skips/responses/deferrals
- Verification is separate - dedicated subagent for builds
- Push once at the end - single push after all fixes verified (auto-triggers new reviews)
- Every comment addressed - nothing is silently ignored
- Minimal reply noise - just state what was done (commit hash), no re-review requests
- Auto-resolve confirmed threads - when AI reviewers confirm fixes are good, resolve those threads via GraphQL API (human-reviewed threads require manual resolution)
- ALWAYS use threaded replies - ALL replies MUST use JSON input with
in_reply_to as an integer