review-pr について
review-pr は、コーディングエージェント向けに GitHub のプルリクエストレビューコメントを取得、検証、処理するスキルです。現行コードを確認したうえで、評価、返信、スレッド解決までを一度の流れで行います。
主な機能
- 01現在のブランチのプルリクエスト検索
- 02トップレベルコメントの取得と分類
- 03現行ファイルに基づくコメント検証
- 04コメントへの返信とスレッド解決
- 05レビュー完了内容の要約
活用シーン
- 01GitHub プルリクエストのレビュー整理
- 02指摘された問題が残っているかの確認
- 03確認済みの修正とレビュアーへの返信
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ richtabor/ agent-skills --skill review-prインストール後、Claude Code で/review-prを入力して読み込まれたか確認します。
詳細
PR コメントのレビュー
GitHub から PR のレビューコメントを取得、評価し、対応します。レビュアーのコメントは古いコードに言及していたり、ロジックを誤解していたりすることが多いため、対応する前に必ず実際のコードベースを確認してください。
プロセス
これは一度に完了するフローです。 コメントを取得し、ファイルを読み、評価を提示し、すべてのコメントに返信し、すべてのスレッドを解決して、最終的な要約を表示します。ユーザーの確認を待ってはいけません。
1. PR を探す
PR 番号が指定されていない場合は、現在のブランチの PR を探します。
gh pr list --head $(git branch --show-current) --json number,title --jq '.[0]'
2. レビューコメントを取得する
ID 付きでコメントを取得します。
gh api repos/{owner}/{repo}/pulls/{number}/comments --jq '.[] | {id: .id, path: .path, line: (.line // .original_line), body: .body, in_reply_to_id: .in_reply_to_id}'
トップレベルのコメント(in_reply_to_id が null のもの)のみを対象にします。
3. 参照先のファイルを読む(重要なステップ)
コメントを評価する前に、必ず現在の実際のコードを読んでください。 レビュアーは次のようなことがよくあります。
- 古いコミットの行番号を参照する
- ロジックを読み違える
- すでに修正済みのコードにコメントする
ファイルパスごとに、重複を除いてファイルを読み、次の点を確認してください。
- 行番号はレビュアーの説明と一致しているか
- 問題はすでに対応済みか
- コードに対するレビュアーの理解は正しいか
4. すべてのコメントを評価する
各コメントを分類します。
| カテゴリー | 基準 | 対応 |
|---|---|---|
| 対応済み | 後続のコミットで問題が修正された、またはレビュアーがコードを読み違えている | コードが実際に何をしているか説明する |
| 修正 | 現在のコードに有効なバグ、セキュリティ上の問題、または誤字がある | 修正を実装する |
| 対応しない | 過剰な設計、スタイルの好み、機能リクエスト、または一貫性を損なうもの | 理由を説明する |
5. 評価を提示し、返信して、解決する
これらすべてを一度に行います。ユーザーの確認を待ってはいけません。 評価を提示し、各コメントに返信して、すべてのスレッドをすぐに解決します。
すべてのコメントに対する評価を提示します。
## PR #[number]: [title]
Found [X] review comments. Here's my assessment:
---
### 1. `path/file.ts:42` — **Already addressed**
> [comment body]
**Issue**: Reviewer concerned about X
**Actual code**: Lines 26-34 already handle this — [brief explanation]
---
### 2. `path/other.ts:15` — **Won't fix**
> [comment body]
**Issue**: Reviewer wants X
**Why skip**: [Over-engineering / Matches existing pattern / Feature request / etc]
---
### 3. `path/file.ts:88` — **Fix**
> [comment body]
**Issue**: Typo in user-facing string
**Proposed change**: Change "Jumpope" to "Jump Rope"
---
## Summary
- **Already addressed**: 6 comments
- **Won't fix**: 8 comments
- **Fix**: 2 comments
その後、すぐにすべてのコメントに返信し、すべてのスレッドを解決します(以下のステップ 6~7)。ユーザーの入力を待ってはいけません。
6. コメントに返信する
対応済みのコメントには、現在の状態を説明して返信します。
gh api repos/{owner}/{repo}/pulls/{pr_number}/comments/{comment_id}/replies \
-X POST \
-f body="This is already handled — lines 26-34 fetch the authenticated user and verify user.id === state before proceeding. If they don't match, it rejects with a CSRF error."
対応しないコメントには、簡潔な理由を添えて返信します。
gh api repos/{owner}/{repo}/pulls/{pr_number}/comments/{comment_id}/replies \
-X POST \
-f body="Won't fix — this matches the exact pattern used for the other integrations in the same file. Changing just this one would be inconsistent."
修正のコメントには、先に修正を実装してから返信します。
gh api repos/{owner}/{repo}/pulls/{pr_number}/comments/{comment_id}/replies \
-X POST \
-f body="Fixed in abc1234"
7. すべてのスレッドを解決する
まず、未解決のスレッド ID をすべて取得します。
cat << 'QUERY' | gh api graphql --input - --jq '.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false) | {threadId: .id, commentId: .comments.nodes[0].databaseId}'
{"query": "query($owner: String!, $repo: String!, $pr: Int!) { repository(owner: $owner, name: $repo) { pullRequest(number: $pr) { reviewThreads(first: 100) { nodes { id isResolved comments(first: 1) { nodes { databaseId } } } } } } }", "variables": {"owner": "OWNER", "repo": "REPO", "pr": 123}}
QUERY
次に、ID を指定して各スレッドを解決します。
cat << 'QUERY' | gh api graphql --input -
{"query": "mutation { resolveReviewThread(input: {threadId: \"THREAD_ID_HERE\"}) { thread { isResolved } } }"}
QUERY
8. 最終的な要約
返信と解決が完了したら、最終的な要約を表示します。
## Review Complete
All 16 conversations resolved.
### Already addressed (6)
| Comment | Explanation |
|---------|-------------|
| State validation | Already validates user.id === state at lines 26-34 |
| HR zones docs | Comments already say "milliseconds", not "percentage" |
### Won't fix (8)
| Comment | Reason |
|---------|--------|
| Form semantics | Matches existing pattern for other integrations |
| Rate limiting | Self-heals on next cron run, over-engineering |
### Fixed (2)
| Commit | Fix |
|--------|-----|
| `abc123` | Fixed typo "Jumpope" → "Jump Rope" |
重要:フロー全体(評価 → 返信 → 解決 → 要約)は一度に行います。「続行してもよいですか?」と確認するために止まらず、そのまま実行してください。
評価ガイドライン
対応済み — 修正せずに説明する
レビュアーが誤っている場合によくあるパターン:
- レビュアーが誤った行番号を参照している:レビュー後にコードが変更されている
- レビュアーがロジックを読み違えている:例:正しい条件を逆だと思い込んでいる
- 問題はすでに修正されている:後続のコミットで対応済み
- コードが別の場所にある:チェック/検証は別の関数で行われている
返信テンプレート:
「これはすでに対応済みです — [具体的な場所] で [その処理の内容] を行っています。[それが正しい理由の簡単な説明]。」
修正 — 実装してコミットする
次の条件を満たす問題のみを修正します。
- 現在のコードに実際に存在する
- バグ、セキュリティ上の問題、または誤字である
- ファイルを読んで確認できる
修正しない — 理由を説明する
| 理由 | 回答テンプレート |
|---|---|
| 既存のパターンに一致 | 「修正しません — これは同じファイル内の X、Y、Z とまったく同じパターンです。これだけを変更すると、一貫性がなくなります。」 |
| 過剰な設計 | 「修正しません — [障害モード] は明確に失敗する/再試行で自動的に回復する/[既存の仕組み] で処理されます。」 |
| 機能リクエスト | 「修正しません — これはバグではなく機能リクエストです。現在のフローは正常に動作します:[現在の動作]。この PR の範囲外です。」 |
| プロダクト上の判断 | 「修正しません — これはバグではなく、プロダクト上の判断です。[現在の動作] は、[理由] により意図されたものです。」 |
| 問題が発生する | 「修正しません — これを変更すると、[既存の動作/X との一貫性] が損なわれます。」 |
よくあるレビュアーの誤解
条件の逆転
レビュアーはブール論理を読み違えることがよくあります。例:
// "Refresh if expires in less than 5 minutes"
if (expiry.getTime() - Date.now() > 5 * 60 * 1000) {
return integration.access_token!; // Token is fresh, return early
}
// Proceed to refresh...
レビュアーの指摘:「条件が逆になっているため、トークンが更新されない」 実際:条件は正しく、新しい場合は早期リターンし、古い場合は更新します。
実装済みの検証を見落とす
レビュアーの指摘:「State パラメーターが検証されていない」 実際:26〜34 行ですでに検証しています。 同意する前に、検証が実装されているか必ず確認してください。
エラーメッセージ内のトークン
レビュアーの指摘:「エラーメッセージに機密トークンが記録されている」 実際:エラーに記録されるのは API のエラーレスポンスであり、こちらのトークンではありません。 エラー文字列の実際の内容を確認してください。
その行に存在しないコード
レビュアーが 174 行目を指摘していますが、ファイルは 161 行しかありません。 レビュー以降にファイルが変更されています。
主な原則
- 一度の流れで実行する:「続行してもよいですか?」と尋ねて立ち止まらず、評価、回答、解決、要約を一度の流れで行う
- 対応する前に確認する:コメントを評価する前に、必ず実際のファイルを読む
- コードベースを信頼する:既存のパターンが機能しているなら、新しいコードもそれに合わせる
- ただ退けるのではなく、説明する:対応を見送ったコメントには、明確な説明を添える
- すべて解決する:修正した場合も説明した場合も、すべてのスレッドを解決する
- 簡潔にする:回答は段落ではなく、1〜2 文にする