pr-commenter · git:20261020.f79b691 · 2026-10-20 · sha256 e6c9bee76faa34cf

pr-commenter git:20261020.f79b691A

Immutable. This exact content never changes and is served at /api/v1/blob/e6c9bee76faa34cf.

---
name: pr-commenter
description: Posts comments on Pull Requests including line-level comments, general PR comments, and replies to existing threads. Handles comment threading, resolving conversations, and coordinated commenting across multiple PRs. Use when posting review feedback, replying to comments, or managing PR discussions. Triggers on requests like "post comment", "reply to comment", "add line comment", or when pr-reviewer or pr-feedback-handler needs to communicate on PRs.
---

# PR Commenter

Posts structured comments on Pull Requests with support for line-level feedback and threading.

## Workflow

### Step 0: Fetch Existing Comments

```bash
# List review comments with their IDs
gh api "repos/{owner}/{repo}/pulls/<pr-number>/comments" \
  --jq '.[] | {id, path, line, user: .user.login, body}'
```

### Step 1: Prepare Comment Content

**Format based on comment type:**

**Line-level comment (on specific code):**
```markdown
**[Category: Quality]** Consider adding error handling

The current implementation doesn't handle the case where `user` is undefined.

**Suggestion:**
```typescript
const user = await getUser(id);
if (!user) {
  throw new NotFoundError(`User ${id} not found`);
}
```
```

**General PR comment:**
```markdown
## Feedback on Test Coverage

The new functionality looks good, but I'd like to see more test coverage:

- [ ] Test case for empty input
- [ ] Test case for maximum boundary
- [ ] Error scenario tests

Once these are added, this will be ready to merge!
```

**Reply to existing comment:**
```markdown
@<actual-reviewer-login> Good catch! I've updated the implementation to handle the edge case:

- Added null check on line 45
- Added test case for this scenario
- Updated error message

Please re-review when you have a chance.
```

Substitute the real login from the comment author; GitHub will not notify a placeholder.

### Step 2: Post Comment

Substitute `<pr-number>`, `<comment-id>` and `<file-path>` yourself — gh only expands `{owner}`, `{repo}`, `{branch}`. Run from inside the repository (or set `GH_REPO=owner/repo`).

**Post line-level comment:**

Get the commit sha with `gh pr view <n> --json headRefOid --jq .headRefOid`.

```bash
# Post a line-level comment (requires commit_id + path + line + side)
gh api "repos/{owner}/{repo}/pulls/<pr-number>/comments" \
  -f body="<comment content>" \
  -F commit_id=<commit-sha> \
  -F path=<file-path> \
  -F line=<line-number> \
  -F side=RIGHT
```

**Post general PR comment:**
```bash
gh pr comment <pr-number> --body "$(cat <<'EOF'
<comment content>
EOF
)"
```

**Post reply to specific comment:**
```bash
# Reply to an existing review comment (in_reply_to = the comment's id)
gh api "repos/{owner}/{repo}/pulls/<pr-number>/comments" \
  -f body="<reply content>" \
  -F in_reply_to=<comment-id>
```

### Step 3: Handle Thread Resolution

**Resolve conversation (if applicable):**

```bash
# Resolve a review thread (GraphQL — REST has no resolve endpoint)
THREAD_ID=$(gh api graphql -f query='
  query($owner:String!,$repo:String!,$num:Int!){
    repository(owner:$owner,name:$repo){
      pullRequest(number:$num){
        reviewThreads(first:50){ nodes{ id isResolved comments(first:1){ nodes{ id } } } }
      }
    }
  }' -F owner="<owner>" -F repo="<repo>" -F num=<pr-number> \
  --jq '.data.repository.pullRequest.reviewThreads.nodes[] | select(.comments.nodes[0].id == "<comment-id>") | .id')

gh api graphql -f query='
  mutation($threadId:ID!){ resolveReviewThread(input:{threadId:$threadId}){ thread{ isResolved } } }' \
  -F threadId="$THREAD_ID"
```

### Step 4: Report Status

Return result:
```yaml
Comment Posted:
  PR: <number>
  Type: <line-level / general / reply>
  Thread: <thread-id or none>
  Status: <posted / resolved / needs-follow-up>
```

## Command Mapping

| Requirement | Command |
|-------------|---------|
| General PR comment | `gh pr comment <n> --body "…"` |
| Line-level comment | `gh api repos/{owner}/{repo}/pulls/<n>/comments` (commit_id + path + line + side) |
| Reply in thread | `gh api repos/{owner}/{repo}/pulls/<n>/comments -F in_reply_to=<id>` |
| Resolve thread | `gh api graphql` → `resolveReviewThread` mutation |

## Comment Types

### Type 1: Review Finding (from pr-reviewer)
Posts a code review finding with severity and category.

**Template:**
```markdown
**[Severity: HIGH] [Category: Security]** Potential SQL injection

**Location:** `src/db/user.ts:42`

**Issue:** User input is directly interpolated into SQL query

**Current:**
```typescript
const query = `SELECT * FROM users WHERE name = '${userInput}'`;
```

**Suggested:**
```typescript
const query = 'SELECT * FROM users WHERE name = $1';
const result = await db.query(query, [userInput]);
```

**Impact:** This could allow SQL injection attacks if userInput contains malicious SQL.
```

### Type 2: Fix Confirmation (from pr-feedback-handler)
Confirms that a requested fix has been implemented.

**Template:**
```markdown
✅ **Fixed:** Type safety issue addressed

**Changes made:**
- Replaced `any` with proper `User` interface on line 45
- Added runtime validation before type assertion
- Updated related tests

Commit: `<commit-sha>`
```

### Type 3: Discussion Reply
Responds to a question or suggestion with reasoning.

**Template:**
```markdown
@<actual-reviewer-login> Thanks for the suggestion!

**Reasoning for current approach:**
I considered using the newer pattern, but opted for the current implementation because:
1. It maintains backward compatibility
2. It avoids breaking changes to the public API
3. The performance difference is negligible for our use case

We can migrate to the new pattern in a future PR when we're ready for breaking changes.
```

### Type 4: Batch Summary (from pr-manager)
Summarizes actions taken across multiple comments.

**Template:**
```markdown
## Feedback Processing Complete

**Summary:**
- ✅ Fixed: 3 issues (commits pushed)
- 💬 Replied: 2 questions (reasoning provided)
- ⏳ Pending: 1 discussion awaiting response

**Details:**
1. Fixed type safety in `userService.ts` (commit: abc123)
2. Fixed error handling in `auth.ts` (commit: def456)
3. Fixed test coverage in `utils.test.ts` (commit: ghi789)
4. Replied to architecture question - see thread
5. Replied to scope question - see thread

Ready for re-review!
```

## Integration

**Called by:**
- pr-reviewer (to post review findings)
- pr-feedback-handler (to post fix confirmations and replies)
- pr-manager (to post batch summaries)
- User for manual comments

**Calls to:**
- GitHub CLI/API for comment posting

**Coordinates with:**
- pr-reviewer for review content
- pr-feedback-handler for fix confirmations
- pr-manager for batch operations

## Multi-PR Commenting

When pr-manager needs to post on multiple PRs:

```bash
# Post on PR #277
echo "Comment for #277" | gh pr comment 277 --body-file -

# Post on PR #278 in parallel
echo "Comment for #278" | gh pr comment 278 --body-file -

# etc.
```

## Error Handling

**If comment fails to post:**
- Check authentication: `gh auth status`
- Check permissions on repository
- Retry with exponential backoff

**If replying to resolved thread:**
- GitHub has no 'reopen' operation — `resolveReviewThread` is one-way. To revive a thread, post a new reply with `in_reply_to` (see Step 2).

## Best Practices

1. **Be specific:** Always reference line numbers and file paths
2. **Be constructive:** Provide suggested fixes, not just problems
3. **Be respectful:** Frame as suggestions, not demands
4. **Be actionable:** Clear next steps for the author
5. **Use severity:** HIGH (blocking), MEDIUM (should fix), LOW (optional)

**Category taxonomy (shared with pr-reviewer)**: `Security, Quality, Performance, Testing, Documentation, Architecture, Maintainability, Compatibility`

## References

- [Acceptance Criteria](references/acceptance-criteria.md) — FR/TS requirements, comment formats, error handling
- [Best Practices](references/best-practices.md) — When to use line-level vs general comments, tone, threading, severity labels