Skip to content
Back to skills

Respond

BSecurity

Respond to incoming code review comments on a PR you authored. Fetches every unresolved comment across all channels, inline threads, review bodies, PR-level conversation, and commit comments, classifies each by author and intent, verifies against the current code, fixes what is real, replies only inside a human's inline thread, closes bot threads and unrepliable channels without a comment, and monitors CI. Use when user says "respond to review", "address comments", "handle reviewer feedback",...

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 26, 2026
ai-agentstypescriptpythonrustgoshellbashreactnodecode-reviewgit

Works with

  • cursor
  • terminal
  • cli
  • api

Security analysis

B75/100
  • criticalSends environment variables or credentials to an external URL

Pro scans all 5 files and shows the line behind each finding

Scanned October 3, 2026

npx -y skills add gufranco/claude-engineering-rules --skill respond --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Respond?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Respond
[![Security: B — Skills Directory](https://www.skillsdirectory.com/api/skills/gufranco-respond/badge)](https://www.skillsdirectory.com/skills/gufranco-respond)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: respond
description: Respond to incoming code review comments on a PR you authored. Fetches every unresolved comment across all channels, inline threads, review bodies, PR-level conversation, and commit comments, classifies each by author and intent, verifies against the current code, fixes what is real, replies only inside a human's inline thread, closes bot threads and unrepliable channels without a comment, and monitors CI. Use when user says "respond to review", "address comments", "handle reviewer feedback", "reply to PR comments", "my PR has comments", or wants a structured pass over reviewer feedback. Do NOT use for performing a review (use /review), or for unattended AI bot thread handling (use /ship --pipeline).
sensitive: true
---
Receive-side counterpart to `/review`. Turns the loose, error-prone workflow of "respond to PR review comments" into a structured, validated pipeline. The seven phases take the user from "I see comments on my PR" to "every thread is answered or closed, code changes are validated and pushed, CI is green".

[`../../rules/pr-comment-discipline.md`](../../rules/pr-comment-discipline.md) governs everything this skill publishes. One reply surface: a human's inline thread, four sentences at most. Bot threads are read, fixed when the finding is real, then resolved in silence. The three channels with no reply endpoint are answered by the code change and closed by minimizing.

## Subcommand Routing

| Invocation | Action |
|-----------|--------|
| `/respond` | Full workflow on the current branch's PR |
| `/respond <PR>` | Same workflow targeting a specific PR number or URL |
| `/respond fetch` | Phase 1 to Phase 3 only. List threads with classification. No implementation, no posting |
| `/respond reply <thread-id>` | Reply to one specific thread. Skip the batch flow |
| `/respond resolve <thread-id>` | Resolve one specific thread. No reply |

If no subcommand is given, default to the full workflow.

## Arguments

| Flag | Effect |
|------|--------|
| No args | Use the current branch's PR |
| `<PR number or URL>` | Target that PR |
| `--humans-only` | Default. Skip threads whose first comment is from a bot |
| `--include-bots` | Include AI bot threads in the workflow, for fixing and closing. Bot threads never receive a reply |
| `--auto` | Execute the approved batch without per-batch confirmation. Requires `RESPOND_AUTO_ACK=1` env var to take effect |
| `--interactive` | Confirm per thread instead of per batch |
| `--filter <pattern>` | Filter threads by file path glob or author login |
| `--dry-run` | Run Phases 1 through 5, print the proposed actions, exit without executing |
| `--re-request` | Re-request review from the original reviewers after the batch ships |
| `--no-resolve` | Skip the resolution step |
| `--resolve-by <author\|reviewer>` | Resolution convention. Default `author`, opt-in `reviewer` |
| `--force-during-review` | Allow force-push even when an open CHANGES_REQUESTED review exists. Off by default |

## Phase 1: Discover PR

1. Run **in parallel**: `git remote get-url origin`, `git branch --show-current`, `git status --porcelain`.
2. Detect platform from the remote URL. Supported platforms: GitHub, GitLab, Bitbucket Cloud. The default workflow in this file documents GitHub. For GitLab specifics, read [`platform-gitlab.md`](platform-gitlab.md) and substitute the API surface. For Bitbucket Cloud, read [`platform-bitbucket.md`](platform-bitbucket.md) and substitute. The classification taxonomy, reply templates, and bot triage rules are identical across platforms.
3. Resolve the platform account per [`../../standards/multi-account-cli.md`](../../standards/multi-account-cli.md). GitHub uses `GH_TOKEN=$(gh auth token --user <account>) gh ...`. GitLab uses `GITLAB_TOKEN=$(glab auth token --hostname <host>) glab ...`. Bitbucket uses `BITBUCKET_TOKEN` or `BITBUCKET_USERNAME`+`BITBUCKET_APP_PASSWORD` via `curl`.
4. Resolve the PR. If an argument is passed, parse it. Otherwise look up the PR for the current branch.

   ```bash
   GH_TOKEN=$(gh auth token --user <account>) gh pr view \
     --json number,url,state,headRefOid,headRefName,baseRefName,author,reviewRequests \
     --jq '{number, url, state, headRefOid, head: .headRefName, base: .baseRefName, author: .author.login, requested: [.reviewRequests[].requestedReviewer.login]}'
   ```

5. Validate. If PR is `CLOSED` or `MERGED`, ask before proceeding. If no PR is found and no argument is passed, stop.
6. Warn on uncommitted changes that conflict with the working tree the skill will modify.
7. When the PR author is the acting account, run `python3 ~/.claude/hooks/ai-review-request.py --repo <owner/name> --pr <n> --account <account>` once. It subscribes the PR to every AI reviewer the repository supports and does nothing when that is already in place. The push in Phase 6 triggers the same check through the hook.

## Phase 2: Fetch Comments

Read [`../../standards/pr-comment-channels.md`](../../standards/pr-comment-channels.md) and use its canonical fetch verbatim. That standard is the single source of truth for what a PR comment is, on all three platforms. Do not hand-roll a narrower query here; a narrower query is exactly how the P0 deadlock report was missed.

The four GitHub channels, all mandatory:

| Bucket | Source | Native resolve |
|--------|--------|----------------|
| Inline threads | `reviewThreads`, `subjectType` `LINE` or `FILE` | Yes |
| Review bodies | `reviews` | No |
| PR-level conversation | `comments` | No |
| Commit comments | `timelineItems`, `PULL_REQUEST_COMMIT_COMMENT_THREAD` | No |

Fetch every review state, not only `[APPROVED, CHANGES_REQUESTED, COMMENTED]`. Filter states after fetching so a `DISMISSED` review carrying an unanswered question stays visible.

Filter rules.

- Drop only what the standard's Terminal States table marks terminal. Everything else is in scope.
- Never drop on `isOutdated` or `isCollapsed` alone. An outdated comment can still name a live bug.
- Honor `isMinimized == true`. It is the closest thing the three non-resolvable channels have to a resolve action, on any of the seven `minimizedReason` values.
- Apply `--humans-only` unless `--include-bots` is set. The human filter keeps items whose first comment is from `author.type == "User"` AND login is not in the AI bot allowlist.
- Group inline threads by file path, then sort by line number within file. Group the other three buckets separately.
- Review bodies, PR-level comments, and commit comments get no reply. They are answered by the code change and closed by minimizing, per the standard's "Answering Each Channel" table.
- Filter out PR-level comments whose body starts with auto-generated markers such as `<!-- LEAD_APPROVAL -->`, `<!-- linear-linkback -->`, or `<!-- This is an auto-generated comment: summarize by coderabbit.ai -->`, since these are tracker or bot signals, not actionable.
- Drop items authored by the running account, your own prior replies unless they were quoted as part of a multi-round conversation.

Cross-check after fetch. Run the Completeness Cross-Check from the standard. Report per-channel counts in Phase 5, never a single total. The skill must never report "nothing to respond to" while a substantive comment in any channel is still unanswered.

AI bot allowlist for classification: `coderabbitai[bot]`, `copilot-pull-request-reviewer[bot]`, `greptile-apps[bot]`, `sourcery-ai[bot]`, `korbit-ai[bot]`, `cursor[bot]`, `qodo-merge-pro[bot]`, `bito-pr-review[bot]`, `gemini-code-assist[bot]`, `claude[bot]`, `tabnine-ai[bot]`. Auxiliary lint or dependency bots: `github-actions[bot]`, `dependabot[bot]`, `renovate[bot]`, `pre-commit-ci[bot]`, `lefthook[bot]`.

## Phase 3: Classify and Verify

For each thread, classify on three axes.

### Axis 1: Author type

| Value | Detection |
|-------|-----------|
| `human` | `author.type == "User"` AND login is not in the AI bot allowlist |
| `bot:ai` | `author.type == "Bot"` AND login matches the AI bot allowlist |
| `bot:lint` | `author.type == "Bot"` AND login matches an auxiliary lint or dependency bot |
| `bot:other` | `author.type == "Bot"` AND no other category matches |
| `self` | Author login matches the resolved account |

### Axis 2: Comment intent

Use the Conventional Comments taxonomy. When the reviewer used an explicit prefix like `nitpick:`, `suggestion:`, `issue:`, `question:`, `praise:`, `thought:`, `chore:`, or `todo:`, trust that prefix verbatim. Otherwise classify heuristically.

| Intent | Conventional Comments mapping | Keyword and structural signals |
|--------|------------------------------|--------------------------------|
| `issue:blocking-bug` | `issue (blocking)` | "this is broken", "will crash", "null pointer", "off-by-one", reproducer present |
| `issue:blocking-security` | `issue (security, blocking)` | "leak", "injection", "auth", "permission", "secret", "CVE", "credential" |
| `issue:blocking-correctness` | `issue (blocking)` | "wrong", "incorrect logic", "this returns", "should be" with a clear assertion |
| `issue:architectural` | `issue (non-blocking)` | "rethink", "different approach", "this whole pattern", "redesign" |
| `suggestion` | `suggestion` | "consider", "could", "what about", "alternatively" |
| `question` | `question` | Ends with `?`, "why did you", "how does this", "is this intentional" |
| `thought` | `thought` | Reflective, no requested action, "I wonder if", "musing" |
| `nitpick` | `nitpick` | Prefixed `nit:`, `nitpick:`, `style:`, very small scope |
| `praise` | `praise` | "nice", "good catch", "clean", no actionable content |
| `chore:out-of-scope` | `chore` | "separate PR", "follow-up", "out of scope". The intent is the reviewer's framing, never a licence to defer |
| `todo` | `todo` | "leave a TODO", reminder for the future, not for this PR |
| `clarification-request` | `question` | "what does this do", "can you explain", "I do not follow" |

### Axis 3: Action decision

Set by the verification step below.

| Decision | Meaning |
|----------|---------|
| `implement` | Comment is correct, apply the fix |
| `push-back` | Comment is incorrect, explain why |
| `clarify` | Need more info from reviewer before acting |
| `dismiss` | The finding does not hold. Bot threads mostly end here |
| `ack` | Acknowledge praise or info-only comment |
| `accept-with-modification` | Implement a variant of the suggestion |
| `conflict` | Two reviewers contradict on the same line. See Multi-Reviewer Conflict Resolution |

For `issue:blocking-*` intents, the decision space is restricted to `implement`, `push-back`, `clarify`.

There is no `defer` decision. A problem that can be fixed in this change is fixed in this change, and no ticket, follow-up, or separate pull request stands in for the fix. See [`../../rules/pr-comment-discipline.md`](../../rules/pr-comment-discipline.md) and [`../../rules/found-fix.md`](../../rules/found-fix.md). When a fix is genuinely blocked outside the change, such as a coordinated release or a migration another team owns, the decision is `push-back` and the reply names the blocker in one sentence.

### Verification step

For every thread classified as `issue:*`, `suggestion`, or `architectural`, read the cited file at the cited line, plus 50 lines of surrounding context. Verify against the current code, not against the code at the time the comment was posted.

| Check | Why |
|-------|-----|
| Does the cited code still exist? | If `isOutdated == true`, the comment may already be resolved by a later push |
| Does the cited code do what the reviewer claims? | False positives happen, especially with AI reviewers |
| Would the suggestion actually be better? | Apply the same criteria the `/review` skill uses |
| Are there hidden constraints the reviewer did not see, like tests, callers, or contracts? | Surfaces push-back cases with evidence |
| Can the bug be reproduced locally? | If not, the reply names the steps tried |

Output per thread: a classification record with author type, intent, decision, evidence, and a draft reply.

## Phase 4: Draft Strategy

For each thread, draft a reply and, when applicable, a code change.

### Step 1: Decide whether a reply exists at all

Author type decides this before a word is drafted, and it is recorded in the plan table.

| Author type | What gets published |
|-------------|---------------------|
| `human`, inline thread | A reply in the thread. The four principles below apply |
| `human`, other channel | No reply. The code change answers it; the commit names the point |
| `bot:ai`, `bot:lint`, `bot:other` | Nothing. Ever |
| `self` | Nothing |

A bot thread is read, verified against the code, fixed when the finding survives the failure-scenario gate in [`../../rules/ai-review-convergence.md`](../../rules/ai-review-convergence.md), and then resolved. No verdict line, no acknowledgment, no dismissal note.

The reasoning is the same reasoning that used to justify a short bot reply, carried to its conclusion. A bot has no stake to manage, cannot be persuaded, will not answer, does not remember the thread, and did not miss anything. An audience with none of those properties needs a shorter message only if it needs a message. It does not. What the verdict line was for, telling a later reader what happened, is carried better by the commit that closed the thread, and a commit outlives any thread.

Never write any of these to a bot thread:

| Never | Why |
|-------|-----|
| A reply of any length | Nothing reads it |
| A verdict such as fixed, declined, or false positive | The commit and the resolve state already say it |
| Second-person address | Addresses a party that is not present |
| Praise or agreement | Credits an agent for a pattern match |
| Argument or persuasion | A bot has no position to change |
| A question | Nothing will answer |

### The four principles below are for human inline threads only

Skip this whole section when the author is a bot. There is nothing to draft.

Every reply obeys the ceiling in [`../../rules/pr-comment-discipline.md`](../../rules/pr-comment-discipline.md): four sentences, polite in a clause, no restatement of the comment, no closing offer. A reviewer is a person with other work. Anything past the ceiling belongs in the code or the pull-request description.

### Principle 1: Fix the code before explaining it

When a reviewer did not understand, the code is the first thing to change. Renaming a confusing variable, extracting a helper, or adding a code-level comment beats writing a thread reply that future readers will not see.

### Principle 2: Lead with reasoning when pushing back

Bare "I disagree" is a known failure mode. Use the Feedback Equation pattern: Observation, Impact, Request. State what the code does, what would change if you took the reviewer's path, and what you want from the reviewer next.

Example. Observation: "The current code uses `setTimeout` instead of `requestAnimationFrame`." Impact: "Switching to `requestAnimationFrame` would skip the ping when the tab is backgrounded, breaking the keep-alive contract documented in `docs/keepalive.md`." Request: "Want me to name the constraint in the function itself, say `pingWhileTabBackgrounded`, or do you see a way to keep the behavior with a different API?"

### Principle 3: Switch to synchronous after two round trips

When a thread has cycled twice without convergence, propose a brief call. The skill does not initiate calls but tags the thread `synchronous-recommended` so the user can act on it.

### Principle 4: When you cannot reproduce, name the steps

"Couldn't reproduce" is a defensive wall. "Couldn't reproduce. Steps I tried: A, B, C. Did I miss something?" invites the reviewer to clarify.

### Reply templates

Full exemplars with good and bad counterparts live in [`reply-templates.md`](reply-templates.md).

**The table below applies to human inline threads only.** A bot thread has no wording to choose. The intent axis still drives the decision for a bot thread, which is then closed silently.

| Intent x Decision | Template summary |
|-------------------|-------------------|
| `issue:blocking-bug` x `implement` | "You're right. Pushed `<SHA>`. <one sentence on the fix>." Add a named regression test |
| `issue:blocking-bug` x `push-back` | Feedback Equation form. End with "Did I miss something?" |
| `issue:blocking-security` x `implement` | "You're right. Pushed `<SHA>` with <fix>." Any second defect the same comment exposed is fixed in the same push |
| `issue:blocking-correctness` x `clarify` | "Want to make sure I am reading this right. <One-line restatement>. Is that it?" |
| `issue:architectural` x `push-back` | "Landing this with the current approach. <Reason>. The redesign is worth its own thread." |
| `suggestion` x `implement` | "Good call. Applied in `<SHA>`." Credit trailer for non-trivial suggestions |
| `suggestion` x `accept-with-modification` | "Took a variant in `<SHA>`. <Difference from the original>." |
| `suggestion` x `push-back` | "Considered that. Went with the current approach because <reason>. The alternative would <downside>." |
| `question` x `ack` | "<Direct answer>." If the answer reveals confusing code, fix the code instead |
| `clarification-request` x `ack` | "<Plain explanation>." If non-trivial, make the code say it: rename, extract, or tighten the type |
| `nitpick` x `implement` | "Fixed in `<SHA>`." |
| `nitpick` x `push-back` | "Sticking with the current style for consistency with <other pattern>." |
| `chore:out-of-scope` x `implement` | The default. A change small enough to be called out of scope is small enough to make: "Fixed in `<SHA>`." |
| `chore:out-of-scope` x `push-back` | Only when the fix is blocked outside this change. "<The blocker>, so it cannot land here." No ticket |
| `todo` x `implement` | Do the work now. A marker recording it is banned by the comments policy |
| `praise` x `ack` | No reply. React with a thumbs-up on GitHub and resolve |
| Bot x any | Not this table. No reply exists. Fix a surviving finding, resolve the thread, move on |

Every template passes the no-internal-config-leakage check before posting.

### Code change planning

For `implement` and `accept-with-modification` decisions, draft the change at the line level. Record: the file path, the lines to modify, the new content, and the validation tests that must pass after.

For `issue:blocking-*` decisions, plan a named regression test like `it('rejects empty companyId per PR #4521')`. Apply when the bug has a specific reproducer, the fix is a one-line guard whose absence could regress invisibly, or the bug was filed by a user or downstream team. Skip when the regression would be loud, like a compile error or a type error.

## Phase 5: Present and Approve

Print a batched table to the terminal. One row per item. Two columns are mandatory. `Channel` is what makes an omitted channel visible rather than invisible. `Reply` is what makes a banned post visible before it is sent: only an `inline` row with a `human` author may carry a preview, and every other row must read `none`. A preview on any other row is a drafting error to fix, not to approve.

```
#  Channel     Author          Type   Location               Intent                 Decision      Reply                          Code change
1  inline      alice           human  src/auth.ts:42         issue:blocking-bug     implement     "You're right. Pushed..."      +12 -3 in src/auth.ts
2  inline      bob             human  src/auth.ts:78         suggestion             push-back     "Considered that. Went..."     none
3  inline      coderabbitai    bot    src/orders.ts:120      nitpick                implement     none, resolve                  +1 -1 in src/orders.ts
4  review-body carol           human  review #4 CHANGES_REQ  issue:blocking-bug     implement     none, minimize                 +8 -1 in src/db.ts
5  pr-level    dave            human  conversation           issue:blocking-bug     implement     none, minimize                 +4 -2 in src/lock.ts
6  commit      erin            human  a1b2c3d src/api.ts     question               implement     none, minimize                 +3 -1 in src/api.ts
7  inline      copilot         bot    src/api.ts:12          suggestion             dismiss       none, resolve                  none
```

Row 6 shows the shape a question in an unrepliable channel takes: the answer is a code change that makes the question stop arising, and the commit message carries the point. When a change alone would leave the reviewer guessing, add the sentence to the pull-request description rather than opening a comment.

Close the table with per-channel counts so a zero is never ambiguous:

```
inline 3 | review bodies 1 | PR-level 1 | commit 1
```

If the batch exceeds 25 rows, paginate with `--filter` suggestions.

Prompt the user to approve the batch as a whole, edit a specific row, split into smaller batches, or abort. `--auto` plus the `RESPOND_AUTO_ACK=1` env var skips the prompt. `--interactive` shifts to per-row approval.

If `--dry-run`, stop here and exit.

## Phase 6: Execute Approved Batch

Order: code first, then reply, then resolve. Each step has its own checkpoint.

### Step 1: Apply code changes

Each thread's change becomes its own commit. Commit message format: `fix(<scope>): <one-line description>`. Body includes `Refs: <comment URL>`. Credit trailers per "Commit Credit Conventions" below.

### Step 2: Run the local quality gate

In order. Show output for each. If any fails, stop and report.

| Step | Detection |
|------|-----------|
| Format | `prettier --check`, `black --check`, `gofmt -l`, `rustfmt --check`, depending on the project |
| Lint | `eslint`, `ruff`, `golangci-lint`, `clippy --deny warnings`, depending on the project |
| Type check | `tsc --noEmit`, `mypy --strict`, `pyright`, depending on the project |
| Test | The project's full suite, with coverage if scripted |
| Build | The project's build command |

Use the same detection logic as `/ship pr` step 4.

### Step 3: Push once at the end

After all commits land cleanly. Use `-u` if no upstream is set. Use `--force-with-lease` only if a rebase rewrote history. Never use `--force`. If an open CHANGES_REQUESTED review exists on the PR, the push hooks block force unless `--force-during-review` was passed.

### Step 4: Re-fetch threads

Confirm the latest SHA is on the PR and no new threads landed during execution.

### Step 5: Post replies via REST

One reply surface. Every other row posts nothing.

| Channel | Reply mechanism |
|---------|-----------------|
| Inline thread, human author | `POST repos/<o>/<r>/pulls/<pr>/comments/<comment-id>/replies` |
| Inline thread, bot author | None |
| Review body, PR-level, commit comment | None. Step 6 closes them |

Write a JSON file to `/tmp/respond-reply-<thread-id>.json`. Single-quoted heredoc to prevent shell expansion.

```bash
cat <<'PAYLOAD' > /tmp/respond-reply-<thread-id>.json
{
  "body": "<draft reply body, includes the fix SHA>"
}
PAYLOAD

GH_TOKEN=$(gh auth token --user <account>) gh api \
  repos/<owner>/<repo>/pulls/<pr>/comments/<comment-id>/replies \
  -X POST \
  --input /tmp/respond-reply-<thread-id>.json
```

### Step 6: Close every item

Only inline threads can be resolved. For each inline thread whose decision is `implement`, `push-back`, `accept-with-modification`, `ack`, or `dismiss`, post the reply first when one exists, then resolve. Threads with decision `clarify` stay open. Threads with decision `conflict` stay open until the conflicting reviewers align.

```bash
GH_TOKEN=$(gh auth token --user <account>) gh api graphql \
  -f query='mutation($threadId: ID!) {
    resolveReviewThread(input: { threadId: $threadId }) {
      thread { id, isResolved }
    }
  }' -F threadId=<thread-id>
```

One resolve per thread. The `bulk-resolve-blocker.py` hook enforces this.

Review bodies, PR-level comments, commit comments, and bot comments outside a resolvable thread are closed by minimizing, since they have no resolve action and get no reply:

```bash
GH_TOKEN=$(gh auth token --user <account>) gh api graphql \
  -f query='mutation($id: ID!) {
    minimizeComment(input: { subjectId: $id, classifier: RESOLVED }) {
      minimizedComment { isMinimized, minimizedReason }
    }
  }' -F id=<node-id>
```

Minimize only after the change that answers the comment has landed. Use `RESOLVED` when a change settled the point and `OUTDATED` when the cited code is gone. Never `SPAM`, `ABUSE`, or `LOW_QUALITY` on a human comment. When minimizing is unavailable, such as on a repository where the account lacks the permission, leave the item open and say so in the final report rather than posting a comment to mark it handled.

### Step 7: Re-request review

If `--re-request` was passed.

```bash
GH_TOKEN=$(gh auth token --user <account>) gh api \
  repos/<owner>/<repo>/pulls/<pr>/requested_reviewers \
  -X POST \
  -f reviewers='["alice","bob"]'
```

The re-request is the whole signal. What changed since the last round belongs in the pull-request description, which the reviewer reads anyway, never in a fresh comment.

### Step 8: Clean up

```bash
rm /tmp/respond-reply-*.json /tmp/respond-query-*.graphql
```

## Phase 7: Monitor and Close

After every push triggered by the batch, enter the Pipeline Monitoring loop from `/ship`. Reuse the same loop as a shared procedure. Loop until CI is green on the latest SHA AND no new threads have appeared since the last fetch. Bot threads that appear after the push are deferred to `/ship --pipeline` unless `--include-bots` was set.

Final output:

```
RESOLVED: 7 comments addressed on PR #1234.
  Channels swept: inline 4 | review bodies 1 | PR-level 1 | commit 1
  - 4 implemented (commits: a1b2c3d, e4f5g6h, i7j8k9l, m0n1o2p)
  - 2 pushed back with reasoning
  - 1 dismissed after the finding did not hold
  Replies posted: 2, both in human inline threads
  Inline threads resolved: 4. Unrepliable channels minimized: 3
  CI: 12 of 12 checks passed
  Re-requested review from: alice, bob
```

The "Channels swept" line is mandatory. It is the evidence that all four channels were queried, and it is the line a user can check when they suspect a comment was missed.

## Service Level Expectations

The skill embeds the cycle-time discipline from Google eng-practices and Pragmatic Engineer.

| Action | Target |
|--------|--------|
| Acknowledge a human review comment | Within 4 hours of becoming aware |
| First substantive response to a batch | Within 1 business day |
| Batch responses, single push | One push covers all approved replies and fixes for the round |
| Re-request review after addressing | The explicit re-request. No accompanying comment |
| Synchronous escalation | After two round trips with no convergence |
| Stale PR handling | If no movement for 7 days, the author either pushes a status update or closes the PR |

The skill enforces these by surfacing reminders, never by acting unilaterally. When a thread has been open for more than 4 hours without acknowledgment, the skill prints a notice. When a PR has been idle for more than 7 days, the skill suggests a status update or closure.

## AI Bot Triage Tactics

Full pattern catalog with per-tool false positives lives in [`bot-triage.md`](bot-triage.md). The summary below is the operational ruleset when `--include-bots` is set.

### Severity baseline

Treat every AI-bot comment as P3 until corroborated by a human reviewer or by a verification check. Independent audits show CodeRabbit precision around 50%, Greptile with the highest catch rate but also the highest false-positive rate, Copilot reporting 71% actionable.

### Known false-positive patterns

| Pattern | Common origin |
|---------|---------------|
| Style suggestion that contradicts the project's lint config | CodeRabbit, Sourcery |
| Imagined APIs, like suggesting a `lodash` helper in a project that bans lodash | CodeRabbit |
| "Add a try/catch" on code that intentionally propagates the error | Multiple bots |
| Security warning on input already validated upstream | CodeRabbit, Greptile |
| "Add JSDoc" in a project whose convention is types-as-docs | CodeRabbit |
| Refactor suggestion that does not compile under TypeScript strict | All bots |
| "Consider using async/await" on code that already uses it | Copilot |

### A wrong bot finding is closed, never answered

Resolve the thread and move on. Nothing is written into it.

Some tools claim to learn from a written dismissal over two to four weeks. The claim is unverified here, and it is the only argument that ever favored writing to a bot. Weighed against a reply on every false positive, on every pull request, for a reader who does not exist, the trade is not worth taking. When a bot repeatedly misses a project rule, the fix is the tool's own configuration file, which is durable, rather than a comment that is not.

### Commands cheat sheet

| Command | Effect |
|---------|--------|
| `@coderabbitai pause` in the PR description | Pauses re-review during heavy iteration. In the description, never in a comment |
| `@coderabbitai resume` | Resumes |
| `@coderabbitai review` | Single re-pass |
| `@coderabbitai ignore` | Disables on this PR |
| `bugbot run` | Triggers a new Cursor BugBot pass |
| `cursor review` | Same |

### Never credit a bot as commit author

The personal CLAUDE.md rule and the broader research both prohibit attributing commits or PRs to AI tooling. The `ai-attribution-blocker.py` hook is the runtime enforcement layer. The skill's draft commit message must not name any AI tool in any author or co-author trailer.

## Multi-Reviewer Conflict Resolution

When two reviewers contradict, the skill surfaces a `conflict` decision instead of executing.

| Pattern | Skill action |
|---------|--------------|
| Reviewer A wants X, Reviewer B wants Y, on the same line | Mark both threads `conflict`. Draft a reply that quotes both verbatim, states the author's slight preference with reasoning, and asks A and B to align before the author pushes |
| Reviewer A approved, Reviewer B has not responded in over 24 hours | Print a notice. Default: do not auto-merge. Suggest a one-time re-request of review from B |
| Reviewer A blocks, Reviewer B has not yet weighed in | Hold the merge. The skill never dismisses a CHANGES_REQUESTED review without an explicit user decision |
| Both reviewers stale for over 2 round trips with no convergence | Tag the threads `synchronous-recommended` and suggest escalation to a tech lead or module owner |

The skill never silently merges or dismisses a CHANGES_REQUESTED review. Re-requesting review is a manual action behind `--re-request <user>`.

## Resolution Convention

Two community conventions exist.

### Default convention from Tidyverse and GitLab

The author resolves only the threads they have fully addressed and that are unambiguous. Anything with an open reply, an open question, a suggestion the author chose not to take, or a request for verification stays open for the reviewer to resolve. This is the default in the skill.

### Alternative convention from Dan Clarke

The person who started the thread resolves. The author never resolves. Opt in with `--resolve-by reviewer`.

In both conventions, the skill never bulk-resolves. Each resolve is a single GraphQL call tied to a specific thread whose action just completed. The `bulk-resolve-blocker.py` hook enforces this at the runtime layer.

### Outdated vs Resolved

GitHub auto-marks comments as `outdated` when the cited line changes. Outdated is not the same as resolved. An outdated comment can still name a live bug: the line moved, the concern did not. The skill never relies on `isOutdated == true` as a substitute for an explicit resolution, and never drops an item on that basis. The same holds for `isCollapsed`, which is a display hint. Force-pushing to mark threads outdated is an anti-pattern flagged in the "As Reviewee" section of [`../../standards/code-review.md`](../../standards/code-review.md).

`isMinimized == true` is different: minimizing is a deliberate human decision recorded on the platform, and it is the nearest thing to a resolve action that the three non-resolvable channels have. Honor it as terminal.

## Commit Credit Conventions

Use Git trailers to credit human reviewers.

| Trailer | When to use |
|---------|-------------|
| `Co-authored-by: <Name> <email>` | The reviewer wrote a portion of the fix, supplied a non-trivial algorithm, or proposed a change the author took verbatim |
| `Suggested-by: <Name> <email>` | The reviewer suggested the direction. The author implemented it independently |
| `Reviewed-by: <Name> <email>` | The reviewer reviewed and approved the change. Common in kernel and Rust projects |

Apply only to human reviewers. Never to AI tools or any non-human contributor. The `ai-attribution-blocker.py` hook is the runtime enforcement layer.

The skill prompts before adding any credit trailer. The default is no trailer unless the reviewer's input was substantive.

## Rules

- Every comment channel in [`../../standards/pr-comment-channels.md`](../../standards/pr-comment-channels.md) is swept every run. Inline threads are one channel of four. Never report "nothing to respond to" without per-channel counts backing the claim.
- Only the Terminal States table drops an item. `isOutdated` and `isCollapsed` are never drop criteria.
- Every drafted reply passes the no-internal-config-leakage check before posting. No `~/.claude/` paths, no rule citations, no checklist numbers in any external output.
- Every code change goes through the full local quality gate before push.
- Closure requires either a posted reply or a landed fix. Resolving a thread that received neither is forbidden.
- A reply is published only into a human's inline thread, at four sentences or fewer. Bot threads and the three unrepliable channels are closed without a comment, per [`../../rules/pr-comment-discipline.md`](../../rules/pr-comment-discipline.md).
- Bulk resolve is forbidden. Each thread is resolved individually after its action completes. The `bulk-resolve-blocker.py` hook backs this rule at runtime.
- `--auto` is the only path that skips per-batch approval. It additionally requires `RESPOND_AUTO_ACK=1` to take effect. Two locks reduce accidental triggers.
- Nothing is deferred and no tracker item is created. The fix lands in this change or the reply names the external blocker.
- AI bot threads are out of scope by default. `--include-bots` is opt-in, and even then they receive no reply.
- Account safety: every `gh` call uses `GH_TOKEN=$(gh auth token --user <account>)` inline.
- Never `git push --no-verify`. Never bypass hooks without an explicit user-confirmed env var.
- Force-push is blocked during open CHANGES_REQUESTED reviews unless `--force-during-review` is passed.
- The skill never dismisses, deletes, or downgrades a review that the running user did not author.
- Restore the working tree on any failure inside Phase 6. The skill leaves a clean tree if it cannot complete the batch.

## Platform Reference Files

| File | When to read |
|------|-------------|
| [`platform-gitlab.md`](platform-gitlab.md) | When the detected platform is GitLab. Documents glab CLI and REST API patterns, discussion model, resolve semantics, and bot allowlist |
| [`platform-bitbucket.md`](platform-bitbucket.md) | When the detected platform is Bitbucket Cloud. Documents REST API patterns, auth model, and the absence of a native resolve concept |

## Related skills

| Skill | When to use it |
|-------|----------------|
| `/review` | Performing a review on someone else's PR. Generates verdicts using the same Conventional Comments taxonomy |
| `/ship --pipeline` | Unattended handling of AI bot threads and CI monitoring without human-thread work. When `RESPOND_DRIVES_PIPELINE=1` is set, `/ship --pipeline` delegates the AI-bot sweep to this skill via `--auto --include-bots`, unifying the vocabulary across both flows |
| `/ship pr` | Creating or updating a PR before review starts |
| `/test` | Running tests after a code change before posting "Fixed in `<SHA>`" |
| `/investigate` | When a reviewer reports a bug that does not reproduce, before drafting the reply |
| `/plan` | When a reviewer requests an architectural change too large for inline reply |

Files in this skill

  • SKILL.md35.2 KB
  • bot-triage.md11.2 KB
  • platform-bitbucket.md7.6 KB
  • platform-gitlab.md8.7 KB
  • reply-templates.md17.5 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.