mcpField
S
stacked-prs

stacked-prs

github.com/mathews-tom開発33843 回インストール今日更新
リポジトリ

stacked-prs について

Stacked PRs は、依存関係のあるプルリクエストのスタックを作成、公開、同期、検証するスキルです。ブランチの祖先関係とプロバイダー上のレビュー基準を分けて扱い、最初のアダプターとして GitHub の gh を記載し、マージとクリーンアップを ship-workflow に委任します。

主な機能

  1. 01ブランチと PR スタックの構成確認
  2. 02PR の公開とベースブランチ修正
  3. 03期待する旧値のリースによるリスタック
  4. 04レビュー可能なスタック単位の検証
  5. 05コミットトレーラーでスタック識別子を管理
  6. 06マージとクリーンアップを ship-workflow に委任

活用シーン

  1. 01依存ブランチを PR スタックとして公開
  2. 02親ブランチ変更後のスタック同期
  3. 03スタック構成とレビュー準備状況の確認
  4. 04承認済みスタックの委任マージを準備

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/mathews-tom/armory --skill stacked-prs

インストール後、Claude Code で/stacked-prsを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

evals/
cases.yaml
references/
github-native.md
merge-discipline.md
metadata-format.md
provenance.md
provider-adapters.md
stack-model.md
sync-algorithm.md

詳細

スタック PR

ブランチのトポロジーを損なうことなく、スタックされたプルリクエストを作成、公開、同期、検証し、既存のスタックをマージする際に必要となるトポロジー、出自、ネイティブなメンバーシップを判断します。

パッケージの識別情報はプロバイダーに依存しません。ブランチの祖先関係の正本は Git であり、レビューのベースに関する正本はプロバイダーの PR メタデータです。最初に文書化されているプロバイダーアダプターは、gh を介した GitHub です。

既存の手動スタックまたは GitHub ネイティブスタックのマージ、マージ後の昇格とリターゲット、クリーンアップを実行するのは、ship-workflow スキルのスタックグラフ実行のみです。このスキルは明示的なスタック判断パケットを作成し、§5 でその実行に委任します。独自の手動マージやクリーンアップ手順はありません。

参照ファイル

ファイル内容読み込むタイミング
references/stack-model.mdスタックの推論、明示的な順序付け、ネイティブスタックの検出、明示的なスタック判断パケットスタックの確認、公開、検証、または委任を行う場合
references/provider-adapters.mdプロバイダーアダプターの契約と、PR の一覧表示、作成、リターゲット、確認に使う GitHub gh コマンドPR の作成、リターゲット、確認を行う場合
references/sync-algorithm.mdスライスの証明、期待される旧値のリース、スタンドアロンのリスタック手順親ブランチまたはベースが移動した後にスタックを同期する場合
references/merge-discipline.md親優先のマージ規則、マージの証明、保持、および委任された実行が適用するエンドポイント選択対象と結果の意味を判断する場合
references/metadata-format.md任意のメタデータスキーマと検証規則.stack-prs.yaml が存在する場合、または推論が曖昧な場合
references/provenance.mdコミットトレーラーによるスタック識別情報、スタンプ付与、検証、マージ方式との連動作成、分割、同期、またはマージ方式の選択を行う場合
references/github-native.mdネイティブスタックの検出、リンクの適格性、ネイティブ同期、ネイティブプレフィックスのポリシーGitHub ネイティブスタックが要求または検出された場合

使用する場面

このスキルを使用する別のパッケージを使用する
依存関係のある複数のブランチで、親ブランチをベースとした PR が必要な場合独立した PR が 1 件の場合は ship-workflow
機能ブランチを、レビュー可能な依存関係のあるブランチに分割する必要がある場合コードが存在する前にタスクを計画する場合は task-decomposer
既存のスタックで、リベース、正しい親ブランチへのリターゲット、検証、またはマージ範囲の判断が必要な場合1 件の PR の差分をレビューする場合は pr-review
既存のスタックをマージするか、マージ後にクリーンアップする必要がある場合(§5 で委任)無関係なブランチのクリーンアップには一般的な Git コマンド

コアのルール

  • どのワークフローを実行する場合も、最初に git rev-parse --show-toplevel を実行してください。
  • リベース、プッシュ、PR の作成、PR のターゲット変更を行う前に、git status --porcelain を実行してください。
  • ユーザーが操作を調査のみに明示的に限定していない限り、作業ツリーに変更がある場合は停止してください。
  • 推測した祖先関係より、既存 PR の baseRefName を優先してください。
  • <base> は origin/HEAD ではなく、ルート PR の baseRefName(gh pr view <root-pr> --json baseRefName --jq .baseRefName)から解決してください。スタックの幹ブランチは、リポジトリのデフォルトブランチとは限りません。
  • 親ブランチの推定が曖昧な場合は、明示的なブランチ順序または .stack-prs.yaml を使用してください。
  • git push --force を単独で使ったり、--force-with-lease を単独で使ったりしないでください。書き換えたヘッドは、--force-with-lease=refs/heads/<branch>:<expected-old-oid> を指定してプッシュしてください。
  • スタックブランチを手動で削除しないでください。証拠に基づくクリーンアップは委任された実行(§5)で行います。
  • このスキルが作成または分割するすべてのコミットに、Stack-Id と Stack-Position のトレーラーを付与してください。ID は .stack-prs.yaml からコピーするか、存在しない場合は一度だけ生成してください。
  • このスキルが作成したスタックのランディングを委任する前に、トレーラーが存在し、一貫していることを確認してください。
  • ランディングを判断する前に、Inspect 中にすべてのオープンなスタック PR についてネイティブスタックへの所属を確認してください(references/stack-model.md § Native Stack Detection)。
  • ノードのマージ方法として squash を選ぶ前に、プロバイダーの squash メッセージポリシー(squash_merge_commit_message)を確認してください(references/provenance.md § Merge Mode Coupling)。

GitHub ネイティブのスタックモード

GitHub ネイティブのスタックは、同一リポジトリ内でのみ使用できます。手動の Armory スタックを拡張するものであり、来歴トレーラー、.stack-prs.yaml、またはプロバイダーに依存しないワークフローに取って代わるものではありません。

ネイティブスタックへの所属は、プルリクエストに対するプロバイダー側の属性であり、このスキルが選択するモードではありません。github-native モードが要求されているかどうかにかかわらず、ランディングを判断する前に Inspect 中にすべてのスタック PR について所属を確認してください。GET repos/{owner}/{repo}/pulls/<number> から .stack を読み取り、GET repos/{owner}/{repo}/stacks/<stack-number> から順序を含む完全な所属情報を取得してください(references/github-native.md § Detecting an already-native stack)。

ネイティブ状態の作成(オプトイン)

手動のスタックを gh stack link でネイティブに変換することは、プロバイダーへの変更です。次の適格性チェックをすべて通過した後にのみ実行してください。

  1. GitHub CLI が利用可能で、gh stack --help が成功すること。利用できない場合は github/gh-stack をインストールしてください。
  2. リポジトリでネイティブスタックのサポートが有効になっていること。ネイティブコマンドの終了コードが 9 の場合、スタックは手動のままにしてください。
  3. 提案するすべてのヘッド/ベースブランチとプルリクエストが、同じ GitHub リポジトリに属していること。フォークとリポジトリをまたぐスタックは拒否してください。
  4. 既存 PR のベース、ローカルのブランチ順序、Stack-Id/Stack-Position の来歴が一致していること。一致しない場合は停止してください。
  5. ユーザーがネイティブモードを明示的に要求していること。

チェックに失敗した場合、スタックは手動のままにしてください。どちらの方向にも、自動で変換したり、スタックの途中で変換したりしないでください。

すでにネイティブなスタックに対する操作(必須)

Inspect によって PR がすでにネイティブだと判明した場合、ネイティブな方法での処理は選択肢ではありません。プロバイダーはスタックのメンバーに対する同期マージを拒否し、委任された実行では、選択された最上位のメンバーに対するガード付きの非同期リクエストを 1 回だけ使って、ネイティブなメンバーをマージします。上記の条件 1〜4 は引き続き安全確認として適用されます。条件 5 の同意は適用されません。プロバイダーがすでにスタックを登録しているためです。

  • gh stack link、gh stack sync、gh stack rebase、gh stack push を使ってリンクと同期を行います(references/github-native.md)。非対話型の同期を行うたびに、gh stack view を再実行してください。
  • マージするには、ユーザーが承認した正確な最上位 PR を指定し、その下にあるスタック内のすべてのオープンメンバーをスタック判断パケットで選択する必要があります。プロバイダーは、その PR までのオープンなプレフィックス全体をマージします。そのため、承認範囲外にある下位のオープンメンバーについては、暗黙に範囲を拡大するのではなく、ユーザーに確認してください。その上にあるオープンメンバーは、パケット内の未選択ノードです。
  • トレーラー保持ポリシー(references/github-native.md § マージ方法の選択とトレーラーの保持)に従って、選択した各メンバーのマージ方法を選択します。マージキューを使う場合はキューのルールによって方法が選ばれるため、パケットの方法は送信されません。
  • マージ処理を委任します(§5)。メンバーごとのリクエスト、通常のマージ、ネイティブなメンバーに対する手動のフォールバックはありません。また、ガード付きリクエストが対象とするのは、選択された最上位のヘッドのみです(references/github-native.md § マージポリシー)。
  • squash_merge_commit_title: COMMIT_OR_PR_TITLE(GitHub のデフォルト)の場合、単一のコミットを含む PR をスカッシュすると、PR のタイトルではなく、そのコミットの見出しがベースブランチ上の件名になります。これはマージ後に、プッシュ済みの履歴を書き換えずに修正することはできません。表示される件名が重要な場合は、委任する前にマージされていないコミットの見出しを PR のタイトルに合わせてください(git commit --amend -m "<pr-title>" を実行してから、git push --force-with-lease=refs/heads/<branch>:<old-head> origin <branch> を実行します)。そして、新しいヘッドをパケットに記録してください。

ワークフロー

1. 調査

何も変更せずにスタックのモデルを作成します。

git rev-parse --show-toplevel
git status --porcelain
git branch --show-current
git for-each-ref --format='%(refname:short)' refs/heads
git symbolic-ref refs/remotes/origin/HEAD | sed 's@^refs/remotes/origin/@@'
gh pr list --state open --json number,title,headRefName,headRefOid,baseRefName,state,url

スタックブランチごとに 1 行を含む表を作成します。この表を記録する前に、すべての PR に対してネイティブスタックの確認を実行してください(references/stack-model.md § ネイティブスタックの検出)。

順序ブランチ親PR状態チェックネイティブ
1feat/parser-coremain#101オープン保留中いいえ
2feat/parser-cachefeat/parser-core#102オープン保留中いいえ

プロバイダーアダプターが利用できない場合、要求されたスタックに一致するローカルブランチがない場合、または PR のベース、明示的な順序、メタデータから親の順序を推定できない場合は、停止します。

2. 公開

不足している PR を作成し、誤ったベースを付け替えます。

git status --porcelain
git push -u origin <branch>
gh pr create \
  --base <parent-branch> \
  --head <branch> \
  --title "<title>" \
  --body-file <generated-body-file>
gh pr edit <number> --base <parent-branch>

生成する PR の本文には、スタックの順序と検証状態を含める必要があります。

## Stack

Stack-Id: `auth-refactor-a1b2c3`
Base: `main`
Position: 1/3

1. `feat/parser-core` -> this PR
2. `feat/parser-cache` -> #102
3. `feat/parser-cli` -> #103

Depends on: (none - root)
Upstack: #102

## Validation

- Pending: commands not run yet

ルート以外の PR では、Depends on: に親 PR の番号を記載します。子が判明している場合は、直下の子 PR の番号を Upstack: に記載します。

ブランチに親を超えるコミットがない場合、既存の PR がクローズされていてマージされていない場合、またはプロバイダーがベースの付け替えを拒否した場合は、停止します。

3. 同期

<base> または親ブランチが更新された後、何かがマージされる前に、references/sync-algorithm.md にある単独の手順を使ってオープンなブランチを再スタックします。各子ブランチの古いヘッド C とフォークポイント F を記録し、切り離されたスクラッチ作業ツリーで F..C を新しい先端 L にリプレイします。結果を検証し、明示的に期待する旧ヘッドを指定したリースを使って公開します。

git status --porcelain
git fetch origin
git merge-tree --write-tree --merge-base=<F> <L> <C>
git push --force-with-lease=refs/heads/<branch>:<C> origin <N>:refs/heads/<branch>

ベースの直上にある最初のブランチから開始し、末端に向かって続けます。競合、リモートリースの失敗、または親 PR がマージされずにクローズされた場合は停止します。親がマージされた後に子ブランチを昇格させてベースを付け替える処理は、委任されたライフサイクル(§5)の一部であり、この手順には含まれません。

4. 検証

レビュー可能なスライスとしてスタックを検証します。実施可能な場合は、すべてのブランチでコストの低いチェックを実行してください。ブランチごとの検証が現実的でない場合は、末端でコストの高い完全なチェックを実行してください。各 PR の本文に、実際に実行した内容を正確に記録してください。

対象リポジトリで検出されたローカルゲートとプロバイダーのチェックを使用してください。別のリポジトリのスタックを操作している場合は、armory パッケージ評価コマンドを実行しないでください。

この armory パッケージの実装に限り、次を使用してください。

uv run python scripts/validate_evals.py
uv run python scripts/generate_manifest.py
uv run python scripts/evaluate_package.py --path skills/stacked-prs
5. マージとクリーンアップ(委任)

マージ、マージ後のプロモーションとターゲット変更、マージ後の受け入れ、および既存の手動またはネイティブなスタック実行のクリーンアップは、ship-workflow スキルの明示的なスタックグラフ契約に従って、一度だけ実行します。

  1. ネイティブメンバーシップも含めて§1の検査を行い、来歴を確認します(references/provenance.md § Trailers の検証)。

  2. スタック決定パケットを1つ作成します(references/stack-model.md § 明示的なスタック決定パケット)。ユーザーが承認した PR だけに select: true を指定し、選択したノードのすべての祖先と、その他すべての関連メンバーは、コンテキストとして未選択にします。各選択ノードには、引用元とマージ方法を含め、リビジョンを含まない decision を指定します。また、検査した対象を明記した provenance: {"disposition": "preserve", ...} を指定します。これをリポジトリ外の非公開一時ファイルに書き込みます。

  3. 登録済みの ship-workflow スキルを読み込みます。クライアントにそのスキルがない場合は、ship-workflow を明記して BLOCKED で停止してください。手動のマージ、ターゲット変更、プロモーションのプッシュ、削除に切り替えてはいけません。

  4. 対象リポジトリのチェックアウトから、読み込んだスキルの絶対ベースディレクトリにある実行ファイルを、まず読み取り専用で実行し、その後、承認済みのエンドポイントを指定して実行します。

    uv run --no-project --python 3.12 python "<ship-workflow-dir>/scripts/ship.py" --stack-plan "/tmp/stack.X/stack.json" --dry-run
    uv run --no-project --python 3.12 python "<ship-workflow-dir>/scripts/ship.py" --stack-plan "/tmp/stack.X/stack.json" --gates "/tmp/stack.X/gates.json" --until merged
    

    「スタックをマージする」は --until merged、「マージしてクリーンアップする」は既定の clean です。「クリーンアップする」のみを指定すると、プロバイダーがすでにマージ済みと報告しているノードだけが選択されるため、新たなマージは行わず、実行内容を検証してクリーンアップします。

  5. コントローラーが保存済みの実行を返した場合に限り、--resume RUN_ID で再開します。解決済みの決定についてのみ、同じトポロジーの更新済みパケットを追加します。ジャーナル記録前の受付または検査で停止した場合、run_id: null または ID なしとなることがあります。その場合は、範囲が限定された入力を解決し、元の範囲を明示した呼び出しをそのまま再実行してください。ID を捏造したり、引数なしの --resume で無関係な実行を選択したりしてはいけません。

  6. 実行のステータス、確認済みのマージ、保持された依存ノード、クリーンアップの処置、次のアクションを伝えます。NEEDS_JUDGMENT は、ここで判断すべきトポロジー、来歴、範囲、またはゲートに関する決定を示します。BLOCKED は、不足している前提条件を示します。

この実行では、親を先に処理する順序、スライスを維持したプロモーション、期待される旧値のリース、ノードごとの新しいゲート、ベースブランチがオープンな状態での保持、ランディング証明(references/merge-discipline.md)が適用されます。また、ネイティブ選択は、保護された1回のリクエストでマージされます(references/github-native.md § ランディングポリシー)。

通常の委任によるリリースでは、リポジトリで現在使用されているプロバイダーチェック、レビュー、保護、マージポリシーを使用します。選択したノードでは、assurance: "high" を明示的に要求できます。通常のノードでは、チェックアウトログの固定や CI ジョブ名の変更は必要ありません。ローカル検証を要求する場合は --gates を指定します。リプレイされるすべてのコミットには per_commit: true を指定し、各ゲートにはそれぞれのタイムアウトを設定してください。検証はプッシュより前に行われ、既存のフックも維持されます。入力が変更されていない状態で拒否が確定した場合は、検証済みのリプレイオブジェクトをそのまま再利用します。変更が不確かな場合は、再試行の前に整合性を確認します。保存された保証設定と検証結果は再開後も維持されます。互換性のない従来の権限設定がある場合は、明示的な判断を求めて停止します。

1 つのブランチをスタックに分割する

1 つのソースブランチに、レビュー可能な依存関係のある PR に分割する必要がある機能が含まれている場合は、分割モードを使用します。ユーザーから、または曖昧さのないコミット名から、ソースブランチ、ベースブランチ、ターゲットブランチの順序を確認してください。

まず調査します。

git status --porcelain
git fetch origin --prune
git merge-base <base> <source-branch>
git log --oneline --reverse <base>..<source-branch>
git diff --stat <base>...<source-branch>
git diff --name-status <base>...<source-branch>

最も安全な分割モードを選択します。

モード使用する状況動作
コミット範囲による分割連続するコミットを明確に区分できる場合依存ブランチを作成し、範囲をチェリーピックします
コミットリストによる分割連続しないコミットを明確に区分できる場合スタック順に、指定したコミットリストをチェリーピックします
パッチを基準にした分割ファイルまたはハンクの境界は明確だが、コミットが混在している場合変更を加える前に、ユーザーが承認した分割マップを求めます
自動分割を拒否必要な境界をまたいで変更が複雑に絡み合っている場合分割が安全でない理由を報告します

ブランチを作成したら、公開する前にリーフをソースブランチと比較します。

git commit --amend --no-edit \
  --trailer "Stack-Id: <stack-id>" \
  --trailer "Stack-Position: <n>/<total>"
git diff --stat <source-branch>...<leaf-branch>
git diff --exit-code <source-branch>...<leaf-branch>

公開する前に、references/provenance.md に従って各スライスのコミットにトレーラーを付与します。トレーラーの付与ではコミットメッセージを修正しますが、ツリーの内容は変わらないため、リーフとソースの比較は引き続き git diff によるツリー比較として行い、必ず合格する必要があります。

リーフがソースブランチと異なる場合は、公開しないでください。

エラー処理

条件対応
変更を加える前にワークツリーに未コミットの変更がある停止し、変更されたパスを報告します
親ブランチの順序が曖昧明示的なブランチ順序または .stack-prs.yaml を求めます
マージされていない既存のクローズ済み PR がある置き換えを作成する前に停止します
親ブランチの削除後に、マージされていない子ブランチがクローズされたreferences/merge-discipline.md § Recovery に従い、その後、残りのマージを委任します
リベースまたはチェリーピックで競合が発生した停止し、ブランチ名と競合ファイルを報告します。子ブランチの処理は続行しません
フェッチ後にリモートブランチが変更された停止します。再調査なしに再試行しないでください
検証に失敗した失敗したコマンドを記録し、公開または委任を停止します
分割後の最上位ブランチがソースと異なるPR の作成前に停止し、残りの差分を報告します
作成したスタック内のコミットに Stack-Id トレーラーがない停止します。委任する前に、未公開のコミットに references/provenance.md に従ってトレーラーを付与します
トレーラーの Stack-Id が .stack-prs.yaml と異なる停止します。変更を加える前に、正式な ID を解決します
開いている下位のネイティブメンバーが、許可されたプレフィックスの範囲外にあるスコープについて判断を求めます。選択範囲を広げてはいけません
マージまたはクリーンアップが要求されたときに ship-workflow がインストールされていないship-workflow の名前を挙げて BLOCKED で停止します
委任の結果が NEEDS_JUDGMENT または BLOCKED確認済みの事実をそのまま伝え、ここで指定されたトポロジー/来歴/スコープの入力を解決します。返された保存済み run のみ再開してください。該当する run がない場合は、解決済みの情報を添えて元のスコープ指定を繰り返します。--resume のみで再開してはいけません。

出力形式

次の内容を報告します。

  1. ブランチ、親、PR 番号または URL、状態、ネイティブメンバーシップを含むスタック順序。
  2. PR の作成、ベースの編集、リベース、プッシュなど、このスキルが実行した変更。
  3. 検証コマンドと、正確な合格/不合格の状態。
  4. マージまたはクリーンアップを委任した場合は、実際の状態、確認済みのマージ、維持された依存ブランチ、クリーンアップの処置、次のアクション。run_id は返され、かつ null でない場合にのみ含めます。
  5. 次に安全に行えるアクション:検証の修正、競合の解決、明示的なブランチ順序/スコープの提示、または返された保存済み run の再開。レシートがない場合は、解決後に元のスコープ指定を繰り返します。

コメント