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 ブランチを取り込む( git fetch → git merge )。並列ラン( parallel = 2 )で兄弟イシューの PR が先にマージされていると、作成時点の base が既に古くコンフリクトしている場合があり、その状態のまま push すると GitHub は test merge commit を作れず pull request トリガーの CI check run が 1 件も発行されない(Issue 435)ため、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 件と誤判定しないため。Issue 480)と mergeable を有界(30 秒間隔・最大 5 分)で確認し、 checksStarted / mergeableAfterPush として返す(Issue 479。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 で確認)。「全チェックが pass に見えるのにマージが進まない場合(cancel された run の残存 check)」節の人間の診断専用コマンド (B) は gh api paginate slurp の生 JSON を外部の jq へパイプして平坦化・集約するため、 gh jq だけでは代替できない。未導入の場合はそのコマンドを実行せず(rerun もせず) blocked として扱う
awk CLI がインストールされていること( command v awk で確認)。同節のエージェント実行可能コマンド (A) は jq がページ単位にしか適用できないため、ページ跨ぎの重複を集約する際にシェル側 awk へ依存する。未導入の場合はそのコマンドを実行せず UNDETERMINED (判定不能)として扱う
git working tree が clean であること( git status で確認)
マージ先ブランチが 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
例: 親イシュー 42 の配下を main へ、並列度 3・Cursor Bugbot 導入済みで実行する場合(マージ可能状態まで自動で進み、マージは GitHub 上で人間が行う):
引数
引数 必須 既定 説明
parent 必須 — 親(ルート)イシュー番号。 issue でも可
branch 任意 main マージ先ブランチ。不正な文字を含む場合はエラー
parallel 任意 3 並列実行数(1〜8)。 1 を指定すると実質的に直列実行になる
externalChecks 任意 未指定 GitHub Actions 以外の外部チェック宣言の配列(最大 10 件)。要素は {"app": "<slug ", "context": "<required check context "} の組で宣言する(slug は英小文字・数字・ハイフン。複数 context は contexts 配列。slug 文字列のみの旧形式も受理するが context 未宣言としてクライアント側自動マージは 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 issue tree/auto merge sample.yml )+ branch protection への委譲、または GitHub 上での人間マージで行う(対象ブランチに branch protection を設定することを推奨)。注意: merge guard hook 導入リポでは subagent の gh pr merge が deny されるため opt in マージと hook は併用できない。boolean 以外はエラーで停止(誤記を黙って読み替えない)
maxResidualWorktrees 任意 100 残置 worktree 総数の上限(DoS 防止ゲートの件数軸。バイト軸 maxResidualWorktreeBytes と独立に併用され、判定は OR=どちらか一方でも超過すれば新規着手を止める)。ラン開始時に横断スキャンで観測した worktree の 物理総数 (メイン worktree のみ除外。状態ファイル追跡済み=使用中の worktree も数える。使用中かどうかはディスク消費を変えないため。PR 185 codex P1 第 5 ラウンド)がこの値を 超過 ( )していたら、ディスク枯渇を防ぐため 新規イシューの着手を停止 する(fail closed。既に走行中のイシュー・monitoring の継続は停止しない)。dispatch ループは新規着手の直前に毎回「開始時観測 + 本ラン積み増し( ephemeralWorktrees.length 。implement / review / pr create / fix routing error の新規作成台帳)」を再評価し、本ランの積み増しで上限を超えた時点でも以降の新規着手を停止する(PR 185 codex P1。バイト軸にも同種の途中経過再評価があるが、算出方法が異なるため後述)。さらに並列投入済みでまだ記録に到達していないタスク分を見込み、新規着手 1 件あたり最大 6 件(implement ×1 + review ×3 + pr create ×1 + fix routing error ×1。 EPHEMERAL KIND MAX テーブルから導出)、monitoring 再開 1 件あたり最大 1 件(fix routing error 分)を予約計上し、「実測 + 予約 + 着手候補分」が上限を超える投入を止める。 monitoring 再開自体もこの予約込み判定の対象 (ただし item.kind === 'implement' の再開に限る。verify close ノードとして到達した再開は runVerifyClose が Merge ループへ入らず fix routing error を積み増さないため予約 0 で対象外。PR 185 Bugbot Medium と同じ線引き)であり、開始前に同じ projected 判定を適用して超過が見込まれる場合は当該イシューの再開をこの周回に限り defer する(恒久停止はしない。次周回・次回実行で予約解放後に再評価。pet hub PR 1062 codex review P1 対応。修正前は monitoring 再開自身の開始を無条件で許可しており、monitoring 項目を順次再開し続けると上限を無視して残置数を際限なく増やせた)。予約起因の超過見込みは今周回の投入見送り(defer)に留め、予約が解放されれば再開する。実測超過は従来どおり恒久停止する(PR 185 codex P1 第 2 ラウンド。ただしこの恒久停止= newStartSuppressed は monitoring 再開の開始自体は妨げない設計を維持しており、上記の monitoring 再開専用 defer とは独立したゲート)。ラン開始時の横断スキャン自体が失敗した場合も、いずれかの軸が有効( maxResidualWorktrees 0 maxResidualWorktreeBytes 0 )なら残置総数を確認できないとみなして新規着手を停止する(fail closed。両軸とも 0 指定時のみ観測失敗でも続行。観測失敗時( residualObserved === false )も monitoring 再開( item.kind === 'implement' の再開に限る)は fail closed で defer する — 観測できない状態での worktree 積み増しを許す fail open を避けるため、 monitoringResumeGateDeferred へ理由を記録してこの周回の再開を見送る(恒久停止ではない。次周回・次回実行で再評価する))。スキャン一覧が非空でも、独立取得したレコード総数との件数照合に不一致(転記の一部脱落の疑い)があれば同様に観測失敗として停止する(PR 185 codex P1 第 4 ラウンド)。使い捨て worktree は削除しない設計(references/recovery.md の「worktree の自動削除」節)のため、この上限超過時は git worktree list で確認し不要な worktree を git worktree remove で 手動削除 してから再実行する。 0 は「この件数軸のみ上限なし(チェック無効)」の明示オプトアウト(バイト軸の fail closed には影響しない)。 負値・非整数はエラーで停止 (マージゲート入力と同じ厳格さ。誤記を黙って読み替えない)。既定値は 100(旧既定 20 では 1 イシュー消化あたり実測 4〜6 件の積み増しで 1 ラン 3 件着手が頭打ちになったため Issue 348 で引き上げ。linked worktree は object store を共有し working tree 分のみディスク消費のため 100 件でも過大ではないが、根拠は本リポジトリ 1 件のみの実測〔≈ 3.4 MB/件〕であり、配布先ごとに追跡ファイル量が異なるため、リポジトリ非依存の絶対閾値として maxResidualWorktreeBytes を必ず併用する。codex review 指摘・PR 390)。 ただし maxResidualWorktreeBytes: 0 でバイト軸を明示オプトアウトし、かつ本引数を未指定のままにした場合はこの補強が働かないため、既定値を安全側の旧既定 LEGACY DEFAULT MAX RESIDUAL WORKTREES (20)へ自動的に引き下げる ( parseMaxResidualWorktrees の bytesAxisDisabled 引数。codex review 指摘・PR 390 第 2 ラウンド: 件数軸だけを緩和した既定値を、リポジトリ非依存の絶対閾値という補強なしに残さない)。利用者が本引数へ明示的に値を指定した場合はこのフォールバックの対象外(指定値をそのまま使う)
maxResidualWorktreeBytes 任意 53687091200 (50 GiB) 残置 worktree ディスク使用量の上限(DoS 防止ゲートのバイト軸。バイト単位。件数軸 maxResidualWorktrees と独立に検証・無効化でき、判定は OR)。 ラン開始時のみの観測ではない (旧記載の訂正。codex review 指摘・PR 390 第 2 ラウンド: 実装は当初からラン中の再評価を持っていたが本節がそれを反映していなかった)。ラン開始時に、残置パス一覧全件へ du sk を実行して KiB を単純合計する観測に加え、共有 .git object store を除いたメイン worktree の working tree 相当サイズ( measureMainWorktreeContentBytes )を新規 1 worktree あたりの安全側予約 perWorktreeByteReserve として確定する(PR 390 codex review P1・Cursor Bugbot High: 素の du 値は object store 全量を含み過大予約になるため除外する)。件数軸の「本ラン積み増し再評価」「予約計上」と同じ形で、 perWorktreeByteReserve × (台帳件数 − 直近基準確定時点の台帳件数) の projection をラン中の新規着手・monitoring 再開の両方の直前に毎回再評価し、超過見込みで新規着手を止める( projectResidualBytes 。基準確定時点までの積み増しは実測基準値に既に含まれているため、そこを差し引かないと二重計上になる。K8Dc 対応・PR 390)。 さらに perWorktreeByteReserve は開始時に確定する下限 floor 値であり、ビルド成果物等で 1 worktree が floor を超えて成長した場合 projection だけでは過小評価し得るため、使い捨て worktree 台帳が BYTE REMEASURE LEDGER INTERVAL (3 件)積み増されるごとに残置パス一覧+台帳パスの合計を実際に du し直し( remeasureResidualBytesIfDue )、実測が上限を超えていれば独立に新規着手を止める。 加えて、新規着手(implement)の直前には台帳増分ゲートを介さず必ず実測し直す ( remeasureResidualBytesNow 。台帳が 3 件増えない間も実行中 worktree はビルド成果物等で成長し得るため、台帳増分だけを契機にすると容量超過後の着手を止められない fail open が残る — PR 390 codex review P1 第 4 ラウンド。測定コストは「同一 dispatch 周回内は 1 回」の間引きで有界化する)。 この実測し直しは以後の projection の基準( residualBytesAtStart ・台帳オフセット byteBaselineLedgerCount )を同一代入で更新する (実測結果を上限超過の即時判定にのみ使って破棄すると、以後の判定が古い基準のまま容量超過の新規着手を許す fail open になる。K8Dc 対応)。合計(直近の実測基準・projection・実測し直しのいずれか)が上限を 超過 していたら新規イシューの着手を停止する(fail closed。既に走行中のイシュー・monitoring の継続は停止しない。件数軸で既に停止済みの場合は追加の抑止はせず観測値のみログへ記録する)。測定不能( du が 1 件でも失敗・非0終了・許可文字集合外のパス混入)は 0 で補わず観測失敗として扱い、この軸が有効なら新規着手を停止する( countResidualWorktrees の「検証不可」計上と同じ fail closed の理由。実測し直しの失敗も projection へフォールバックせず新規着手を停止する。存在しないパス〔並行 cleanup による削除〕のみ 0 として許容し、 du 自体の実エラーのみ測定失敗とする)。 エージェントの worktreePath 省略・空文字で台帳に未検証エントリが生じた場合は、この時点で git worktree list porcelain の物理一覧(メイン除く全件・独立レコードカウントとの件数照合付き)へフォールバックして実測を継続し、フォールバックも失敗した場合(一覧取得不成立・件数不一致・パス検証不可)のみ従来どおり fail closed で新規着手を停止する ( buildPhysicalByteMeasureTargets 。review / pr create / fix 系 worktree は隔離 worktree 内で detach するため branch 照合による帰属特定ができず、フォールバックは測定専用(削除経路へは流さない)で物理一覧を丸ごと差し替える。Issue 404)。ラン開始時観測が失敗したまま( residualBytesObserved === false )の場合は、monitoring 再開の projected 判定(前述の item.kind === 'implement' 限定の projection)自体も件数軸と同じ fail closed 方針で defer し、観測が回復するまでそのランの monitoring 再開全体を待機させる(観測不能のまま fix routing error worktree の新規作成を許すと容量を確認できないまま超過し得るため)。 0 は「このバイト軸のみ上限なし(チェック無効)」の明示オプトアウト(件数軸の fail closed には影響しない。件数軸の既定値フォールバックについては maxResidualWorktrees 行を参照)。 負値・非整数はエラーで停止 。既定 50 GiB は Issue 348 の検討案 B(実バイト数上限)を採用した後、Issue 467 でビルド成果物の大きいリポジトリでの誤停止(vector db 629 実測)を踏まえ 2 GiB から引き上げたもので、配布先リポジトリのファイル量に依存しない絶対閾値として件数軸既定値 100 の妥当性を補強する。 残置サイズの合計上限とは独立に、実ディスクの空き容量そのものも新規着手・monitoring 再開の直前に毎回検証し直す ( measureFreeDiskKib / remeasureFreeDiskNow 。Issue 467 P0 codex review 対応・PR 468 で P0/High の再指摘に追加対応: 残置合計サイズが上限(既定 50 GiB)未満でも、実ディスクの空き容量自体はそれよりずっと小さいことがあり得るため〔例: 残置 8 GiB・実空き 4 GiB の導入先では、残置サイズだけを見るゲートは 50 GiB に達するまで新規着手を止めない〕、 df Pk でメイン worktree が属するファイルシステムの実空き容量を測定する。 ラン開始時 1 回だけの測定では以後の消費を反映できない ため(codex review P0)、バイト軸の remeasureResidualBytesNow と同じ「新規着手・monitoring 再開の直前に必ず実測し直す(間引きは同一 dispatch 周回内 1 回)」設計を踏襲する。判定に使う必要バイト数は 単一 worktree 分の予約とだけ比較しない (codex review P0: 実行中タスクの未消費予約・投入済み候補自身の予約を合算していないと過小評価になる)。 projectFreeDiskReserveBytes が「実行中タスクの残余予約( reservedUnits 。件数軸・バイト軸 (b) と同じ「最大増分 − 記録済み数」の計算をそのまま再利用)+着手候補自身の最大増分( extraReserveUnits )」の合計に 1 worktree あたりの生の容量見積り( rawPerWorktreeByteReserve ) を掛けて必要バイト数を算出し、実測空き容量がこれを下回れば抑止する。バイト軸の perWorktreeByteReserve ( clampPerWorktreeByteReserve で容量上限に対する予算配分とし