create-issue-tree
Phase 分割された GitHub Issue ツリーを新規作成するスキル。「イシューツリー作って」「タスクを Phase 別に Issue 化」「Issue ツリーを起票して」で使用。 要件・タスク一覧を受け取り、タスク分解(既定 2h 粒度・--granularity で変更可)→ Phase 分割 → ルート(トラッキング)issue → Phase 親 issue → 子 issue の階層を sub_issues API で紐付け。 phase ラベル付与・ルート issue 本文の Phase 別表生成まで自動化。任意の phase 指定で部分起票にも対応。 ツリーの棚卸し・更新
By fandhe-ai · 625 installs
npx skills add fandhe-ai/agent-cli-skills --skill create-issue-tree
Source repository · Upstream listing
create issue tree
要件・タスク一覧から Phase 分割された GitHub Issue ツリーを新規作成する。
ルート(トラッキング issue)→ Phase 親 issue → issue → sub issue の 4 階層を構築し、implement issue tree が post order DFS で消化できる構造を維持する。
ルート issue 本文の運用ルール「実行順は sub issues リスト順が正」は既定では post order の 優先度 に留まり、並列実行時に後続 Phase が前 Phase を追い越す余地がある。Phase 完了を厳密に順序保証したい場合は implement issue tree 実行時に phaseGate: true を指定する(implement issue tree の SKILL.md 参照)。
使い方
引数としてタスク要件テキストまたはファイルパスを渡す。
phase オプションで特定 Phase のみ起票することもできる(大規模ツリーを段階的に起票する場合)。
2 回目以降の部分起票では root で既存ルート issue 番号を渡し、同じツリーに継ぎ足す
(指定しないと新しいルート issue が重複作成される)。
milestone オプションで起票する issue 全件に割り当てる GitHub Milestone を指定できる
( root 指定時は省略可。既存ルートの milestone を自動継承する)。
granularity オプションで 1 issue に収める実装時間の上限を指定できる。
2h ・ 4h ・ 1h のように正整数+時間単位( h )で指定する。優先順位は
granularity 明示 root 指定時の既存ルート issue 本文マーカー 既定 2h の順
(Step 1 で確定)。決定した値はルート issue 本文へ <! granularity: Nh として
永続化され、同じルートに対する update issue tree 実行時に継承される。
前提条件
gh CLI がインストールされ、認証済みであること( gh auth status で確認)
対象リポジトリへの Issue 書き込み権限があること
フロー
Step 1: 要件を分析してタスクを分解する
入力テキストまたはファイルから要件を読み込み、以下の観点でタスクを分解する。
粒度基準: 1 issue は実装 ${GRANULARITY} (既定 2h・ granularity で変更可)程度に収める。 超えると判断した場合は sub issue に再分解する
granularity の値は代入前に Claude 側でも同じ正規表現( ^[1 9][0 9] h$ )で検証し、
不一致なら このフェンスを実行せず ユーザーに再指定を求める(未信頼値を生成済みシェルへ
埋め込まない)。優先順位は使い方節のとおり、 granularity ルートのマーカー 既定 2h の順。
以降の Step は Step 1 で出力された GRANULARITY の値を使う(既定 2h と読み替えない)。
各タスクの依存関係・実行順を把握する
タスク数を集計し、Phase 分割の要否を判断する(目安: 10 件超で Phase 分割を検討)
分解結果をユーザーに提示し、Phase 構成・issue 数について確認を取る。
phase オプションが指定されている場合は該当 Phase のタスクのみ対象とする。
Step 2: Phase 構成を設計する
タスク数・依存関係をもとに Phase を設計する。
Phase は独立して開発可能な単位で分割する(例: Phase 1 基盤・Phase 2 機能・Phase 3 改善)
各 Phase に親 issue タイトル(Conventional Commits 形式推奨)を割り当てる
全体をまとめるルート(トラッキング)issue のタイトルを決定する
例: chore(global): 全 open issue の Phase 別トラッキング (YYYY MM DD)
タスクが少数(Phase 分割不要)の場合はルート issue + 子 issue の 2 階層構成にする。
Step 2.5: milestone を決定する
このツリーに割り当てる GitHub Milestone を決定する。ルート・Phase 親・子・sub issue の
全件に同一 milestone を適用する(ツリー単位で 1 milestone)。
root が指定されている場合は、ここで先に ROOT NUMBER を設定し、milestone の
継承・書き込みを行う前に OPEN 状態を検証する(closed なルートの milestone を
書き換えてから中断する事故を防ぐ。Step 3 側では再代入・再検証しない)。
milestone 非運用リポジトリのガード : milestone が明示されていない場合、リポジトリに
milestone が 1 件も存在しなければ(closed 含む)milestone 非運用リポジトリとみなし、
以降の確認をすべてスキップして MILESTONE は空のまま Step 3 へ進む
(milestone を使わないリポジトリの起票フローに確認を増やさない)。
優先順位は milestone root からの継承 ユーザーへの確認 の順。
milestone が指定されている場合: その値をそのまま MILESTONE として使用する
( root も同時指定されている場合、ルート側の milestone より milestone を優先する。
ルート側と異なる値の場合は、ルートの milestone も合わせて更新してよいかユーザーに確認する。
更新しないと回答された場合はツリー内で milestone が混在する点を伝えたうえで続行する)
milestone 未指定かつ root 指定時: 既存ルートの milestone を自動継承する
(milestone が取得できた場合のみユーザーへの確認は不要)
MILESTONE が空(既存ルートに milestone が未設定)の場合は自動継承とみなさず、
「どちらも未指定の場合」と同じユーザー確認フローへ進む(リポジトリに milestone が
存在するのにサイレントに milestone なしで進行しない。milestone が 1 件もない場合は
冒頭の非運用ガードが先に働くため、この確認には到達しない)。
どちらも未指定の場合、または root 指定時に継承すべき milestone が空だった場合:
milestone を割り当てるかユーザーに確認する。
割り当てる場合はオープン中の milestone 一覧を提示して選ばせるか、新規 milestone 名の
入力を受け付けて MILESTONE に設定する。割り当てないと回答されたら MILESTONE は
空のまま Step 3 以降へ進む(issue は milestone なしで作成される)。
ユーザーが一覧にない新規 milestone 名を入力した場合、 gh issue create milestone は
既存の milestone 名しか受け付けないため、使用前に milestone 自体を作成する。
同名の closed milestone が既に存在すると作成が 422(already exists)で失敗するため、
その場合は reopen するか別名にするかをユーザーに確認する。
root 指定時に継承すべき milestone が空でこのフローに合流した場合、決定した
MILESTONE を既存ルート issue にも反映する(子だけ milestone が付き、ルートが
未設定のまま残る不整合を防ぐ)。
Step 3: ルート(トラッキング)issue を作成する
ルート issue はツリー全体の進捗を管理するトラッキング issue として作成する。 ルート issue 自体には phase ラベルは付与しない (Phase 親以下の issue にのみ付与する)。
root 指定時は新規作成をスキップする。 phase での 2 回目以降の部分起票で
ルート issue を重複作成しないため、Step 2.5 で設定・OPEN 検証済みの ROOT NUMBER を
そのまま再利用する(ここで再代入・再検証しない)。
root 未指定の場合のみ、以下でルート issue を新規作成する。
表のプレースホルダー行は scripts/merge root body.sh (Step 6 の root 経路)が追記位置として読む。
文言を変えるときは同スクリプトの awk とテスト (n) を合わせて直す。
Step 4: Phase 親 issue を作成して紐付ける
Phase ごとに親 issue を作成し、sub issues API でルートへ紐付ける。
以下のスニペットは PHASE 変数で Phase 番号を切り替える。 phase 指定時はその番号を、
全 Phase 起票時は処理中の Phase 番号を設定する(タイトル・ラベルとも PHASE に追従させる)。
タイトル規約が feat(phase N): と異なるツリーでは上記の自動判定に頼らず、候補をユーザーに
提示して再利用すべき Phase 親を確認する。
PHASE NUMBER が空(既存の Phase 親がない)場合のみ、以下で新規作成してルートへ紐付ける。
Step 5: 子 issue・sub issue を作成して紐付ける
各タスクを issue として作成し、Phase 親へ紐付ける。粒度基準(既定 2h・ granularity )超のタスクはさらに sub issue に分解する。
issue 数が多い場合(50 件超が目安)は per page=100 パラメータを使用し、ページネーションで全件確認する。
Step 6: ルート issue 本文を Phase 別表で更新する
全 issue の作成が完了したら、ルート issue 本文の Phase 別表を実際の issue 番号・件数で更新する。
root での部分起票では本文を全置換しない。 既存ルートの本文には先行 Phase の表が
含まれるため、現在の本文を取得し、今回起票した Phase の行・セクションのみを追記・更新した
本文で gh issue edit する。全置換は新規作成( root 未指定)時のみ行い、その生成は scripts/create root body.sh に、
root 時のマージは scripts/merge root body.sh に任せる(本文生成ロジックを SKILL.md へ書かない)。
Step 3 の雛形のままのルート(Step 6 到達前に中断した起票の再実行)でも、表のプレースホルダー行
(作成後に更新) を今回の Phase 行へ置き換えて完走する。
root 指定時は scripts/merge root body.sh が既存本文を取得し、今回の Phase 行・セクションを
実ツリーから生成してマージする(Issue 556)。各コードフェンスは独立したシェルで実行され得るため、
このフェンスは Step 3 / Step 4 と同形にスクリプトを 3 レイアウトから自己完結的に解決する。
ROOT NUMBER(ルート issue 番号)・GRANULARITY(Step 1 で確定した粒度)・PHASE(Step 4 で確定した
Phase 番号 N)・PHASE NUMBER(その Phase 親 issue 番号)が未設定なら起動前に停止する。
終了コード (成功時の stdout 最終行は result=merged root=<n phase=<N 。エラーメッセージは stderr)
exit 意味 本文の更新
0 既存本文へ今回の Phase 分をマージし gh issue edit が成功 あり
1 引数不正( root ・ phase number は正整数、 phase は数字、 granularity は ^[1 9][0 9] h$ )、既存本文・Phase 親・sub issues・子孫の取得失敗、追記位置なし・Phase 行を出力不可、プレースホルダー残り・検査失敗、一時ファイル作成失敗 なし
2 前提不備( tree lib.sh を読み込めない、 gh ・ jq が無い) なし
その他 gh issue edit 自身の終了コード 不明(実状態を確認する)
マージの不変条件: Phase 行・セクションは実ツリー(sub issues API)からのみ作り、先行 Phase の表・自由記述は保持する /
issue タイトルは非信頼データとして & < バッククォート・バックスラッシュ・ を HTML 文字参照へ変換し改行を空白にする / プレースホルダーが残る本文では
gh issue edit しない(fail closed)/ 一時ファイルは成否によらず削除する / granularity マーカーは常に
GRANULARITY で書き直す / update issue tree の管理マーカー区間があれば内側だけを置換し、 <details 内(退避節)は対象外 /
マーカーが 1 組でない・除外後も同名見出しが複数ある・ <details が閉じていない本文は中止する(行内・行末の </details も閉じとして数えるが、除外〔素通し〕にするのは <details の内側で始まる行・開いたまま終わる行・行頭が素の <details / </details の行だけで、表行・見出しの行頭以外のタグ文字列は置換対象のまま。表行・見出しが開いたまま終わる場合も中止する。管理マーカー区間の内側〔マーカーが無ければ本文全体。コードフェンス内を除く〕にバッククォート・ <! ・ ・バックスラッシュを含む行、または許可していない HTML タグ〔 <details </details <summary </summary の属性の無い素の形を取り除いたあとに < が残る行。属性付きの <details ・ <span ・ <br 等〕を含む行があれば、タグが文字か構造か判定できないため exit 1 で中止する。 単独は中止しない)。詳細は scripts/merge root body.sh 冒頭コメントを参照。
root 未指定(新規作成)の場合は scripts/create root body.sh が実ツリーから本文を生成して更新する
(Issue 555)。ヘルパー( list subs 等)は両経路とも scripts/tree lib.sh を共用する。
同じ形式で、ROOT NUMBER と GRANULARITY が未設定なら起動前に停止する。
終了コード (成功時の stdout 最終行は result=updated root=<n phases=<k 。エラーメッセージは stderr)
exit 意味 本文の更新
0 本文を生成し gh issue edit が成功 あり
1 引数不正( root は正整数・ granularity は ^[1 9][0 9] h$ )、sub issues 取得失敗、Phase 親 0 件、Phase 番号決定不可、子孫取得失敗、プレースホルダー残り・検査失敗、Phase 行数不一致、一時ファイル作成失敗 なし
2 前提不備( tree lib.sh を読み込めない、 gh ・ jq が無い) なし
その他 gh issue edit 自身の終了コード 不明(実状態を確認する)
生成の不変条件: 表は実ツリー(sub issues API)からのみ作る / issue タイトルは非信頼データとして
& < バッククォート・バックスラッシュ・ を HTML 文字参照へ変換し改行を空白にする /
プレースホルダーが残る本文では gh issue edit しない
(fail closed)/ 一時ファイルは成否によらず削除する。詳細は scripts/create root body.sh 冒頭コメントを参照。
Step 7: 作成結果を報告する
検証
ルート issue の sub issues に各 Phase 親 issue が列挙されていることを確認する
各 Phase 親 issue の sub issues に子 issue が列挙されていることを確認する
gh issue view "${ROOT NUMBER}" でルート issue 本文の Phase 別表が正しく生成されていることを確認する
gh issue view "${ROOT NUMBER}" json body jq .body に <phaseN number ・ N ・ (作成後に更新) ・素の N セルが残っていないことを確認する(残っていれば Step 6 を再実行する)
MILESTONE を割り当てた場合、 gh issue view <N json milestone jq '.milestone.title'
でルート・Phase 親・子いずれも ${MILESTONE} と一致することを確認する
よくある失敗
問題 回避策
root を指定せず 2 回目の部分起票でルート issue が重複作成される 2 回目以降は必ず root <既存ルートissue番号 を渡す
sub issue id に issue 番号をそのまま渡す gh api .../issues/<number jq '.id' で database id を取得してから POST する
phase ラベルが存在しないリポジトリで issue 作成が失敗する Step 4 冒頭の gh label create "phase:${PHASE}" を必ず先に実行する
root 追記時に既存ルートの milestone が未設定なのに気づかず milestone なしで起票してしまう リポジトリに milestone が存在する場合、Step 2.5 は継承結果が空ならユーザー確認フローへ自動的に合流する(確認で milestone を選ぶとルート issue にも反映される)。milestone が 1 件もない非運用リポジトリでは非運用ガードによる milestone なし起票が正常動作
closed 親の下に open issue が残置される Phase 親を close する前に全子 issue の close を確認する
Step 6 の本文を手書きのプレースホルダーのまま gh issue edit してルート本文が雛形で上書きされる 実ツリーから表を生成する scripts/create root body.sh (新規作成)・ scripts/merge root body.sh ( root )を使う。検査ガードに引っかかったら本文を送らず中止される
Step 6 到達前に中断し、雛形のままのルートが残った root <ルート番号 を付けて再実行する。プレースホルダー行は今回の Phase 行へ置き換わる
granularity に 2 h ・ 2 ・ 0h 等を渡して中断される 正整数+h 形式( ^[1 9][0 9] h$ 。例: 2h ・ 4h )で指定する
注意事項
1 issue は粒度基準(既定 2h・ granularity で変更可)程度に収める。 超えると判断した場合は sub issue に分解する
issue タイトルは Conventional Commits 形式を推奨( feat: ・ fix: ・ chore: 等)
phase 指定で部分起票した場合、別 Phase の追加起票では 必ず root <既存ルートissue番号 を渡す (Step 3 の新規作成をスキップして既存ツリーへ継ぎ足し、Step 6 も全置換せず既存本文へ差分追記する)。起票後は update issue tree に同じルート issue 番号を渡して棚卸しする
ページネーション: sub issues が 100 件を超える場合は per page=100&page=N でページングして全件取得する
Step 6 の本文生成は新規作成が scripts/create root body.sh 、 root マージが scripts/merge root body.sh 。本文生成ロジックを SKILL.md へ書き戻さない(肥大とヘルパー重複の再発防止)
シェルコマンドの変数は必ず "${var}" でクォートする(コマンドインジェクション対策)
gh issue create は json 非対応 。issue URL を stdout に出力するため、 grep oE '[0 9]+$' で末尾の番号を抽出して変数に保持する
sub issues API の sub issue id は issue 番号ではなく database id (GitHub 仕様)。 gh api "repos/{owner}/{repo}/issues/<number " jq '.id' で id を取得してから POST する。番号をそのまま渡すと誤った issue を紐付ける/404 になる
phase ラベルは Step 4 冒頭の gh label create "phase:${PHASE}" color "0075ca" で issue 作成より前に必ず作成する(作成済みリポジトリでは no op)