to-pr
対象のブランチにまだプルリクエスト(PR)が開かれていない場合は新しくPRを作成し、既に開かれている場合はそのPRの説明を自動的に更新します。どちらのパスも同じ方法で機能します。すべてのセクションを実際の差分とコミット履歴に基づいて記述し、対象リポジトリのPRテンプレート構造を尊重し、内容を捏造することは決してありません。どちらのパスも、呼び出し後の確認を求めません。/to-pr を実行することが唯一の承認ステップです。これはユーザーが1人であることを前提としているためです。
依存関係
認証済みの gh CLIが必要です。すべてのパスでこれを使用します(gh pr view、gh pr create、gh pr edit、gh api、gh repo view)。git と base64 も使用されますが、これらはClaude Codeを実行できるすべてのマシンに標準でインストールされているため、ここではリストしません。
使用するタイミング
- ユーザーがPRを開く、作成する、または更新するように依頼した場合、あるいはPRの説明を入力または更新するように依頼した場合。
- ユーザーが
/to-prと入力した場合(ターゲット、--ready/--draft、--baseを伴う場合も含む)。 - 新しいコミットが最後に説明を入力した後にプッシュされたり、差分や規約の変更により以前の説明が古くなった場合に、テンプレートの構造に沿って既に入力された説明を更新する場合。
--ready、--draft、または--baseを使用して、既存のPRのレビュー準備完了状態またはベースブランチを切り替える場合(他の変更は意図しない)。
使用しないタイミング
- 明示的に指定されたターゲット(PR番号またはURL)が実際のPRに解決されない場合。エラーとして報告してください。新しいPRを作成するようにフォールバックしないでください。タイプミスによって無関係なPRが作成されることがあってはなりません。
- ターゲットのテンプレートとは異なる構造で書かれた実際のコンテンツを置き換える場合、またはこの入力が実際には関係のないPRのコンテンツに触れる場合。それは入力ではなく書き換えです。触れる前にユーザーに確認してください。
- テンプレートの「Screenshot」(またはその他の視覚的証拠)セクション。テンプレートにあるものをそのまま残してください。このスキルはライブブラウザセッションをバックエンドとしていないため、「本来あるべき姿」の画像を生成できません。
- クローズ済みまたはマージ済みのPR、およびGitHubの複数テンプレート選択フォルダー(
.github/PULL_REQUEST_TEMPLATE/*.md)。単一ファイルの.github/PULL_REQUEST_TEMPLATE.mdのみが読み取られます。
引数の文法
args から3つのオプショナルな要素を、任意の順序または位置でスキャンします。
--readyまたは--draftトークン。両方が存在する場合はエラーです。報告して停止してください。--baseトークンの直後に続くブランチ名の値。- 1つの余剰トークン。ターゲット(PR番号またはURL)です。複数の余剰トークンがある場合は曖昧です。報告して停止してください。
ルーティング
- ターゲットが指定された場合(明示的なPR番号またはURL):常に
gh pr view <target> --json body,url,number,headRefName,baseRefName,title,closingIssuesReferencesで直接解決します。これは常に更新パスです。明示的なターゲットは、すでに存在するPRを指定します。 - ターゲットが指定されなかった場合:現在のブランチに対して
gh pr view --json body,url,number,headRefName,baseRefName,title,closingIssuesReferencesを実行します。成功した場合は、そのPRに対して更新パスを実行し、この同じ結果を再利用します。失敗した場合(このブランチに開かれているPRがない場合)、作成パスを実行します。
作成パス
- ベースブランチを解決します。
--baseで上書きされない限り、次の手順で行います。- 現在のブランチの上流追跡リファレンスを読み取ります:
git rev-parse --abbrev-ref --symbolic-full-name @{u}(失敗は無視します。上流が設定されていない場合があります)。 - 現在のブランチとは異なる短い名前のブランチを指している場合にのみ使用します(リモートプレフィックスを削除します。例:
origin/feature-x→feature-xとして比較します)。同じ名前の追跡は、プッシュ/プルのための配管であり、ターゲットのシグナルではありません。 - それ以外の場合は、リポジトリのデフォルトブランチにフォールスルーします:
gh repo view --json defaultBranchRef -q .defaultBranchRef.name。 - 意図的に祖先検出ヒューリスティック(候補ブランチ間の
git merge-baseの距離を比較するなど)は使用しません。コミットグラフの形状からターゲットを推測することは、以下のタイトル導出で拒否された脆弱性とまったく同じであり、ベース解決でそれを再導入すべきではありません。
- 現在のブランチの上流追跡リファレンスを読み取ります:
- 必要に応じてブランチをプッシュします。上流がすでに設定されているが、ローカルコミットがその上にない場合(
git rev-list @{u}..HEAD --count> 0)、git pushは明確です。上流が設定されていない場合は、git remoteがリストする単一のリモートにプッシュします(git push -u <remote> HEAD)。複数のリモートが設定されている場合は曖昧です。報告してどれかを尋ねてください。originを推測しないでください。 - 解決されたベースより前の最初のコミットからタイトルを導出します。「タイトルの導出」を参照してください。
- 本文を作成します。「本文の作成」を参照してください。テンプレートはステップ1で解決されたベースブランチから取得します。
- PRを開きます:
gh pr create -B <base> --title "<title>" --body-file <file> --assignee @me。--readyが指定されていない限り、--draftを追加します。 - 報告します。新しいPRのURL、タイトル、ベース、ドラフト/準備完了状態、どのタイトル階層が適用されたか(そのままの文言 / 文書化された規約 / 推測された規約)、ベースより前にマージコミットが検出されたかどうか(情報提供のみ。「タイトルの導出」を参照)、および自分にアサインされたことを報告します。
更新パス
- PRの現在の本文とメタデータを取得します(上記のルーティング時にすでに実行済み)。
urlフィールド(https://github.com/<owner>/<repo>/pull/<n>)はPR自身のリポジトリを指します。これはローカルでチェックアウトされているリポジトリとは異なる場合があります。ターゲットは任意のリポジトリへの完全なURLになり得るためです。 --baseが指定された場合は、最初にターゲットを変更します:gh pr edit <target> --base <new-base>。本文を作成する前にこれを行ってください。次のステップでのテンプレート取得が、古いベースではなく新しいベースを読み取るようにするためです。--readyまたは--draftが指定された場合は、PRの状態を切り替えます:--readyの場合はgh pr ready <target>、--draftの場合はgh pr ready <target> --undo。- 本文を作成します。「本文の作成」を参照してください。テンプレートはPRの
baseRefName(ステップ2が実行された場合は変更後のベース、そうでない場合は元のベース)から取得します。 - 完成した本文をスクラッチファイルに書き込み、1回の呼び出しでPRを更新し、同時に自分自身にアサインします:
gh pr edit <target> --body-file <file> --add-assignee @me。 - 報告します。どの空白が埋められたか、どのチェックボックスがチェックされたか、どのセクションが触れられずに残されたかとその理由、適用されたターゲット変更やドラフト状態の変更、およびPRが自分にアサインされたことを報告します。これにより、誰かがPR自体を読む前に、その理由が明らかになります。
本文の作成
両方のパスで共通です。「テンプレート」とは、ターゲットリポジトリ自身の .github/PULL_REQUEST_TEMPLATE.md を指し、呼び出しパスがすでに決定したベースブランチ(作成パスのステップ1、または更新パスの baseRefName)から取得されます。ヘッドブランチやルート/docs/ バリアントからは決して取得しません。
gh api "repos/<owner>/<repo>/contents/.github/PULL_REQUEST_TEMPLATE.md?ref=<base>" \
--jq .content | base64 --decode
- ファイルが存在する場合は、すべての見出し、HTMLコメント、チェックボックスをそのままの位置に保持します。
- API呼び出しが404を返す場合は、組み込みのフォールバック構造を使用します:
## What changed、## Why、## Testing。 - これを
gh pr create自身の-T/--fill/--fill-verboseに委譲しないでください。-Tはローカルファイルの生テキストを空白を埋めずにダンプし、--fill/--fill-verboseはテンプレートを認識せずにコミットメッセージから自動入力します。常に完全な本文を作成し、--body-file/-Fで渡します。
更新パスでのみ、テンプレート自身の構造の後に追加されたもの(CI生成セクション、デプロイプレビューリンク、または本文に続くその他のもの)は、バイト単位で最後に保持します。これを位置的に、テンプレートの最後のセクションの後にあるものとして検出します。特定のセクション名でマッチさせることは決してしません。唯一の例外は、AI帰属行です。これは、PRの作成または生成についてAIアシスタントやツールに帰属するトレーラー(例:「🤖 Generated with [Claude Code]」、「CoAuthored-By: 」、「Assisted by Copilot」)です。これは、どのようにPRが作成されたかの成果物であり、ターゲットリポジトリ自身のコンテンツではないため、その内容に基づいて認識します。固定のツール名リストでは認識しません。また、本文を作成する際にこれを書くことは決してしません。作成パスでは、まだ競合するものがないため、このステップは適用されません。
空白を埋める前に、差分の証拠を1回の呼び出しで収集します。実際の差分は、このスキルが行う他のすべてのルックアップとは異なり、任意に大きくなる可能性があります。そのため、このセッションに直接取り込むのではなく、general-purpose サブエージェントにそれを読み取るようにディスパッチします。サブエージェントのモデルを上書きしないでください。「決して発明しない」という根拠が維持されなければならないこの証拠は、機械的な抽出ではなく判断を要するものであり、品質をより安価な階層と交換する場所ではありません。
サブエージェントに、呼び出しパスがすでに解決したベースブランチに対して git log --first-parent <base>..HEAD(件名だけでなく、完全なコミットメッセージ)と git diff <base>...HEAD を実行するようにタスクを与え、その出力に基づいて明確にラベル付けされたセクションでのみ報告するように指示します。
- Change summary — 差分が実際に何をするか。ファイルごと、または論理的にグループ化して。変更の目的を決して書かない。
- Testing evidence — 追加または変更されたテスト、差分が暗示する実行コマンド、差分またはコミットメッセージに表示される手動検証手順。カテゴリ全体を省略するか、一般的な定型文で埋めない。
- Commit messages — 各コミットメッセージをフェンスで囲まれたコードブロック内に、文字通りに再現する。言い換えたり、圧縮したり、要約したりしない。たとえ長さの制約があっても。以下のチケット推論フォールバックは正確なフッターテキストに依存しているため、
Refs #9をCloses #9のように読み間違えることは、このカテゴリが存在するまさにその失敗です。 - Ticket references — コミットメッセージまたは差分自体に現れるチケット番号またはトラッカーURL。
このレポートは証拠であり、特定のテンプレートのための散文ではありません。サブエージェントは、この実行がどのテンプレートを埋めるかを知らないため、ターゲットのセクション名や構造を決して想定してはなりません。証拠を実際のテンプレートの空白にマッピングすることは、以下のこのスキル自身の仕事です。
レポートを信頼する前の安価なクロスチェックとして、このセッションで直接 git diff --stat <base>...HEAD を実行し(ファイルリストと行数のみ。完全な差分は不可)、それをサブエージェントの変更概要と比較します。不一致(例えば、--stat が示すよりも少ないファイルしか言及されていない場合)は、不完全なレポートから本文を作成するのではなく、サブエージェントを再実行することを意味します。
すべての空白を実際の何かに基づいて埋めます。決して発明してはいけません。
- What changed — 差分証拠サブエージェントの変更概要。
- Why — 以下のチケット推論ステップを参照。
- Testing — 差分証拠サブエージェントのテスト証拠。カテゴリが省略された場合は、Testing を定型文で埋めずに空のままにします。
- テンプレートが定義するその他のチェックボックスや空白は、差分証拠サブエージェントのレポートが実証的にサポートするものだけを埋めます。残りはチェックせず、触れずに残します。
- テンプレートの非空白コンテンツ(固定の免責事項、Screenshotセクションなど)は、テンプレートにある通りにそのまま残します。差分が実証的にサポートする場合にのみ埋め、決して発明しません。
Why のチケット推論は、トラッカーの規約に従って、正確に1つのフォールバックパスで埋めます。
- ターゲットリポジトリに文書化されたトラッカーまたはコミットフッターの規約を探します。
CONTRIBUTING.md、CLAUDE.md/AGENTS.md、またはそれを説明するdocs/ページなど。 - 存在する場合は、このPRをその規約の用語でチケットに結びつける証拠を探します。
closingIssuesReferences、ブランチ名、差分証拠サブエージェントのチケット参照、または規約の形式に一致するコミットメッセージフッターなど。規約に正確に従います。例えば、Closes #<n>/Refs #<n>フッター、またはリンクされたトラッカーURL。 - 規約が文書化されていない場合、または文書化されていてもこのPRに該当するチケットがない場合は、同じようにフォールバックします。Why を、差分証拠サブエージェントの変更概要とコミットメッセージから構築された、チケット参照のない平易な散文の要約として書きます。1つのフォールバックパスであり、2つではありません。
タイトルの導出
作成パスのみ。更新パスは既存のPRのタイトルに触れることはありません。
gh pr create 自身の --fill-first は決して使用しないでください。これには文書化されたオープンバグ(cli/cli#10604)があり、マージコミットを含むブランチでは、git log のデフォルトの走査が、実際に現在のブランチで行われた最初のコミットではなく、マージされたブランチからのコミットを「最初」として表面化させる可能性があります。代わりに、--first-parent を使用して自分で同等の処理を実行します。これにより、この問題を無条件に回避できます。
git log --reverse --first-parent <base>..HEAD --format=%s
最初の行が最初のコミットの件名です。
コミット数に関係なく、ベースより前にマージコミットがないか確認します:git log --first-parent <base>..HEAD --merges。空でない場合は、情報として開発者に報告します。作成をブロックしたり、タイトル導出を変更したりすることはありません(上記の --first-parent によりすでに影響を受けません。たとえその最初の親コミット自体がマージであっても)。これは、マージ時にリベースマージの競合になる前に、非線形履歴を表面化させるだけです。
上記の %s ログが1行しかない場合、ブランチは単一コミットです。タイトルはその件名をそのまま使用します。完了です。以下の階層選択はスキップします。
複数コミットのブランチでは、優先順位に従ってフォーマット階層を選択し、最大でも1つを適用します。
- 文書化された規約。 上記の「Why」ステップで文書化されたチケット推論規約を確認するのと同じ方法で、ターゲットリポジトリに文書化されたPRタイトル規約がないか確認します。文書化されたコミットメッセージ形式の規約(例:
AGENTS.md/CLAUDE.mdでのConventional Commits)も、リポジトリのドキュメントがPRタイトルとコミットメッセージを明示的に区別していない限り、文書化されたPRタイトル規約としてカウントされます。 - 推測された規約。 文書化された規約が適用されない場合にのみ:
gh pr list --state merged --base <resolved-base> --json title -L 30。30はgh pr list自身のデフォルトの結果制限と一致するため、サンプルサイズはツールの自然なページに追従し、任意の数値ではありません。結果が5未満の場合、この階層は完全にスキップします。5未満のサンプルでは、共有プレフィックスは偶然である可能性が規約である可能性と同じくらい高いためです。
[以下、翻訳がトランケートされました]