pr-review-loop

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

PR Review Loop

PR审核处理循环

Purpose

目标

Address all open PR review comments one at a time using an opinionated, resumable workflow. Works with comments from any reviewer (human or bot).
使用一套既定的、可恢复的工作流,逐个处理所有未解决的PR审核评论。支持处理来自任何审核者(人工或机器人)的评论。

Typical invocations

典型触发方式

Users trigger this skill with prompts like:
  • "Address all open review comments on this PR"
  • "Work through the code review feedback on PR #42"
  • "Fix the review comments left by @alice on this pull request"
  • "Use pr-review-loop on PR #123"
用户可以通过以下类似指令触发该技能:
  • "处理此PR上所有未解决的审核评论"
  • "处理PR #42的代码审核反馈"
  • "修复@alice在此拉取请求上留下的审核评论"
  • "在PR #123上使用pr-review-loop"

Prerequisites

前置条件

  • gh
    CLI (preferred). If unavailable, fall back to any tool available to interact with GitHub.
  • The PR branch must be checked out locally.
  • gh
    CLI(优先推荐)。如果不可用,可使用任何能与GitHub交互的替代工具。
  • 必须已在本地检出该PR对应的分支。

Process

处理流程

Step 1 — Pre-flight

步骤1 — 预检

Inspect the project for safeguard conventions by checking these files (if they exist):
  • CLAUDE.md
    ,
    AGENTS.md
  • Makefile
  • .github/workflows/
  • README.md
Identify all required safeguards (tests, compilation, linting, formatting, etc.). Run all of them. If any fail, stop immediately and report — do not proceed on a broken baseline.
检查项目中的防护规范,查看以下文件(如果存在):
  • CLAUDE.md
    AGENTS.md
  • Makefile
  • .github/workflows/
  • README.md
识别所有必需的防护措施(测试、编译、代码检查、格式化等)。 运行所有防护检查。如果任何检查失败,立即停止并上报——不要在基线已损坏的情况下继续操作。

Step 2 — Get Current PR Number and Basic Info

步骤2 — 获取当前PR编号及基本信息

bash
undefined
bash
undefined

Get current PR details

获取当前PR详情

gh pr status
gh pr status

View PR with all comments

查看包含所有评论的PR

gh pr view
undefined
gh pr view
undefined

Step 3 — Collect Unresolved PR Comments (Source of Truth: reviewThreads)

步骤3 — 收集未解决的PR评论(权威来源:reviewThreads)

bash
undefined
bash
undefined

Fetch review threads and keep only unresolved ones.

获取审核线程,仅保留未解决的线程。

gh api graphql -f query=' query($owner:String!, $name:String!, $number:Int!) { repository(owner:$owner, name:$name) { pullRequest(number:$number) { reviewThreads(first:100) { nodes { id isResolved path line comments(first:20) { nodes { id databaseId author { login } body createdAt replyTo { databaseId } } } } } } } }' -f owner='{owner}' -f name='{repo}' -F number={pr_number}
| jq '.data.repository.pullRequest.reviewThreads.nodes | map(select(.isResolved == false))'

Use unresolved `reviewThreads` as the canonical list for processing. Do not drive the workflow from `/pulls/{pr}/comments` alone.
gh api graphql -f query=' query($owner:String!, $name:String!, $number:Int!) { repository(owner:$owner, name:$name) { pullRequest(number:$number) { reviewThreads(first:100) { nodes { id isResolved path line comments(first:20) { nodes { id databaseId author { login } body createdAt replyTo { databaseId } } } } } } } }' -f owner='{owner}' -f name='{repo}' -F number={pr_number}
| jq '.data.repository.pullRequest.reviewThreads.nodes | map(select(.isResolved == false))'

将未解决的`reviewThreads`作为处理的标准列表。不要仅依赖`/pulls/{pr}/comments`来驱动工作流。

Step 4 — Triage

步骤4 — 分类处理

Read the triage guide for the specific classification framework and examples. If the guide is not available, use the MUST_FIX / SHOULD_FIX / PARK / OUT_OF_SCOPE / NEEDS_CLARIFICATION classification with your own judgment (see definitions below).
Classify every unresolved comment as: MUST_FIX, SHOULD_FIX, PARK, OUT_OF_SCOPE, or NEEDS_CLARIFICATION.
Triage all comments before acting on any.
If a comment is non-actionable/no-op (e.g. acknowledgment, praise, emoji-only), classify as OUT_OF_SCOPE and reply with a short acknowledgment before resolving.
If a comment's intent is genuinely ambiguous — multiple interpretations exist and each would lead to a meaningfully different change — classify as NEEDS_CLARIFICATION rather than guessing.
If Perplexity or other research tools are available and a comment requires external knowledge to classify (e.g., library idioms, language conventions), use them to inform your decision.
阅读分类指南了解具体的分类框架和示例。如果该指南不可用,请根据自己的判断使用MUST_FIX / SHOULD_FIX / PARK / OUT_OF_SCOPE / NEEDS_CLARIFICATION分类(定义如下)。
将每条未解决的评论分类为:MUST_FIX(必须修复)、SHOULD_FIX(应该修复)、PARK(暂时搁置)、OUT_OF_SCOPE(超出范围)或NEEDS_CLARIFICATION(需要澄清)。
在处理任何评论之前,先完成所有评论的分类。
如果评论无需操作(如确认、表扬、仅含表情符号),分类为OUT_OF_SCOPE,并回复简短的确认后标记为已解决。
如果评论的意图确实不明确——存在多种解释,且每种解释会导致截然不同的修改——分类为NEEDS_CLARIFICATION,而非猜测。
如果有Perplexity或其他研究工具可用,且评论需要外部知识才能分类(如库的惯用写法、语言规范),可使用这些工具辅助决策。

Step 5 — Process ONE comment at a time

步骤5 — 逐个处理评论

Process in order: all MUST_FIX first, then SHOULD_FIX. Skip PARK and OUT_OF_SCOPE for now (they are handled in the summary).
NEEDS_CLARIFICATION comments: post one focused question as a reply to the thread (see format below), do not resolve the thread, and move on to the next comment. Do not implement anything.
Cascading comments: When multiple comments form a cascade (e.g., changing a trait signature requires updating all impls, callers, and tests), group them into a single commit referencing all comment IDs. Implement the full cascade atomically — applying any single comment without the others would leave the code in an inconsistent state.
For each comment (or group of cascading comments):
5a. Assess complexity
Is this trivial (e.g., rename a function, fix a typo, adjust formatting)?
  • Yes → fix directly, no plan needed
  • No → create a plan file at
    .pr-review/plan-<comment-id>.md
    before touching any code
The plan file must describe:
  • What the comment is asking for
  • The approach to fix it
  • Files that will be changed
5b. Run safeguards
Run all safeguards identified in Step 1. They must all pass before you touch any code. If they fail, stop and report.
5c. Fix, park, or ask for clarification
  • Fix: implement the change
  • Fix with adaptation: if the reviewer's suggestion is directionally right but the exact code won't compile or is otherwise infeasible, implement the closest working alternative. Document the constraint in your reply (Step 5f) so the reviewer understands why the implementation differs from their suggestion.
  • Park (if you discover mid-fix that it should be parked): write reasoning, revert any partial changes, no commit
  • Ask for clarification (if you discover mid-assessment that the intent is genuinely ambiguous): post one focused question to the thread (see below), do not resolve, no commit, move on
Clarification question format (for NEEDS_CLARIFICATION or mid-assessment uncertainty):
bash
cat > /tmp/pr-review-reply-{comment_id}.md <<'EOF'
Thanks for the feedback! Before I make a change, I want to make sure I understand what you're after:

<one specific, focused question — e.g. "Did you mean to rename this everywhere, or just at the call site?" or "Would you prefer approach A (…) or approach B (…)?">
EOF

jq -n --rawfile body /tmp/pr-review-reply-{comment_id}.md '{body:$body}' > /tmp/pr-review-reply-{comment_id}.json

gh api repos/{owner}/{repo}/pulls/{pull_number}/comments/{comment_id}/replies \
  --input /tmp/pr-review-reply-{comment_id}.json
Ask exactly one question. Do not list alternatives unless directly needed to frame the question. Leave the thread unresolved so the reviewer's answer re-surfaces it.
5d. Run safeguards again
Run all safeguards. They must all pass. If they fail, fix the regression before moving on — do not skip this step.
5e. Commit and push
Each comment gets its own focused commit. Reference the comment author in the message body.
bash
git add <changed files>
git commit -m "<conventional commit message describing the fix>

Addresses PR comment from @<reviewer>."
git push
Example commit flow across multiple comments:
bash
undefined
按顺序处理:先处理所有MUST_FIX,再处理SHOULD_FIX。 暂时跳过PARK和OUT_OF_SCOPE(将在总结步骤中处理)。
NEEDS_CLARIFICATION评论: 在该线程下回复一个聚焦的问题(见下方格式),不要标记线程为已解决,然后处理下一条评论。不要进行任何实现操作。
连锁评论: 当多条评论形成连锁关系时(如修改 trait 签名需要更新所有实现、调用方和测试),将它们归为一个提交,并引用所有相关评论ID。完整实现整个连锁修改——仅应用单条评论的修改会导致代码处于不一致状态。
对于每条评论(或一组连锁评论):
5a. 评估复杂度
是否为简单修改(如重命名函数、修复拼写错误、调整格式)?
  • 是 → 直接修复,无需制定计划
  • 否 → 在修改代码前,创建计划文件
    .pr-review/plan-<comment-id>.md
计划文件必须包含:
  • 评论的要求
  • 修复方案
  • 将修改的文件
5b. 运行防护检查
运行步骤1中识别的所有防护检查。在修改代码前,所有检查必须通过。 如果检查失败,停止操作并上报。
5c. 修复、搁置或请求澄清
  • 修复:实现修改
  • 适配修复:如果审核者的建议方向正确,但具体代码无法编译或不可行,实现最接近的可行方案。在回复中记录约束条件(步骤5f),以便审核者理解实现与建议的差异原因。
  • 搁置(如果在修复过程中发现应搁置):记录原因,回滚所有部分修改,不提交
  • 请求澄清(如果在评估过程中发现意图确实不明确):在该线程下回复一个聚焦的问题(见下方),不要标记为已解决,不提交,处理下一条评论
澄清问题格式(适用于NEEDS_CLARIFICATION或评估过程中的不确定性):
bash
cat > /tmp/pr-review-reply-{comment_id}.md <<'EOF'
感谢您的反馈!在进行修改前,我想确认我理解的是否正确:

<一个具体、聚焦的问题——例如:“您是希望在所有地方重命名,还是仅在调用处重命名?” 或 “您更倾向于方案A(…)还是方案B(…)?”>
EOF

jq -n --rawfile body /tmp/pr-review-reply-{comment_id}.md '{body:$body}' > /tmp/pr-review-reply-{comment_id}.json

gh api repos/{owner}/{repo}/pulls/{pull_number}/comments/{comment_id}/replies \
  --input /tmp/pr-review-reply-{comment_id}.json
仅提出一个问题。除非直接需要明确问题,否则不要列出备选方案。不要标记线程为已解决,以便审核者的回复能重新触发该线程的处理。
5d. 再次运行防护检查
运行所有防护检查。所有检查必须通过。 如果检查失败,先修复问题再继续——不要跳过此步骤。
5e. 提交并推送
每条评论对应一个聚焦的提交。在提交信息正文中引用评论的作者。
bash
git add <changed files>
git commit -m "<符合规范的提交信息,描述修复内容>

Addresses PR comment from @<reviewer>."
git push
多评论处理的提交示例:
bash
undefined

Comment 1: Add missing documentation

评论1:添加缺失的文档

git commit -m "docs: add module-level documentation for MetricsRecorder
Addresses PR comment from @reviewer about missing module docs." git push
git commit -m "docs: add module-level documentation for MetricsRecorder
Addresses PR comment from @reviewer about missing module docs." git push

Comment 2: Use Duration instead of i64

评论2:使用Duration替代i64

git commit -m "refactor: use Duration type for timing parameters
Addresses PR comment from @reviewer - improves type safety." git push

**5f. Reply to the PR comment**

Post a reply on the PR comment explaining:
- What was done (for fixes: reference the commit)
- Why it was parked (for deferred items)
- Why it was rejected (for out-of-scope items)

Preferred (gh CLI):
```bash
git commit -m "refactor: use Duration type for timing parameters
Addresses PR comment from @reviewer - improves type safety." git push

**5f. 回复PR评论**

在PR评论下回复,说明:
- 已完成的操作(对于修复:引用提交)
- 搁置的原因(对于延迟处理的项)
- 拒绝的原因(对于超出范围的项)

推荐方式(使用gh CLI):
```bash

Avoid inline backticks/shell interpolation issues by writing body to a file.

将回复内容写入文件,避免行内反引号/ shell插值问题。

cat > /tmp/pr-review-reply-{comment_id}.md <<'EOF' <reply text> EOF
jq -n --rawfile body /tmp/pr-review-reply-{comment_id}.md '{body:$body}' > /tmp/pr-review-reply-{comment_id}.json
gh api repos/{owner}/{repo}/pulls/{pull_number}/comments/{comment_id}/replies
--input /tmp/pr-review-reply-{comment_id}.json

**5f.1 Verify reply body**

Immediately verify what was posted (to catch shell mangling):
```bash
gh api repos/{owner}/{repo}/pulls/comments/{new_reply_comment_id} | jq '{id, body, html_url}'
5g. Resolve the comment
Mark the comment as resolved on GitHub.
First, find the thread ID for the comment:
bash
gh api graphql -f query='
query {
  repository(owner: "{owner}", name: "{repo}") {
    pullRequest(number: {pr_number}) {
      reviewThreads(first: 50) {
        nodes {
          id
          isResolved
          comments(first: 1) { nodes { body } }
        }
      }
    }
  }
}'
Then resolve the thread:
bash
gh api graphql -f query='
mutation {
  resolveReviewThread(input: {threadId: "{thread_id}"}) {
    thread { id isResolved }
  }
}'
Verify resolution:
bash
gh api graphql -f query='
query {
  node(id: "{thread_id}") {
    ... on PullRequestReviewThread {
      id
      isResolved
    }
  }
}'
5h. Delete plan file
If a plan file was created, delete it:
bash
rm .pr-review/plan-<comment-id>.md
cat > /tmp/pr-review-reply-{comment_id}.md <<'EOF' <回复文本> EOF
jq -n --rawfile body /tmp/pr-review-reply-{comment_id}.md '{body:$body}' > /tmp/pr-review-reply-{comment_id}.json
gh api repos/{owner}/{repo}/pulls/{pull_number}/comments/{comment_id}/replies
--input /tmp/pr-review-reply-{comment_id}.json

**5f.1 验证回复内容**

立即验证已发布的回复(避免shell处理导致的错误):
```bash
gh api repos/{owner}/{repo}/pulls/comments/{new_reply_comment_id} | jq '{id, body, html_url}'
5g. 标记评论为已解决
在GitHub上标记评论为已解决。
首先,查找评论对应的线程ID:
bash
gh api graphql -f query='
query {
  repository(owner: "{owner}", name: "{repo}") {
    pullRequest(number: {pr_number}) {
      reviewThreads(first: 50) {
        nodes {
          id
          isResolved
          comments(first: 1) { nodes { body } }
        }
      }
    }
  }
}'
然后标记线程为已解决:
bash
gh api graphql -f query='
mutation {
  resolveReviewThread(input: {threadId: "{thread_id}"}) {
    thread { id isResolved }
  }
}'
验证已解决状态:
bash
gh api graphql -f query='
query {
  node(id: "{thread_id}") {
    ... on PullRequestReviewThread {
      id
      isResolved
    }
  }
}'
5h. 删除计划文件
如果创建了计划文件,删除它:
bash
rm .pr-review/plan-<comment-id>.md

Step 6 — Stop condition

步骤6 — 停止条件

Stop when no MUST_FIX or SHOULD_FIX comments remain.
If you prefer to batch-resolve all threads at once rather than one by one, you can do so here:
bash
gh api graphql -f query='
query {
  repository(owner: "{owner}", name: "{repo}") {
    pullRequest(number: {pr_number}) {
      reviewThreads(first: 50) {
        nodes { id isResolved comments(first: 1) { nodes { body } } }
      }
    }
  }
}' | jq -r '.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false) | .id' \
  | while read thread_id; do
    gh api graphql -f query="mutation { resolveReviewThread(input: {threadId: \"$thread_id\"}) { thread { id } } }"
  done
当没有MUST_FIX或SHOULD_FIX评论时停止。
如果您希望一次性批量标记所有线程为已解决,而非逐个处理,可在此执行以下命令:
bash
gh api graphql -f query='
query {
  repository(owner: "{owner}", name: "{repo}") {
    pullRequest(number: {pr_number}) {
      reviewThreads(first: 50) {
        nodes { id isResolved comments(first: 1) { nodes { body } } }
      }
    }
  }
}' | jq -r '.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false) | .id' \
  | while read thread_id; do
    gh api graphql -f query="mutation { resolveReviewThread(input: {threadId: \"$thread_id\"}) { thread { id } } }"
  done

Step 7 — Summary

步骤7 — 总结

Post a final comment on the PR summarising:
undefined
在PR上发布最终评论,总结:
undefined

PR Review Loop — Summary

PR审核处理循环 — 总结

Fixed

已修复

  • [commit abc1234] Renamed
    foo
    to
    bar
    (comment by @alice)
  • ...
  • [提交 abc1234] 将
    foo
    重命名为
    bar
    (来自@alice的评论)
  • ...

Parked

已搁置

  • Refactor of X module deferred — tracked in #<issue> (comment by @bob)
  • ...
  • X模块的重构已推迟 — 跟踪在#<issue>中(来自@bob的评论)
  • ...

Rejected

已拒绝

  • Suggestion to use Y rejected: project convention is Z (comment by @carol)
  • ...
  • 使用Y的建议已拒绝:项目规范为Z(来自@carol的评论)
  • ...

Awaiting Clarification

待澄清

  • Asked @alice: "Did you mean to rename this everywhere, or just at the call site?" — thread left open
  • ...

Omit any section that has no entries.

Use a body file to avoid shell interpolation:
```bash
cat > /tmp/pr-review-summary.md <<'EOF'
<summary text>
EOF

gh pr comment {pr_number} --body-file /tmp/pr-review-summary.md
Then verify the posted summary body:
bash
gh pr view {pr_number} --comments
  • 向@alice提问:“您是希望在所有地方重命名,还是仅在调用处重命名?” — 线程未关闭
  • ...

省略没有内容的部分。

使用文件写入内容以避免shell插值问题:
```bash
cat > /tmp/pr-review-summary.md <<'EOF'
<总结文本>
EOF

gh pr comment {pr_number} --body-file /tmp/pr-review-summary.md
然后验证已发布的总结内容:
bash
gh pr view {pr_number} --comments

Resumability

可恢复性

This skill is designed to be interrupted and restarted in a fresh context at any point.
On startup:
  1. Run pre-flight (Step 1)
  2. Re-fetch unresolved comments from GitHub (Step 3) — already-resolved comments won't appear
  3. Check for an existing
    .pr-review/plan-*.md
    file — if found, you are mid-fix on that comment; continue from Step 4b
  4. If the previous run was interrupted, verify the latest issue/comment bodies and thread states before continuing (to catch partially posted or malformed remote writes)
  5. Triage remaining comments and continue
This means no progress is ever lost. Each fix is committed and pushed before moving on.
该技能设计为可在任何点中断并在新的上下文中重启。
启动时:
  1. 运行预检(步骤1)
  2. 从GitHub重新获取未解决的评论(步骤3)——已解决的评论不会显示
  3. 检查是否存在现有的
    .pr-review/plan-*.md
    文件——如果存在,说明正在处理该评论;从步骤4b继续
  4. 如果上一次运行被中断,在继续前验证最新的issue/评论内容和线程状态(以捕获部分发布或格式错误的远程操作)
  5. 分类剩余评论并继续处理
这意味着不会丢失任何进度。每次修复完成后都会提交并推送,再处理下一个。

State Directory

状态目录

.pr-review/
at the repo root (gitignored by the project).
  • plan-<comment-id>.md
    — plan for the comment currently in progress (deleted after resolution)
仓库根目录下的
.pr-review/
(已被项目忽略)。
  • plan-<comment-id>.md
    — 当前处理中评论的计划文件(解决后删除)

Do Not

禁止操作

  • Bundle all PR feedback into one large commit
  • Make multiple unrelated changes in a single commit
  • Push all changes at once without intermediate commits
  • Leave comments unresolved after addressing them
  • 将所有PR反馈合并为一个大提交
  • 在单个提交中进行多个不相关的修改
  • 不进行中间提交,一次性推送所有修改
  • 处理完评论后不标记为已解决