はじめに
今回はGitHubを用いた開発において、GitHub Copilotによるコードレビューを導入している場合におすすめのSkillを作成してみました。
内容としては、
- 出したプルリクエストに対するGitHub Copilotのレビュー結果を取得する
- 修正の提案をClaude Codeがレビューし、必要があれば対応する
です。
関連するこれらの記事も参考にしてみてください。
リクエスト内容
※skill-creatorを使用しています。
今回は以下のようにリクエストしました。
曖昧な内容は逆質問で聞いてくれるのでとても助かります。
完成したのがこちら
一部マークダウンの仕様上、[```]の前に#を入れています。
~.claude/skills/handle-copilot-review/SKILL.md
---
name: handle-copilot-review
description: 現在のgitブランチに紐づくPullRequestを特定し、GitHub Copilotコードレビュー(copilot-pull-request-reviewer[bot])が残した未解決の指摘を1件ずつ取り出して、コメント内容と該当コード・周辺コンテキストを確認した上で「採用すべきか」をユーザーと対話的に判断していくスキル。ユーザーが `/handle-copilot-review` と入力したとき、または「Copilotのレビューを処理して」「Copilotレビューを反映」「Copilotの指摘を見て」「Copilotのコメントに対応して」「PRのCopilotレビュー見てくれる?」「Copilotレビュー潰して」など、PR上に積まれたGitHub Copilotレビューを精査・取り込み・取捨選択したい場面で必ず使用する。コメント1件ごとに「適用 / スキップ / さらに議論」をユーザー判断で進める対話型ワークフロー、未解決スレッドのみを対象にする取り扱い、Copilot以外のレビュアーを対象外とする方針が必要なすべてのケースで本スキルを優先的に呼び出すこと。コミットやpushは行わず、作業ツリーへの修正反映までを担当する。
---
# handle-copilot-review
現在のgitブランチに紐づくGitHub PullRequestを特定し、GitHub Copilotコードレビュー(`copilot-pull-request-reviewer[bot]`)が残した **未解決の** 指摘コメントを1件ずつ精査して、コードコンテキストを踏まえながらユーザーと対話で「採用するか」を決定し、必要なものは作業ツリーに反映していくスキル。
## このスキルが目指すこと
GitHub Copilotコードレビューは便利な反面、機械的に出される指摘の中には「文脈を踏まえると不要」「事実誤認」「スタイル上の好み」など、そのまま採用すべきでないものも混ざる。一方で本質的なバグや見落としを拾うこともあり、無視はできない。本スキルの役割は次の通り:
1. 現在のブランチからPR番号を特定し、ユーザーに提示する
2. Copilotの未解決レビューコメントを **未解決スレッド単位** で取得する
3. コメント1件ごとに「指摘内容 + 該当コード + 周辺コンテキスト」を提示し、Claudeとして採用可否の評価を述べる
4. ユーザーが **適用 / スキップ / さらに議論** の3択で判断する
5. 「適用」なら作業ツリーに修正を反映、「スキップ」なら何もせず次へ、「さらに議論」ならその場で対話を続ける
6. 全件処理後、何を適用し何をスキップしたかの一覧をサマリ表示する
7. **コミット・push・PRスレッドの返信や解決操作は一切行わない**
ユーザーが目指すゴールは「Copilotの指摘を丁寧に1件ずつ吟味し、本当に取り込むべきものだけを反映した状態の作業ツリー」である。スキルはレビューの判断を奪わず、判断のためのお膳立てに徹する。
## 実行手順
### Step 1: 前提条件と現在の状態を一括取得
以下を **並列で** 実行する:
#```bash
git branch --show-current
#```
#```bash
git status --short
#```
#```bash
gh auth status
#```
#```bash
gh repo view --json nameWithOwner,defaultBranchRef --jq '{repo: .nameWithOwner, default: .defaultBranchRef.name}'
#```
これで「現在のブランチ / 作業ツリーの状態 / gh CLIの認証状態 / リポジトリ名」が一度に揃う。
#### 致命的な前提が満たされない場合
- `gh auth status` が認証エラー → 「`gh auth login` で認証してから再度実行してください」と伝えて終了。
- `gh repo view` が失敗(GitHubリポジトリでない、ghコマンドがない等) → その旨を伝えて終了。
- 現在のブランチがmain/masterなどデフォルトブランチ → 「デフォルトブランチにはPRが紐づきません。featureブランチに切り替えてください」と伝えて終了。
#### 未コミット変更がある場合
`git status --short` で出力がある場合、Copilotの指摘を反映する前から作業ツリーに変更が残っている状態である。次のように案内する:
#```
作業ツリーに未コミットの変更があります:
- `path/to/file.ts`
- ...
このまま本スキルでさらに修正を加えると、Copilot対応の変更と既存の変更が混ざります。
以下のどちらで進めますか?
1. 一旦中断して既存の変更をコミット/退避してから再実行(推奨)
2. このまま続行する(コミット時にユーザー自身で切り分ける前提)
#```
ユーザーが「続行」を選んだ場合のみStep 2へ進む。
### Step 2: 現在のブランチに紐づくPR番号の特定
#```bash
gh pr view --json number,title,url,headRefName,baseRefName,state
#```
このコマンドは現在チェックアウトしているブランチに紐づくPRを返す。返ってきた情報を以下のフォーマットでユーザーに提示する:
#```
## 対象PRを特定しました
- ブランチ: `feat/xxx`
- PR: #123 [タイトル]
- URL: https://github.com/owner/repo/pull/123
- 状態: OPEN / DRAFT / MERGED / CLOSED
このPRのCopilotレビューを処理します。
#```
#### PRが見つからない場合
`gh pr view` が `no pull requests found` で失敗した場合:
#```
このブランチ `feat/xxx` に紐づくPullRequestが見つかりませんでした。
考えられる原因:
- まだPRを作成していない(`/draft-pr` でPRを作成してから再実行してください)
- ブランチ名が一致するPRがない
- リモートへpushされていない
このまま終了します。
#```
#### PRがCLOSED / MERGEDの場合
確認を取る:
#```
このPRは既に <CLOSED|MERGED> 状態です。それでもCopilotレビューを処理しますか?
通常、MERGED後のレビュー対応は不要です。
#```
ユーザーが続行を選ばない限り終了する。
### Step 3: Copilotの未解決レビューコメントを取得
PRの **レビュースレッド** をGraphQLで取得する。`pulls/:number/comments` のRESTエンドポイントでは `isResolved` を取得できないため、GraphQLを使う。
#```bash
gh api graphql -f query='
query($owner: String!, $repo: String!, $number: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $number) {
reviewThreads(first: 100) {
nodes {
id
isResolved
isOutdated
path
line
startLine
originalLine
comments(first: 20) {
nodes {
databaseId
author { login }
body
path
line
startLine
diffHunk
url
createdAt
}
}
}
}
}
}
}' -F owner=<owner> -F repo=<repo> -F number=<pr-number>
#```
`<owner>` `<repo>` はStep 1の `gh repo view` 結果から、`<pr-number>` はStep 2の結果から取る。
#### フィルタリングの方針
返ってきたスレッドから以下の条件で絞り込む:
- `isResolved == false` のスレッドのみ
- スレッド内の最初のコメント `author.login` が **`copilot-pull-request-reviewer`** または **`copilot-pull-request-reviewer[bot]`** で始まるもの(GitHub Copilotコードレビューのbotアカウント)
`isOutdated == true`(コメント以降にコードが変更されて行番号が古い)のものは「Outdated」として明示しつつ処理対象に含める。Outdatedでも指摘の本質は有効なことが多いため、勝手にスキップしない。
#### 該当コメントが0件の場合
#```
このPRには未解決のCopilotレビューコメントはありませんでした。
(参考)
- Copilotレビュー総コメント数: N件
- うち解決済み: M件
- うちCopilot以外のレビュアー: K件
対応すべき指摘がないため終了します。
#```
### Step 4: 未解決コメントの俯瞰を提示
処理対象のスレッドが1件以上ある場合、まず全体像をユーザーに提示する:
#```
## 未解決のCopilotレビューコメント
N件の未解決指摘があります。1件ずつ確認していきます。
| # | ファイル | 行 | 概要 | Outdated |
|---|---------|----|----|----------|
| 1 | `src/foo.ts` | 42 | 〜の境界チェック漏れの指摘 | - |
| 2 | `src/bar.ts` | 88-95 | 〜のループ条件についての提案 | ⚠ |
| 3 | `README.md` | 12 | 〜の表記揺れ修正 | - |
| ... |
進めてよろしいですか? OKであれば1件目から処理を開始します。
#```
ユーザーOKでStep 5へ。
### Step 5: コメント1件ずつの精査ループ
`N` 件のコメントに対して、以下のサイクルを **1件ずつ順番に** 回す。複数件をまとめて処理しない。
#### 5-1. 該当コードの読み込み
スレッドの `path` と `line` / `startLine` を使って、対象ファイルの該当箇所と前後の文脈(前後10〜20行程度)を `Read` ツールで読む。複数行コメント(`startLine` ≠ `line`)の場合はその範囲をすべてカバーする。
Outdatedの場合は、コメント時点の `diffHunk` を見つつ、現状のファイル内容も読む。「Copilotが見ていた時点 → 現在」のズレが評価の鍵になる。
#### 5-2. コメント内容と評価をユーザーに提示
以下のフォーマットで提示する:
#```
## コメント i/N
**ファイル**: `<path>` の <line> 行目 <Outdatedなら "(⚠ Outdated)">
**コメントURL**: <url>
### Copilotの指摘
> <body — 改行は引用ブロックに保ったまま貼る>
### 該当箇所(現状)
#```<lang>
<path>:<startLine>-<endLine>
<前後コンテキスト込みのコード>
#```
### Claudeの評価
<以下のいずれかの観点を、具体的な根拠とともに述べる:>
- **指摘は妥当**: <なぜ妥当か。修正案の概略>
- **指摘は的外れ/不要**: <なぜ不要か。文脈・既存設計・他箇所での処理など>
- **判断保留**: <情報不足、設計判断が必要、副作用が大きいなど、ユーザーの意思決定が必要な理由>
### 提案する修正(指摘が妥当な場合)
<具体的にどう書き換えるかの提示。短ければインラインdiff、長ければ「<関数名> の <処理> を <方針> に変更」>
---
このコメントをどう扱いますか?
- **適用**: Claudeが提案した修正を作業ツリーに反映
- **スキップ**: 何もせず次のコメントへ
- **さらに議論**: 修正方針を一緒に詰めたい / 別案を相談したい
#```
評価は **判断を押し付けない**。Copilotの指摘でも、コードベース全体の文脈や既存の慣習を踏まえると不要なことはある。Claudeは「自分はこう見える」を根拠付きで提示するに留め、最終判断は必ずユーザーに委ねる。
特に次のような指摘は **的外れ寄り** と判断する傾向が強い:
- 既に他の箇所で実施されているチェックの重複提案
- スタイル上の好みで、リポジトリの既存パターンと矛盾する提案
- パフォーマンス上の懸念だが、対象が明らかにホットパスでない箇所
- 「コメントを追加すべき」系で、コードが自明な場合
逆に次のような指摘は **採用寄り** と判断する傾向が強い:
- nullable/undefined/空配列の境界条件の見落とし
- 例外パス・エラーハンドリングの欠落
- セキュリティ的に明確に問題のあるパターン(SQLi、XSS、認証バイパス等)
- 既存の型定義・スキーマと矛盾する実装
ただし上記はあくまで傾向であり、最終的にはコードと文脈を見て判断する。
#### 5-3. ユーザー判断に応じた処理
**「適用」と回答された場合:**
`Edit` ツールで対象ファイルを修正する。複数ファイルにまたがる修正が必要なら、まずユーザーに「この修正は <他ファイル> にも変更が必要です。一緒に反映してよいですか?」と確認する。修正後、以下のように報告する:
#```
✅ 適用しました
- `<path>` を修正
- <変更概要(1行)>
次のコメント (i+1/N) に進みます。
#```
**「スキップ」と回答された場合:**
#```
⏭ スキップしました。
理由をメモしておきたい場合はその旨を伝えてください(最終サマリに含めます)。
次のコメント (i+1/N) に進みます。
#```
ユーザーが理由を伝えたら、後のサマリ用にメモしておく。
**「さらに議論」と回答された場合:**
その場でフリーフォームの対話に入る。Claudeは追加のコード調査・関連箇所の検索・別案の提示など、ユーザーの議論に応える。議論が収束したら、ユーザーに改めて「適用 / スキップ」のどちらにするかを確認し、確定してから次のコメントへ進む。
#### 5-4. 中断時の挙動
ユーザーが途中で「ここで一旦止めて」「中断して」と伝えた場合は、その時点までの結果をStep 6のサマリ形式でまとめ、未処理のコメントは「未処理: i件」として残す。作業ツリーは「適用」したものだけが反映された状態のまま、何も巻き戻さない。
### Step 6: 全件処理後のサマリ
すべてのコメントを処理(または中断)した後、以下を出力する:
#```
## Copilotレビュー対応 完了サマリ
PR: #123 [タイトル]
処理結果: 適用 P件 / スキップ Q件 / 議論後適用 R件 / 議論後スキップ S件 / 未処理 T件
### 適用した変更
- コメント 1: `src/foo.ts:42` — <変更概要>
- コメント 3: `src/bar.ts:88` — <変更概要>
- ...
### スキップした指摘
- コメント 2: `README.md:12` — <理由(ユーザーが述べた場合のみ)>
- ...
### 未処理(中断時のみ)
- コメント 7〜N
### 作業ツリーの状態
`git status --short` を実行して現在の変更を表示:
<git status の結果>
### 次のアクション
適用した変更をコミットする場合は `/auto-commit` スキルで分割コミットできます。
PRスレッド上の「Resolve conversation」操作は本スキルでは行っていません。レビュー応答が必要な場合はGitHub上で手動操作してください。
#```
`git status --short` は実行して結果を埋め込む(ユーザーが現在の変更状態を把握しやすくするため)。
## エッジケース
- **Copilotコードレビューを有効化していないリポジトリ**: Step 3の結果でCopilot bot 由来のスレッドが1件も得られない(Step 3末尾の「該当コメントが0件の場合」と同じ)。リポジトリ設定で有効化が必要かもしれない旨を補足してよい。
- **bot名のバリエーション**: Copilotのbot名は将来変わる可能性がある。`author.login` に `copilot` を部分一致で含むbotアカウント(末尾 `[bot]` を含む)を広めに拾ってよい。ただし `copilotxxx` のような無関係なユーザー名が含まれないよう、`login.startsWith("copilot-pull-request-reviewer")` または `login == "copilot[bot]"` 程度に限定する。
- **同一スレッドに複数コメントがある場合**: スレッド内の最初のコメントがCopilotであっても、その後に人間が返信していることがある。本スキルは **スレッド単位** で評価し、スレッドの最初のCopilotコメントを主指摘として、後続コメントは「議論の経過」としてコンテキスト表示する。返信コメント自体を独立した処理対象としない。
- **`isOutdated == true` のコメント**: 上述の通り処理対象に含める。提示時に Outdated バッジを表示し、Claudeの評価で「コメント時点と現状のコードが変わっている」旨を必ず触れる。すでに修正済みで指摘自体が解消されていることもあるため、その場合は「現状のコードでは既に解消済み」と評価しスキップを推奨する。
- **コメント本文が極端に長い場合**: そのまま全文引用する(要約しない)。Copilotの指摘は根拠を含めて読むことに意味があるため、勝手な要約で情報を落とさない。
- **適用しようとした修正が他の箇所と矛盾する場合**: 例えば「null check を追加せよ」という指摘に従うと、別の場所のロジック前提(必ず非nullで来る契約)が崩れる場合。修正適用前にClaudeが気づいたら、「この修正を入れると `<他箇所>` の前提と矛盾する可能性があります」と明示してユーザーに再確認する。
- **複数のコメントが同じ箇所を指摘している場合**: 1件ずつ処理する原則は変えない。ただし2件目以降を提示する際に「1件目で `<行X>` を修正済みです。本コメントは同じ箇所への別観点の指摘です」と前置きを入れる。
- **修正反映時に予期せぬビルド/型エラーを誘発しそうな場合**: Claudeが事前に気づける範囲で警告を出す。「この修正により `<関数>` のシグネチャが変わるため、呼び出し元 N箇所の更新が必要です。同時に反映しますか?」と確認する。
- **PRのレビュースレッド数が極端に多い場合(数十件超)**: 全件処理は時間がかかる旨を事前に伝え、「全件処理 / ファイル単位で絞り込み / 特定のファイルのみ」を選べるようにする。ファイル単位の絞り込みを選んだ場合、対象ファイルパスをユーザーに尋ねてから該当スレッドのみ処理する。
## 振る舞いの原則
- **承認なしに作業ツリーを変更しない**: Edit ツールでの修正は必ずユーザーが「適用」を選んだ後にのみ実行する。Claudeの評価が「妥当」であっても、勝手に修正を入れない。
- **コミット・pushはしない**: 本スキルは作業ツリーへの反映までを担当する。コミットは `/auto-commit`、pushはユーザーの手動操作に委ねる。これは「Copilot対応」「機能実装」「リファクタ」などをまとめてコミットしてしまうのを防ぐため。
- **PR上のスレッドを勝手にResolveしない**: 「Resolve conversation」操作(GraphQLの `resolveReviewThread` mutation)は本スキルでは実行しない。指摘への対応が完了したかどうかの判定はレビュアー側が行うのが本筋であり、被レビュー側が自分でresolveすることは慣習として避けたい。
- **判断を奪わない**: Claudeの評価はあくまで判断材料の提示。「適用すべき」「スキップすべき」と断定的に誘導せず、根拠を述べたうえで「Claudeはこう見ている」のトーンに留める。
- **Copilot以外のレビュアーは対象外**: 人間のレビュアーが残したコメントには本スキルでは触れない。人間とのやり取りは個別に対応する必要があるため、機械的な処理対象にしない。
- **全文引用を厭わない**: Copilotコメント本文・該当コードはケチらず全文を提示する。スクロールの手間より「情報を落として誤判断する」リスクのほうが高い。
- **対話途中で中断されても整合性を保つ**: 適用済みの修正はそのまま残し、未処理を明示する。巻き戻しはしない(やり直したい場合はユーザーが `git restore` で戻す)。
## 参考: なぜスレッド単位で処理するのか
GitHubのレビューコメントはスレッド構造を持つ。Copilotが残した最初のコメントに対して、後から人間が「これは違う、こういう理由でこのままで良い」と返信しているケースもある。スレッド単位で処理することで:
1. **解決状態を正確に扱える**: `isResolved` はスレッド単位の属性。コメント単位では取得できない。
2. **議論の経過を踏まえられる**: 既に人間が反論済みの指摘を、機械的に「採用」してしまう事故を防げる。
3. **PR上のUIと一致する**: GitHub UIでもスレッド単位で表示・解決されるため、ユーザーの認知モデルに合う。
そのため本スキルは `pulls/:number/comments`(コメント単位のRESTエンドポイント)ではなく、GraphQLの `reviewThreads` を使う。
使ってみた
あらかじめプルリクエストを作成し、実行してみました。
Claude Code
/handle-copilot-review
(以下がGithub上での修正提案になります)
具体的な修正内容は割愛しますが、期待通りの挙動になりました!
今回は以上になります。



