GitHub トリアージ は何をしますか?
リポジトリのオープンな GitHub Issue と Pull Request をトリアージします。オプションで準備完了の PR を先に処理し(パスするボット PR とメンテナー承認済み PR をマージ、未レビューの PR をレビュー)、次に既に解決済みの Issue をクローズ(解決した PR またはコミットを引用したコメント付き)、Issue とそれを修正する保留中の PR が互いに参照し合うようにし、ローカル限定で未解決の各 Issue に優先度と変更規模の見積もりを割り当てます。
使用するタイミング
- ユーザーが
/github-triageを実行し、リポジトリのオープンな Issue と Pull Request を整理または確認する場合。 - Issue のバックログが漂流している場合:解決済みの作業がオープンのまま、修正が Issue をクローズせずにマージされた、または Issue にリンクされていない PR が進行中。
- 準備完了の PR が積み上がった場合(パスする依存関係更新、承認済みで CI パスしている PR)、または PR が未レビューのまま放置されている場合。
使用すべきでないタイミング
- 自動的に呼び出さないでください。このスキルは元に戻せない GitHub への書き込み(PR のマージ、Issue のクローズ、コメントの投稿)を行い、明示的な呼び出し時にのみ実行します。
- GitHub 上で優先度や作業規模の ラベル を適用するために使用しないでください。優先度とサイズはローカルのみで表示され、投稿されることはありません(安全ルール参照)。
- 人間による最終マージ判断の代わりとして使用しないでください — すべてのマージは明示的な承認のために提案され、自律的には実行されません。
基本原則
- 書き込みはゲート制御。 最初に完全なトリアージを計算し、マージを含むすべての提案書き込みをレビュー用に提示し、ユーザーが承認するまで何も実行しません。
- クローズ前に証拠を確認。 具体的で引用可能な理由(マージ済み PR またはデフォルトブランチのコミット)なしに Issue をクローズしてはいけません。証拠が弱いか曖昧な場合は、Issue を未解決のままにしてレビュー用にフラグを立てます。
- 優先度とサイズはローカルに留める。 これらはユーザー向けの内部計画支援ツールであり、GitHub に書き込まれることはありません。
ワークフロー
フェーズ 0: 対象リポジトリを選択
gh auth status # gh が認証済みであることを確認
git rev-parse --is-inside-work-tree # PWD は git リポジトリか?
git remote -v # リモートを列挙
リモートの中から 異なる GitHub ホストのリポジトリ のセットを特定します。リモートが GitHub ホストであるのは、URL のホストが github.com であり、以下のいずれかの形式の場合です:
https://github.com/OWNER/REPO(.git)[email protected]:OWNER/REPO(.git)ssh://[email protected]:OWNER/REPO(.git)
それぞれを OWNER/REPO に正規化し、重複を排除します(フォーク設定では origin と upstream が異なる GitHub リポジトリを指している可能性があります;同じ OWNER/REPO を指す複数のリモートは 1 回としてカウントします)。
選択ルール:
| 状況 | アクション |
|---|---|
| 異なる GitHub リポジトリがちょうど 1 つ | デフォルトとして使用 — プロンプトを表示しない。 |
| git リポジトリでない、または GitHub リモートが 0 個 | ユーザーにトリアージする OWNER/REPO を尋ねる。 |
| 異なる GitHub リポジトリが複数 | AskUserQuestion を使用してユーザーに OWNER/REPO を選択させる。 |
GitHub Enterprise ホストは確実に自動検出できません。ユーザーが GHE インスタンスで作業している場合は、
OWNER/REPOを尋ね、GH_HOSTを設定するか、ghの設定済みホストを使用するよう指示してください。続行する前に、解決されたリポジトリをユーザーに確認します。
結果を REPO="OWNER/REPO" として保存し、すべての gh 呼び出しに -R "$REPO" を渡します。使用前に ^[A-Za-z0-9._-]+/[A-Za-z0-9._-]+$ に対して検証し、不正な形式や悪意のあるリモート URL がコマンドに流れ込まないようにします。
フェーズ 1: Issue とコンテキストを収集
# オープン Issue(デフォルトでは gh issue list は PR を除外)
gh issue list -R "$REPO" --state open --limit 1000 \
--json number,title,body,labels,assignees,comments,reactionGroups,createdAt,updatedAt,url
# オープン PR — 「保留中の修正」候補(Issue フェーズ用)および PR トリアージ(フェーズ 2 用)
gh pr list -R "$REPO" --state open --limit 1000 \
--json number,title,body,author,isDraft,reviewDecision,latestReviews,\
mergeable,mergeStateStatus,statusCheckRollup,labels,createdAt,headRefName,url,closingIssuesReferences
# 最近マージされた PR — 「既に解決済み」候補
gh pr list -R "$REPO" --state merged --limit 300 \
--json number,title,body,mergedAt,url,closingIssuesReferences
closingIssuesReferences は、PR がクローズするようリンクされている Issue をリストします — PR 本文内の GitHub のクローズキーワード(close/closes/closed、fix/fixes/fixed、resolve/resolves/resolved)、または手動の UI リンクによって設定されます。これは最も強力なシグナルです。これでカバーされない Issue については、デフォルトブランチのコミットメッセージも検索します。デフォルトブランチを選択したリポジトリから権威的に解決します(ローカルの origin/HEAD からではなく、これは未設定または間違ったリモートを指している可能性があります):
default_branch=$(gh repo view "$REPO" --json defaultBranchRef --jq .defaultBranchRef.name)
# Issue 番号をアンカーし、#12 が #120、#123 などに一致しないようにする
git log --oneline "origin/$default_branch" \
| grep -iE "(close|fix|resolve)[sd]? +#<N>([^0-9]|$)"
フェーズ 2: オープン Pull Request のトリアージ(オプション)
Issue の 前に PR を処理します:ここで準備完了の PR をマージすると、Issue フェーズでの「既に解決済み」チェックが、それらのマージが着地した作業を認識します。
オープン PR がない場合、このフェーズをスキップします。それ以外の場合は、オープン PR を要約し、ユーザーに今 PR を処理するかどうかを尋ねます(AskUserQuestion:PR を処理 / Issue にスキップ)。スキップされた場合は、Issue 分類に直接進みます。
レビュー、CI、およびマージ状態から各オープン PR を分類します。以下のフィールド形状は、gh pr ... --json が実際に返すものです — 直感ではなくこれらに依存します:
- マージ準備完了 =
mergeable == "MERGEABLE"かつmergeStateStatus == "CLEAN"かつ CI がブロックしていない(以下)。CLEANは GitHub サーバーサイドの「競合なし、遅れていない、ドラフトではない、必須チェックパス」の判定であり、他のmergeStateStatus(BEHIND、UNSTABLE、BLOCKED、DIRTY、DRAFT…)は 準備完了ではありません。mergeable == "UNKNOWN"(GitHub はマージ可能性を遅延再計算します。特に別のマージ直後)は 準備完了ではない として扱います — 短時間再ポーリングするかスキップします。決してこれを基にマージしてはいけません。 - CI がブロックしていない —
statusCheckRollup(__typenameをキーとする)をスキャンし、実際の問題がある場合のみ PR を拒否します:ハード障害(conclusionがFAILURE/CANCELLED/TIMED_OUT/ACTION_REQUIRED/STARTUP_FAILURE/STALEのCheckRun、またはstateがFAILURE/ERRORのStatusContext)、または まだ実行中 のもの(statusがQUEUED/IN_PROGRESS/WAITING/PENDINGのCheckRun、またはstateがPENDING/EXPECTEDのStatusContext— 待機、まだマージしない)。SUCCESS、NEUTRAL、SKIPPEDは 問題なし であり、ブロックしてはいけません(例:依存関係更新でNEUTRALを報告する CodeQL 実行 — 緑の Dependabot PR はNEUTRALな CodeQL チェックでCLEAN)。空のロールアップは CI なし です — これは異なる状態であり、決して準備完了として扱われません。mergeStateStatus == "CLEAN"は既に 必須 チェックステータスを反映しています。ロールアップを使用して、失敗/保留中の 非必須 チェックをキャッチします。 - ボット/自動化 =
author.is_bot == true。自動マージ 許可リスト を、author.loginに対してghのレンダリングを正規化した後で照合します — 先頭のapp/と末尾の[bot]を取り除きます(gh は Dependabot を一部のバージョンでapp/dependabot、他のバージョンでdependabot[bot]として返します;両方をdependabotに正規化します)。デフォルトで許可リストに含まれるもの:dependabot、renovate、およびユーザーが指定したもの。許可リストにないボットからのパスする PR は報告され、マージは提案されません。 - メンテナー承認済み =
latestReviewsにstate == "APPROVED"のエントリがあり、そのauthorAssociationがOWNER/MEMBER/COLLABORATORであり、author.loginが PR の作成者ではない。reviewDecision == "APPROVED"だけを 使用しないでください:これはブランチ保護によって駆動され、必須レビュールールがないリポジトリではnullになるため、過信(書き込みアクセスを確認できない)と本物の承認を見逃す、の両方を引き起こします。 - 未レビュー =
latestReviewsに、PR 作成者以外からのAPPROVED/CHANGES_REQUESTEDエントリがない(フォークの「レビュー無効」ボットコメントはレビューではありません)。
| カテゴリ | 条件 | 提案アクション |
|---|---|---|
| マージ可能なボット PR | 許可リストにあるボット + 準備完了 + ドラフトでない | 段階的、順序通りのマージ を提案 |
| 承認済みで準備完了 | メンテナー承認済み + 準備完了 + ドラフトでない | マージを促す |
| 未レビュー | 非ボット + 作成者のみがレビュー(またはレビューなし)+ ドラフトでない | レビューサブエージェントの起動 を提案 |
| 作業が必要 | ドラフト、ハード CI 障害、保留中 CI、競合、遅れ、変更要求、または準備完了でないボット PR | 報告のみ — アクションは提案しない |
(「準備完了」は既に CI 非ブロックを含んでいます。レビューサブエージェントは人間作成の PR 用です — 準備完了でないボットの依存関係更新は「作業が必要」として報告され、レビューされません。)
分類された PR を提示し、AskUserQuestion を介して適用可能なアクションを提案します。
段階的、順序通りのマージ(ボット PR および承認済み準備完了 PR):最初にマージセットとマージ方法を確認し(マージは元に戻せません)、次に 一つずつ、最も古いものから マージします。リポジトリが許可する方法を選択し、許可しない場合は安全に失敗します:
gh repo view "$REPO" --json mergeCommitAllowed,squashMergeAllowed,rebaseMergeAllowed # -R ではなく位置指定リポジトリ
各 PR について順に、マージ直前に再検証 します(各マージ後に状態が変化します — 着地した PR は次の PR を BEHIND、競合状態、または再計算中にする可能性があります)、同期的に マージし、着地したことを確認してから 次に進みます:
gh pr view <N> -R "$REPO" --json isDraft,reviewDecision,mergeable,mergeStateStatus,statusCheckRollup
# まだ準備完了(ドラフトでない、mergeable == MERGEABLE、mergeStateStatus == CLEAN、CI 非ブロック)の場合のみ続行
gh pr merge <N> -R "$REPO" --<method> # --auto も --admin も決して使用しない
gh pr view <N> -R "$REPO" --json state # 次の PR に進む前に "MERGED" を期待
PR が準備完了でなくなった場合(mergeable == "UNKNOWN" を含む)、マージが着地しなかった場合、または必要なチェックがすべてグリーンでない場合は停止して報告します — 決して強制、--admin、--auto、またはチェックのスキップを行いません。ボット PR の場合は、依存関係とバージョンジャンプ(例:メジャーバンプ)をゲートで表面化し、ユーザーがコンテキストを持って判断できるようにします。
レビューサブエージェント(未レビュー PR):ユーザーがオプトインした場合、PR ごとに 1 つの Agent を起動します — すべて同じアシスタントメッセージ内で並列実行されます。各サブエージェントは 1 つの PR の差分をレビューし、構造化されたレビューを返します。それぞれを作業ディレクトリの github-pr-<number>-review.md に書き込みます(その PR の以前のファイルがあれば上書きします)。レビューは 読み取り専用で、GitHub に投稿されることはありません。サブエージェントプロンプト、レビュールーブリック、およびファイル形式については、references/reviewing-prs.md を参照してください。
マージ後は、マージ済み PR リスト(フェーズ 1 の --state merged クエリ)を 再取得 し、Issue フェーズがそれらのマージで解決された Issue を検出できるようにします。
フェーズ 3: 各オープン Issue を分類
すべてのオープン Issue を正確に 1 つのバケットに分類します。
バケット A — 既に解決済み(作業は着地したが、Issue はオープンのまま)。 具体的な証拠が必要です。単一の弱いシグナルよりも裏付けを優先します:
- マージ済み PR が
closingIssuesReferencesに Issue をリストしている、またはそのタイトル/本文がクローズキーワードとともに#Nを参照している。(最強。) - デフォルトブランチ上のコミットがクローズキーワードとともに
#Nを参照している。 - Issue が要求する動作が 現在のコードに明らかに存在する — Grep/Read で関連コードを読み取って確認し、推測しない。異なる実装または部分的な実装では Issue は解決されません。
→ 提案書き込み:解決 PR/コミットを指定するコメントを付けて Issue をクローズ。
gh issue close <N> -R "$REPO" \
-c "#<PR>(<簡単な理由>)で解決されました。変更が $default_branch にマージされたためクローズします。"
バケット B — 保留中の PR が解決する見込み(オープン PR が Issue に対応している)。
いずれかの方向で検出します:オープン PR の closingIssuesReferences に Issue が含まれている;Issue の本文/コメントが PR にリンクしている;またはオープン PR が Issue の説明と同じものを明らかに修正している。目標は Issue と PR が 互いに参照すること です — 真のギャップのみを埋め、非破壊的な書き込みを優先します:
- どちらの方向にも参照がない → 参照がない側にポインターコメント(非破壊的)を投稿します。
#<PR>/#<N>への言及は、GitHub が相手のタイムラインにミラーリングする相互参照を作成します。gh issue comment <N> -R "$REPO" -b "#<PR> で修正が進行中です。" - 少なくとも一方の方向に既にリンクがある → 「既にリンク済み — アクションなし」と記録。
PR 本文を編集しないでください。ユーザーが明示的に PR にマージ時に Issue を 自動クローズ させたい場合を除きます。コメントは参照を確立しますが、自動クローズは トリガーしません — 自動クローズをトリガーするのは、PR 本文 または コミットメッセージ のクローズキーワードのみです。ユーザーがオプトインした場合、説明を決して上書きしないでください:編集の直前に本文を再取得し、stdin 経由で渡します。これにより、信頼できない PR テキストがシェル補間された文字列を経由することがなくなります:
body=$(gh pr view <PR> -R "$REPO" --json body --jq .body)
printf '%s\n\nCloses #%s\n' "$body" "<N>" | gh pr edit <PR> -R "$REPO" --body-file -
既に存在するリンクを重複させないでください。
バケット C — 未解決(解決も保留中の PR もなし)。 ローカル限定 で優先度と変更規模見積もり(次のセクション)を割り当てます。
フェーズ 4: 未解決 Issue のスコアリング(ローカル限定)
優先度 — Critical / High / Medium / Low。以下を考慮:
- 影響/重大度 — セキュリティ、データ損失、クラッシュ、または正確性のバグは機能強化より上位。ドキュメント/外観は最下位。既存のラベル(
security、bug、crash、regression)は強力なシグナル。 - 波及範囲 — 影響を受けるユーザー/ワークフローの数。
- シグナル — リアクション(👍)、重複レポート、継続的なアクティビティがある経過期間。
- 緊急性 — リリースをブロックする、期限がある、またはアクティブなリグレッションがある。
変更規模 — 労力のプロキシ。推定 総変更行数(追加+削除、生成/ベンダーファイルを除く)から Kubernetes/Prow 式の T シャツバケット size/* で表現:
| バケット | 推定変更行数 |
|---|---|
| size/XS | 1–9 |
| size/S | 10–29 |
| size/M | 30–99 |
| size/L | 100–499 |
| size/XL | 500+ |
Issue の説明とチームのコンテキストから判断します — 実際のコード変更は必要ありません。単一の不足タイポのように明白でない限り、XS をデフォルトにしないでください。
フェーズ 5: 人間によるレビューのために提案を提示
結論を明確な形式で表示します。各セクションはオプションであり、関連データがある場合のみ表示します:
マージ準備完了 — アクションが必要 (#{count})
| # | タイトル | 作成者 | 理由 |
|---|---|---|---|
| … | … | … | … |
→ gh pr merge <N> -R "$REPO" --squash
準備完了、承認済み — アクションが必要 (#{count})
| # | タイトル | 承認者 |
|---|---|---|
| … | … | … |
レビュー準備完了 — サブエージェントを起動 (#{count})
| # | タイトル | 作成者 |
|---|---|---|
| … | … | … |
作業が必要 (#{count})
| # | タイトル | 状態 |
|---|---|---|
| … | … | … |
既に解決済み — クローズを提案 (#{count})
| # | タイトル | 根拠 |
|---|---|---|
| … | … | … |
保留中の PR にリンク (#{count})
新しくリンクしたもの、既にリンク済みだったものをそれぞれ示します。
未解決 Issue
| # | タイトル | 優先度 | 規模 |
|---|---|---|---|
| … | … | … | … |
提案された各書き込みアクションについて、確認を求めます(AskUserQuestion)。承認された場合のみ実行します。
安全ルール
- すべての書き込み前にユーザー確認。
ghを使用した GitHub への書き込み(Issue/PR の操作、コメント/ラベルの追加)は、すべてのトリアージ結果を計算して表示した 後、各アクションごとに明示的な承認を求める。 - 優先度と規模はローカルに留める。 これらはユーザーにテキストで表示されます。GitHub にラベルやコメントとして書き込まないでください。表示するときは「ローカル限定」と明確にラベル付けしてください。
- クローズ前に証拠を確認。 解決された各 Issue は、修正をマージした PR(
closingIssuesReferences、タイトル/キーワード)またはデフォルトブランチのコミット(コミットメッセージのクローズキーワード)への引用可能なリンクを持っていなければなりません。推測しないでください。 - 不明な場合は閉じない。 証拠が弱い場合(あいまいな Issue の言及、確認できない修正)は、Issue を未解決のままにしてレビュー用にフラグを立ててください。クローズはテストやデプロイの検証を必要としませんが、リンクされた証拠が必要です。
- マージは決して自動化しない。 各マージは最初に承認を得るために表示されます。
--autoまたは--adminフラグは使用しないでください。マージのたびにプッシュの直前に再検証します。 - 強制プッシュや管理者バイパスは禁止。
gh pr mergeで--adminを渡すことは絶対にしないでください — マージは保護ルールを尊重し、スキップしてはいけません。 - PR の説明は決して上書きしないでください。 ユーザーが Issue の自動クローズをオプトインした場合でも、編集の直前に
gh pr viewで本文を取得し、stdin 経由で渡します。