implement-issue-tree

親イシュー配下のサブイシュー(孫含む)を依存順を保ちつつ worktree で並列に自動実装・push 前 review・PR 作成・CI 監視・マージ可能状態化まで一括自動化。 「イシューツリーを並列実装」「配下のサブイシューをまとめて実装」「ツリー全体を並列で実装して」「イシュー階層を自動開発」で使用。 per-issue 計画立案(Plan: セッション継承モデル)→実装(Implement: sonnet)の分業。push 前 review(Review 通過後にのみ push・PR 作成して CI を 1 回だけ起動)。 外部チェック構成は args の externalChecks

By fandhe-ai · 766 installs

npx skills add fandhe-ai/agent-cli-skills --skill implement-issue-tree

Source repository · Upstream listing

implement issue tree 親イシュー番号を指定し、配下のサブイシュー(孫以下の全子孫を含む)を依存順を保ちつつ worktree で並列に自動実装・ローカル diff レビュー・push + PR 作成・CI 監視・マージ可能状態化まで自動化する Workflow を起動する。squash merge は autoMerge: true + externalChecks 明示(全 App の信頼済み check context 宣言込み)の opt in ランでのみクライアント側で実行する(references/automerge design.md の「クライアント側自動マージの設計」節参照)。既定( autoMerge 未指定 / false )ではマージせず停止し、マージは GitHub 上で人間が行う。 CI リソース節約のため「push 前 review」設計を採用している。Implement フェーズではローカルブランチにコミットのみ積み、Review が全通過した後にはじめて push・PR 作成を行う。Review が収束失敗した場合は push も PR も作らないため、CI が一切起動しない。push(PR 作成時・Merge ループの fix 後の再 push)の直前には必ず base ブランチを取り込む(起点の確立・fetch・merge・push・push の反映確認・PR の検出と作成は scripts/pr push.sh が決定的に行い、エージェントはコンフリクトの解消・commitlint に合わせた subject の決定・PR の文面だけを担う。Issue 603 第 4 弾。fix が CI に拒否された既存コミットのメッセージだけを書き直した場合は、捨てるコミットがすべて tree と親を保っているとスクリプトが確かめたときだけ lease つきの push で反映し pushed rewritten を返す。内容や親が変わる書き換えと pr create の push は従来どおり通常の push だけで、拒否されれば push failed 。Issue 696)。並列ラン( parallel = 2 )で兄弟イシューの PR が先にマージされていると、作成時点の base が既に古くコンフリクトしている場合があり、その状態のまま push すると GitHub は test merge commit を作れず pull request トリガーの CI check run が 1 件も発行されないため、push 前ゲートで解消を試みてから push する(解消不能なら push 自体を止める)。さらに push 直後(PR 作成時・fix の再 push 時)には、push した head にチェックが発行されたか( check run の total count + combined status の statuses 件数の合計 。 gh pr checks / merge exec と同じ集計定義。commit status のみを発行する CI で 0 件と誤判定しないため)と mergeable を有界(30 秒間隔・最大 5 分。 scripts/observe pr.sh mode push が、push した HEAD が PR の head になるのを待ってから読む。Issue 603 第 3 弾)で確認し、 checksStarted / mergeableAfterPush として返す(push 前ゲート通過後に兄弟 PR がマージされて base が動いたケースを、監視ラウンドを消費する前に捕捉する)。 mergeableAfterPush: CONFLICTING を受けたホストは monitor を 1 ラウンドも起動せずに base 取り込み( baseMergeCount で有界)へ直行する。両値はエージェントの自己申告でありマージ判定には使わない(分岐ヒントと状態ファイルへの記録専用。 /issue trees/<n .json の pushChecksStarted / pushMergeable )。 末端の実装イシューは post order DFS の順序を優先度として空きスロットへ貪欲投入し、最大 parallel (既定 3)件まで並列実行する。各 implement / fix は独立した git worktree で隔離実行されるため、並列でもブランチ・working copy が衝突しない。機能的依存( dependsOn )と親子関係(親は全子の完了を待つ verify close)だけが待機条件となる。 前提条件 gh CLI がインストールされ、認証済みであること( gh auth status で確認) jq CLI がインストールされていること( command v jq で確認)。 monitor の観測スクリプト scripts/observe pr.sh は全モードで外部 jq を使う (封筒の payload の組み立て、 gh api paginate のページごとの出力の合算〔 jq s 〕、 arg / argjson / @uri 。jq 1.5 以上が要り、1.6〔ubuntu 22.04〕・1.7〔debian・macOS〕・1.8〔alpine〕で実走を確かめた)。未導入だとスクリプトは exit 3 で封筒を出さず、監視は取得失敗として扱う。ほかに、「全チェックが pass に見えるのにマージが進まない場合(cancel された run の残存 check)」節の人間の診断専用コマンド (B) は gh api paginate slurp の生 JSON を外部の jq へパイプして平坦化・集約するため、 gh jq だけでは代替できない。未導入の場合はそのコマンドを実行せず(rerun もせず) blocked として扱う gh の機能の前提( observe pr.sh ): gh pr view json state,headRefOid,mergeable,headRefName,baseRefName,closingIssuesReferences,isCrossRepository ・ gh api paginate ・ gh api graphql 。複数ページの合算は gh api paginate の出力を jq s で行い、 gh api slurp (新しめの gh の機能)には依存しない。 必要な gh の最低版は未確認 (実走確認は gh 2.102.0 の実 API のみ。公式のリリースノートで各フィールドの導入版は確かめていない)。時間制限のために bash のジョブ制御( set m )と mktemp ・ date +%s ・ sleep を使う(macOS の bash 3.2 と Linux で動く)。base 取り込みの scripts/base merge.sh は gh pr view json number,headRefName jq … (gh 内蔵の jq。外部の jq は要らない)と、 git remote get url push all (git 2.7 以上)・ git merge no ff no edit F ( git 2.20 以上 。実測では 2.20.4 にあり 2.18.4 以前に無く、2.19 系は未確認。無い git では base 取り込みが commitFailed 〔 failed 終端〕になり push はされない。詳細は references/script trust model.md)・ git merge base is ancestor ・ git ls remote を使う。 observe pr.sh mode push は push した HEAD を git rev parse HEAD で読むため、pr create・fix のエージェントの作業ディレクトリ(push した worktree)で実行する awk CLI がインストールされていること( command v awk で確認)。同節のエージェント実行可能コマンド (A) は jq がページ単位にしか適用できないため、ページ跨ぎの重複を集約する際にシェル側 awk へ依存する。未導入の場合はそのコマンドを実行せず UNDETERMINED (判定不能)として扱う git working tree が clean であること( git status で確認) 測定スクリプト( scripts/measure .sh ・ scripts/run verified.sh )が使う bash ・ du ・ df ・ awk と、 sha256sum または shasum (macOS の標準は shasum )。macOS(BSD userland・bash 3.2)と Linux(GNU)の両方で動く書き方に限っている。どれかが無いと測定が失敗し、残置バイト軸が有効なランは新規着手を止める(fail closed) マージ先ブランチが CI green の状態であること( autoMerge 運用ではランの完了後にも確認する。後述の strict = false 前提により、古い base に対して成功したチェックのままマージされ得るため)。 この確認はマージ先ブランチへの push で CI が起動することに依存する 。push トリガの workflow が無い、または paths フィルタで該当 head では起動しないリポジトリでは前提確認・完了後確認のいずれも検証不能であり、 autoMerge: true は非推奨とする。成立可否の確認手順(対象(マージ先)ブランチを検査するプローブ。 branch 未指定時のみ既定ブランチへフォールバック)と不成立時の扱いは references/automerge design.md の「補償策の成立確認(base CI プローブ)」節を参照 ( autoMerge: true で使う場合)ベースブランチの ruleset で required status checks の strict(マージ前の base 最新化必須 = strict required status checks policy )を false にしていること 。 true だと 1 件マージするたびに他の open PR の base が陳腐化し、並列ラン( parallel = 2 )が収束しない。G0 は strict を要件にしないため false でも自動マージは成立する(references/automerge design.md の「strict を G0 の要件にしない理由」節) 対象リポジトリへの書き込み権限があること 親イシューと子イシューが GitHub の sub issues API で紐付いていること(紐付けは create issue / create issue tree を参照) 使い方 Workflow ツールで scriptPath にこのスキルディレクトリ内の scripts/implement issue tree.js を指定して起動する。パスは導入形態で異なり、後述の merge guard hook のパスと 同じ導入形態なら同じルート配下 にある(js と hook は必ず同一のスキルディレクトリに同居する)。3 レイアウト: upstream skills/ レイアウト (本リポジトリ Fandhe AI/agent cli skills のソース): skills/implement issue tree/scripts/implement issue tree.js .agents/skills/ に vendored ( npx skills add Fandhe AI/agent cli skills で導入した downstream リポジトリ): .agents/skills/implement issue tree/scripts/implement issue tree.js .claude/skills/ symlink 経由 (本リポジトリが内部参照に使うレイアウト。実体は skills/ を指す symlink): .claude/skills/implement issue tree/scripts/implement issue tree.js args.skillDir (配布後は呼び出し側が必ず渡す): scriptPath と同じスキルディレクトリ(上の 3 レイアウトのいずれかの implement issue tree/ 。 scripts/ の 1 つ上)を 絶対パス で args.skillDir に渡す(例: /Users/me/repo/.claude/skills/implement issue tree 。相対の scriptPath を使う場合は $(pwd)/.claude/skills/implement issue tree のように起動時のメイン作業ディレクトリで絶対化する)。Workflow スクリプト自身はファイルシステムに触れないため、決定的な手順をスキル同梱のスクリプトへ切り出した部分(Issue 603。測定 scripts/measure .sh ・PR の観測と待機 scripts/observe pr.sh ・base 取り込み scripts/base merge.sh ・PR 作成と fix の push scripts/pr push.sh ・ツリー取得 scripts/fetch tree.sh )の実行場所をここから決める。 ラン開始時( dryRun を含む全ラン)に、埋め込みの全スクリプトのハッシュを実ファイルと 1 回照合し(エージェント 1 回。 run verified.sh verify only )、版ずれ・欠落は何も着手せずに停止する (予検査。検出できるのは版ずれと転記ミスで、悪意あるエージェントの捏造ではない。各スクリプトの起動時の照合は別に毎回働く)。 named workflow( {name: "implement issue tree"} )で起動する場合も args.skillDir が要る (named workflow は .claude/workflows/implement issue tree.js を指すだけで、スクリプトの置き場所を Workflow ランタイムは教えない)。サブエージェントは必ずこのメイン作業ディレクトリ側の scripts/run verified.sh を bash で起動し(実行ビットに依存しない)、worktree 内のコピーは使わない。起動前に期待ハッシュ(ビルダーが生成物へ埋め込む)と照合し、不一致・欠落は起動せず fail closed になる。信頼モデルは [references/script trust model.md](references/script trust model.md)。形式は args.repo と同じ厳格さで検証し、不正な値(相対パス・ .. ・ // ・末尾 / ・許可外の文字・400 文字超・文字列以外)は黙って読み替えず起動時エラーで停止する。 未指定のとき: 全ラン( dryRun: true を含む。ツリー取得が全ランで fetch tree.sh 経由になったため。 maxResidualWorktreeBytes: 0 でも必要)は、エージェントを 1 回も呼ぶ前に起動時エラーで停止する。 例: 親イシュー 42 の配下を main へ、並列度 3・Cursor Bugbot 導入済みで実行する場合(マージ可能状態まで自動で進み、マージは GitHub 上で人間が行う): 例: 品質を優先して計画を fable 、実装と fix を opus に上げ、セキュリティ専用の Review を opus で足す場合(通常の Review・PR 作成・機械的な agent は既定のまま): 引数 引数 必須 既定 説明 parent 必須 — 親(ルート)イシュー番号。 issue でも可 skillDir 必須 — このスキルディレクトリ( scripts/ の 1 つ上)の絶対パス (Issue 603)。決定的な手順を切り出したスクリプト(現在は残置 worktree のバイト測定 measure residual bytes.sh ・実ディスク空き容量 measure free disk.sh ・PR の観測と有界の待機 observe pr.sh ・自動 base 取り込みと push の検証 base merge.sh ・pr create と fix の base 取り込み・push・PR 作成 pr push.sh ・状態ファイルの書き込み state.sh ・merge exec のマージ直前の検証 merge gate.sh ・worktree の破棄と掃除 worktree remove.sh ・Recover の機械手順 recover prep.sh ・ツリー取得 fetch tree.sh )をサブエージェントが実行する場所。ラン開始時にこの場所の全スクリプトのハッシュを 1 回予検査する(不一致・欠落は何も着手せずに停止)。 scriptPath と同じスキルディレクトリを渡す。 全ランで必須 (ツリー取得が全ランで fetch tree.sh 経由のため dryRun: true でも必要。monitor が observe pr.sh を使うため maxResidualWorktreeBytes: 0 でも必要)で、未指定なら起動時エラーで停止する(エラー文に渡す値の例を示す。エージェントを 1 回も呼ばない)。形式は絶対パス(英数字・ . ・ ・ ・ / ・半角スペース、先頭は / + 英数字または )のみで、相対パス・ .. ・ // ・末尾 / ・400 文字超・文字列以外は起動時エラー。存在・ハッシュの確認はスクリプト側(実行時)が行い、欠落・不一致は測定失敗として新規着手を止める(fail closed)。配布後は既存の呼び出し手順がこの引数を渡すよう更新が必要 branch 任意 main マージ先ブランチ。不正な文字を含む場合はエラー parallel 任意 3 並列実行数(1〜8)。 1 を指定すると実質的に直列実行になる phaseGate 任意 false true でルート( args.parent )直下の子(Phase 親 or leaf)を sub issues リスト順( siblingIndex 。タイトルの feat(phase N): 等は非信頼データのため解析しない)に直列化する opt in ゲート 。直列化の単位は「ルート直下の子とその子孫全部(部分木)」で、単位 Uₖ(k≥1)の部分木は、それより手前の全単位 U₀…U {k 1} の前提(子を持つ Phase 親なら自身を除く子孫全部、子を持たない leaf なら自身)がすべて merged / closed になるまで着手しない(Phase 親自身の verify close 完了は前提に含めない設計。「前 Phase 親の 全子 が merged/closed」という要件に合わせるため)。新しいスケジューラ状態は作らず、既存の依存グラフ( depsMap )へ合成辺を追加するだけなので、dispatch ループ・前提プローブ(ラン中の人手マージ検知)・ 前回ランで作成済みの次 Phase PR の monitoring 再開 にもそのままゲートが効く(同一引数での再実行でも次 Phase の PR は前 Phase 完了までマージされない)。ゲート辺は循環除去で削除されない(本文由来の逆向き dependsOn の方が無視される)。 autoMerge: false では前 Phase の PR がマージ可能状態のまま blocked で停止するため、次 Phase へ進めるには人手マージ後の前提プローブ検知、または再実行を要する。 parent に Phase 親そのものを渡した場合はその直下の子が直列化される(仕様上は動くが、ルート〔トラッキング issue〕への指定を推奨)。Phase ごとに別ランを直列起動する必要はない(verify close がルートまで伝播する)。boolean 以外はエラーで停止(誤記を黙って読み替えない) dryRun 任意 false true で事前見積りだけを行い、何も書かずに終了する (Issue 585)。ツリー取得・依存の解決・ツリー外の前提 issue の state 取得は通常どおり行うが、状態ファイルの作成・更新( state:init all 含む)、worktree 作成、Plan 以降の実装系エージェントの起動、PR・issue への書き込みを一切行わない。返却は dryRun: true ・ startable (着手見込みの件数 count ・今すぐ着手できる件数 readyNow ・先頭 5 件 first 。着手できたノードが全て成功する前提の見込み)・ blocked ( count と、 outOfTree 〔ツリー外の open な前提を直接待つ〕/ phaseGate 〔前 Phase 未完了の合成辺で止まる〕/ downstream 〔それ以外の下流・子の保留〕/ optinTestsInvalid 〔前提は満たすが opt in テスト宣言が承認一覧と一致せず、通常実行の runImplement 冒頭で blocked になる実装ノード〕/ savedBranchMismatch 〔同じく状態ファイルの branch が本イシューの命名でないため blocked になる実装ノード〕それぞれの count と先頭 5 件 first 。分類は前記の順で最初に当てはまる 1 つで、前提が失敗済みで実行されないノードは自身の条件を見ずに依存側へ分類する。自身が blocked になるノードは着手見込みに入れず、下流へ伝播させる)・ preBlocked (状態ファイルの照合不成立等で最初から止まる番号)・ closedCleanupPending (通常実行で行う「closed 後始末」の対象見込み。 count ・先頭 5 件 first ・最大エージェント呼び出し数 maxAgentCalls 。dryRun では実行しない)・ outOfTreeDeps (open / unknown / closed / ancestors)。halt・残置 worktree 上限・CI の結果は実行時にしか分からないため見積りに含めない。「着手できるノードが 0 件で blocked が大半」と分かったら、通常ランの前にツリー外の前提 issue の close や phaseGate の見直しを検討する。boolean 以外はエラーで停止 externalChecks 任意 未指定 GitHub Actions 以外の外部チェック宣言の配列(最大 10 件)。要素は {"app": "<slug ", "context": "<required check context "} の組で宣言する(slug は英小文字・数字・ハイフン。複数 context は contexts 配列。slug 文字列のみの旧形式も受理するが context 未宣言としてクライアント側自動マージは fail closed で停止する)。 未指定と [] は意味が異なる optinTestCommands 任意 [] opt in テストとして実行してよいコマンドの承認一覧(文字列配列・最大 20 件。 parseOptinTestCommands )。イシュー本文の <! optin tests: ... 宣言は、正規化(水平空白の連続を 1 個へ畳む)後にこの一覧の値と 文字列完全一致 したものだけが実装エージェントへ渡る(次節「opt in テストの宣言」参照)。要素は許可形式(文字集合・パストラバーサル・ // ・絶対パス・許可ランナー・サブコマンド制約・mvn GAV・deno リモート指定子)を通らなければ 起動時エラーで停止 する( externalChecks と同じ厳格さ。誤記を黙って読み替えない)。 未指定 / [] の場合は本文に宣言があっても全件 invalid(fail closed。承認一覧が無ければイシュー本文だけでコマンドを持ち込めない) autoMerge 任意 false true + externalChecks 明示(確定。全 App の信頼済み context 宣言込み)の opt in ランでクライアント側 squash merge を実行する (references/automerge design.md の「クライアント側自動マージの設計」節参照。マージは merge exec の自己取得再検証(HEAD sha・checks・スレッド・外部チェック)+ G0(ベースブランチのサーバー側強制の実測 = required status checks の bypass 不能性(ruleset は bypass actors 空。classic branch protection のみのリポジトリは非対応 — bypass 不能性の検証に必要な protection 読取が admin 権限を要求し write トークンで証明できないため classic unsupported で辞退)+ strict 適用(マージ前の base 最新化必須)+ レビュースレッド解消の必須化 + 手順 3 の合格判定対象チェック context の required 化(client only チェックの不在)+ 外部チェック App の宣言 context + App ID 組( context + integration id )束縛の required 化 + required checks 全エントリの発行元 integration id 束縛(同名 commit status 偽装の遮断。検証できなければ issuer unbound )。確認できなければ server enforcement missing で blocked 終端)+ match head commit + merge verify の独立確認を経る。monitor の出力はマージ経路の入力に使われない)。既定 false ・ externalChecks 未確定時・信頼済み context 未宣言時(slug のみの旧形式)はマージせず、PR はマージ可能状態の blocked で停止する(実装・push 前 Review・PR 作成・CI 監視・fix ループは値によらず自動で進む)。opt in を使わない場合、auto merge はサーバー側 workflow(upstream の docs/implement issu