---
name: "pr-review-response"
description: "Teaches agents to reply to PR review comment threads after fixing issues, making resolutions traceable"
domain: "pull-requests, code-review, traceability"
confidence: "low"
source: "observed (agents fix review feedback silently — reviewers can't tell which comments were addressed)"
tools:
  - name: "github-mcp-server-pull_request_read"
    description: "Read PR review threads and comments"
    when: "Step 1 — fetching review comments to understand what needs fixing"
  - name: "gh api (REST)"
    description: "Reply to review comment threads and resolve threads via GraphQL"
    when: "Step 3 — posting reply to each comment thread after fixing"
---

## Context

When an agent fixes code in response to PR review comments (from Copilot, a human reviewer, or any GitHub reviewer), the fix alone is not enough. The reviewer needs to see — on the PR thread itself — which comments were addressed and how. Without replies, comments stay visually unresolved, reviewers must re-read the entire diff to verify fixes, and there's no traceable link between feedback and resolution.

Use this skill whenever:
- You are fixing code based on PR review feedback
- You are addressing Copilot review suggestions
- You are responding to reviewer-requested changes on a PR
- A squad member hands you review comments to resolve

## SCOPE

✅ THIS SKILL PRODUCES:
- Reply comments on each review thread explaining the fix
- Optionally resolved threads (via GraphQL when appropriate)
- Commit messages that reference the PR and review context

❌ THIS SKILL DOES NOT PRODUCE:
- The code fixes themselves (that's the agent's domain work)
- New review comments or reviews
- PR descriptions or summaries

## Patterns

### Step 1: Read the review comments

**Using MCP tools (preferred when available):**

```
github-mcp-server-pull_request_read
  method: "get_review_comments"
  owner: "{owner}"
  repo: "{repo}"
  pullNumber: {pr_number}
```

This returns review threads with metadata: `isResolved`, `isOutdated`, `isCollapsed`, and their associated comments. Each comment has an `id` you'll need for replies.

**Using gh CLI (fallback):**

```bash
gh api repos/{owner}/{repo}/pulls/{pr_number}/comments --paginate
```

Each comment object contains `id`, `body`, `path`, `line`, and `in_reply_to_id`. Top-level comments have no `in_reply_to_id` — those are the ones you reply to.

### Step 2: Fix the code

Make the actual code changes. This is your normal domain work — the skill doesn't prescribe how to fix, only how to communicate the fix.

**Track what you changed.** For each review comment, note:
- The comment `id` (top-level, not a reply)
- The file and line referenced
- What you actually changed (brief description)
- The commit SHA after pushing (if available)

### Step 3: Reply to each review thread

After fixing and committing, reply to **each** review comment thread individually.

**REST API call (via gh CLI):**

```bash
gh api repos/{owner}/{repo}/pulls/{pr_number}/comments/{comment_id}/replies \
  -f body="Fixed in {sha_short} — {brief description of what was changed}"
```

**Important:** `{comment_id}` must be the ID of the **top-level** comment in the thread. You cannot reply to a reply — only to the original review comment.

**Example replies:**

```bash
# Specific and traceable
gh api repos/bradygaster/squad/pulls/42/comments/18234/replies \
  -f body="Fixed in a1b2c3d — switched to path.dirname(squadDirInfo.path) for worktree consistency"

# When applying a suggested code change
gh api repos/bradygaster/squad/pulls/42/comments/18235/replies \
  -f body="Applied suggestion — updated error message to include the file path for debuggability"

# When pushing back on a suggestion
gh api repos/bradygaster/squad/pulls/42/comments/18236/replies \
  -f body="Considered but not applied — this path needs to stay absolute because worktree resolution depends on it. See detectSquadDir() in detect-squad-dir.ts."
```

### Step 4: Resolve threads (optional, GraphQL only)

Thread resolution is only available via the GitHub GraphQL API. Use this when your fix fully addresses the comment and no further discussion is needed.

**First, get the thread IDs** (they're different from comment IDs):

```bash
gh api graphql -f query='
  query {
    repository(owner: "{owner}", name: "{repo}") {
      pullRequest(number: {pr_number}) {
        reviewThreads(first: 100) {
          nodes {
            id
            isResolved
            comments(first: 1) {
              nodes { body databaseId }
            }
          }
        }
      }
    }
  }
'
```

Match thread IDs to comment IDs using `databaseId`, then resolve:

```bash
gh api graphql -f query='
  mutation {
    resolveReviewThread(input: {threadId: "{thread_node_id}"}) {
      thread { id isResolved }
    }
  }
'
```

**When to resolve vs. leave open:**
- ✅ Resolve: You fixed exactly what was requested, no ambiguity
- ❌ Don't resolve: You pushed back, applied a different fix, or the comment needs further discussion
- ❌ Don't resolve: The reviewer is a human — let them confirm and resolve themselves

**Rule of thumb:** Agent-to-agent threads (e.g., Copilot review → agent fix) can be resolved by the fixer. Human reviewer threads should be left for the human to resolve.

### Step 5: Commit message traceability

Commit messages should reference the PR context:

```
fix: address review feedback on PR #{pr_number}

- Switched to path.dirname() for worktree path resolution (comment #18234)
- Updated error message to include file path (comment #18235)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
```

For single-comment fixes, a shorter format works:

```
fix: use path.dirname() for worktree consistency (PR #{pr_number} review)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
```

## AGENT WORKFLOW (Summary)

1. **READ** — Fetch review threads using MCP tool or `gh api`
2. **FIX** — Make code changes, tracking comment ID → change mapping
3. **COMMIT** — Push with traceable commit message referencing PR and comments
4. **REPLY** — Post individual reply to each thread via `gh api .../replies`
5. **RESOLVE** — (Optional) Resolve agent-to-agent threads via GraphQL
6. **STOP** — Do not batch-reply, do not skip threads, do not resolve human threads

## Examples

### Example: Copilot flags a potential null dereference

**Review comment (id: 55123):**
> `squadDir` could be undefined here. Consider adding a null check.

**Agent workflow:**
1. Read the comment via `get_review_comments`
2. Add the null check in `src/cli/core/detect-squad-dir.ts`
3. Commit: `fix: add null check for squadDir (PR #99 review)`
4. Reply:
   ```bash
   gh api repos/bradygaster/squad/pulls/99/comments/55123/replies \
     -f body="Fixed in f4e5d6c — added early return when squadDir is undefined, matching the pattern in loadConfig()"
   ```
5. Resolve the thread (Copilot → agent, safe to resolve)

### Example: Multiple review comments on one PR

**Comments:**
- id: 55123 — "Null check needed" on `detect-squad-dir.ts:42`
- id: 55124 — "Consider using path.join()" on `detect-squad-dir.ts:58`
- id: 55125 — "This log message is too verbose" on `output.ts:15`

**Agent handles each individually:**
```bash
# Fix all three, commit
git add packages/squad-cli/src/cli/core/detect-squad-dir.ts packages/squad-cli/src/cli/core/output.ts
git commit -m "fix: address 3 review comments on PR #99

- Added null check for squadDir (comment #55123)
- Switched to path.join() for cross-platform paths (comment #55124)
- Reduced log verbosity to debug level (comment #55125)"

git push

# Reply to each thread individually
gh api repos/bradygaster/squad/pulls/99/comments/55123/replies \
  -f body="Fixed — added early return when squadDir is undefined"

gh api repos/bradygaster/squad/pulls/99/comments/55124/replies \
  -f body="Fixed — switched to path.join(squadDir, 'config.json') for cross-platform consistency"

gh api repos/bradygaster/squad/pulls/99/comments/55125/replies \
  -f body="Fixed — changed from console.log to debug() so it only shows with --verbose flag"
```

### Example: Handling Copilot suggestion blocks

Copilot sometimes provides `suggestion` blocks with exact code to apply:

**Review comment (id: 55130):**
````
Consider using optional chaining:
```suggestion
const name = config?.agent?.name ?? 'default';
```
````

**Reply format when applying:**
```bash
gh api repos/bradygaster/squad/pulls/99/comments/55130/replies \
  -f body="Applied suggestion — using optional chaining with nullish coalescing"
```

**Reply format when not applying:**
```bash
gh api repos/bradygaster/squad/pulls/99/comments/55130/replies \
  -f body="Not applied — config is guaranteed non-null at this point (validated on line 12). Optional chaining would mask errors."
```

### Example: Pushing back on a review comment

Not every review comment should be accepted. When a suggestion is incorrect or doesn't apply:

```bash
gh api repos/bradygaster/squad/pulls/99/comments/55140/replies \
  -f body="Considered but not applied — this file is in the zero-dependency bootstrap set (see copilot-instructions.md § Protected Files). Adding path.join() would require importing from the SDK, which breaks the bootstrap constraint."
```

Do NOT resolve the thread when pushing back. Leave it open for the reviewer to confirm.

## Anti-Patterns

- ❌ **Fixing silently** — Making code changes without replying to the review thread. The reviewer has no way to know which comments were addressed.
- ❌ **Batch-replying "all fixed"** — A single comment saying "Addressed all review feedback" on the PR. Each thread needs its own reply so reviewers can verify individually.
- ❌ **Resolving without explaining** — Marking threads resolved without posting a reply first. The resolution gives no context on what was done.
- ❌ **Resolving human reviewer threads** — Only resolve threads from automated reviewers (Copilot, bots). Let human reviewers confirm and resolve their own threads.
- ❌ **Vague replies** — "Fixed" or "Done" without saying what was changed. The reply should be specific enough that the reviewer doesn't need to re-read the diff.
- ❌ **Replying before pushing** — Reply after your fix is committed and pushed, not before. The reply should reference actual committed code.
- ❌ **Ignoring comments you disagree with** — If you don't apply a suggestion, reply explaining why. Silence looks like you missed it.
- ❌ **Replying to replies** — The REST API only supports replying to top-level review comments. Attempting to reply to a reply will fail with a 404.
