大きすぎる/複数の関心事を含む既存 GitHub Issue を sub-issue に割り、親を umbrella に作り替える。「issue-split」「issueを分割して」「issueをsub-issueに割って」と指示されたとき。
Install
npx skillscat add kasiopeiya/claude-dev-template/issue-split Install via the SkillsCat registry.
/issue-split
大きすぎる、または複数の関心事を含む open な Issue 1件 を sub-issue(縦スライス)に割り、親を umbrella(子への入口)に作り替える。
Plan を割るのは /to-issues、既に Issue になっているものを割るのが本スキルである。 /to-issues は「親 Issue はクローズも変更もしてはならない」と定めており、親本文の作り替えを担当できない。その担当が本スキルである。
人間か /issue-check が起動し、AI が Phase 1 以降を実行する。
前提
- いつ割るかは人間が決める。 親 Issue の本文を書き換えるため、AI は「割った方がよい」と提案するまでに留める。例外は
--from-issue-checkの起動で、/issue-checkのレンズが割ると決め切っている。 - リポジトリのファイルは変更しない。 触るのは GitHub Issue(本文・ラベル・sub-issue 紐付け)だけ。
- 分割規則と子 Issue の本文テンプレートは書き写さない。 縦スライスの規則は `/to-issues`、本文テンプレート
<issue-template>とラベル判定は `/quick-issue` が正典。2箇所に持つと、片方が古いまま残る。 - 親はクローズしない。 すべての sub-issue が close されるまで親は open のまま置く(
/sweep・/issue-checkの「sub-issue が open な親は閉じない」ガードと揃える)。例外は `/issue-regroup` だけである。親の open な子が全部ブロッカー待ちになったときに限り、子を他の親へ移してこの親を close する。
Phase 1: 対象を読む
gh issue view <番号> --comments本文とコメントをすべて読む。決定はコメント側にだけ書かれていることがある。
既に sub-issue が付いていないか確認する。付いていれば、その範囲は割り済みなので対象から外す。
gh api graphql -f query='{repository(owner:"<owner>",name:"<repo>"){issue(number:<番号>){subIssues(first:50){nodes{number state title}}}}}'Issue が触れる領域の設計書(docs/design-hub.md 経由)とポリシー(docs/policy-hub.md)を、割り方を決めるのに要る範囲だけ読む。
Phase 2: 割るかどうかを決める
--from-issue-check なら、この Phase を飛ばして Phase 3 へ進む。 レンズが同じ表で「割る」と決め切っており、ここで判定し直すと、統合側が判定を決め直すことになる(review-subagent-lens-policy が禁じている)。
次の表を上から順に評価し、先に当たった行で確定する。割れない・割らないと判定したら、ここで終了し Issue には一切触らない。
| 判定 | 条件(1つでも当たれば該当) | どうするか |
|---|---|---|
| 割れない | ・本文だけでは縦スライスに割れない(仕様が未確定) | /grill-me → /to-plan → /to-issues の経路を案内して終了する |
| 割らない | ・割ると各片が単体でデモ・検証できなくなる(縦スライスにならない。ただし /to-issues の縦スライス規則が例外に挙げる開発の道具の立ち上げは、その道具だけの片にしてよい)・タスクが多いだけで関心事は1つ |
終了する。分量は割る理由にならない |
| 割る | ・タスク一覧が2つ以上の変更種別にまたがる(実装フローの Skill が2種以上になる) ・完了条件が、互いに独立して検証できる2つ以上の塊に分かれる ・目的の一文に「〜と〜」で関心事が2つ以上並ぶ |
Phase 3 へ進む |
「割れない」で終わるのは失敗ではない。仕様が決まっていない Issue を無理に割ると、決まっていないことが子の数だけ複製される。
ここで終了するときは、判定・当たった条件・次に取るべき経路を報告する。Phase 7 の報告表は割った場合のものなので使わない。
Phase 3: 分割案を人間に確認する
--from-issue-check なら確認を飛ばし、分割案をそのまま Phase 4 で起票する。 分割は GitHub Issue の操作だけで、誤っても子を閉じて親を戻せる。
分割案を番号付きリストで提示し、承認を得るまで直す。粒度・依存関係・統合や分割の要否をユーザーに問う(提示の型は /to-issues の「ユーザーに確認する」が正典)。
あわせて、親に残す内容(この変更が必要な理由・作るもの・トレース)と子へ移す内容を一覧で示す。親から消えるものを人間が見ないまま本文を書き換えない。
Phase 4: 子 Issue を起票する
分割案を、依存順(ブロッカーが先)に起票する。
本文は /quick-issue の <issue-template> に従う。人間が上から3節(「この変更が必要な理由」「対応方針」「タスク一覧」)を読むだけで、何の話で結局何をするのかが分かる型だからである。
分割ではそこに1節を足し、3節を落とす。足す節は「完了条件」の直後に置き、上の3節を動かさない。
- 今回作らないこと(と、作る条件):足す。親のスコープ境界を子へ渡し、実装者の「ついで」を止める
- ブロッカー:埋める。テンプレートにある節なので位置は動かさない。先に起票した子の実番号。無ければ「なし(すぐ着手できる)」
- 作るもの:落とす。「対応方針」と役割が重なる
- どう気づいたか:落とす。経緯は親にあり、子ごとに書くと同じ話が子の数だけ増える
- 親Issue:落とす。Phase 5 の紐付けで親子関係が見えるので、本文に持つと二重管理になる
親の各節は次のように振り分ける。
- この変更が必要な理由:同名の節へ、子のスコープに合わせて書き直す(丸写ししない)
- 作るもの(
/to-issues産の親では「対応方針」):「対応方針」の採る案と「いま→変えた後」の表に書き直す - 確定済みの決定:その子に効く決定を「対応方針」の根拠・却下した案へ、確かめた事実は「現状」へ
- 今回作らないこと(と、作る条件):同名の節へ、子ごとに書き分けて転記する
- タスク一覧・完了条件:同名の節へ該当分を移す(親からは消える)
- 実装フロー(使用するSkill):同名の節へ、その子が触れる変更種別だけに絞って転記する
- トレース(要件定義書との対応):親に残し、根拠となる機能ID・BR を子の「この変更が必要な理由」で名指しする(要件からの追跡を切らないため)
親に「確定済みの決定」節が無く「grill-me で確定した仕様」節がある場合(/to-issues が起票した Issue)も、扱いは同じである。
ラベルは ai-fixable / issue:needs-human-decision のどちらか一方を必ず付ける(判定は /quick-issue が正典)。boy-scout は付けない。issue:needs-human-decision を付けた子では、上から2番目の節が「対応方針」ではなく「人間に決めてほしいこと」になる。
親が issue:decided 付きなら、ai-fixable にした子にも issue:decided を付け、親の「対応方針」にある「人間が決めた名指し例外」の行のうち、その子に当たるものを書き写す。子は親で人間が決めた中身を分けたもので、新しい中身を足さないからである。印が無いと、/issue-check が子を同じ例外で差し戻す。
タスク一覧と完了条件は、起票前にポリシー(docs/policy-hub.md)・rules(.claude/rules/)と照合する。ポリシーに反する作業を親から引き継いだままにしない。
Phase 5: sub-issue として紐付ける
親と子の node id を取り、addSubIssue で紐付ける。
gh api graphql -f query='query($o:String!,$r:String!,$n:Int!){repository(owner:$o,name:$r){issue(number:$n){id}}}' \
-F o=<owner> -F r=<repo> -F n=<番号>gh api graphql -f query='mutation($p:ID!,$c:ID!){addSubIssue(input:{issueId:$p,subIssueId:$c}){clientMutationId}}' \
-F p=<親のid> -F c=<子のid>紐付けに失敗した子があれば、その番号を報告に残す。成功した分をロールバックしない——親本文のリンク一覧(Phase 6)があれば、紐付けが無くても親子は辿れる。
Phase 6: 親を umbrella に作り替える
gh issue view <番号> --json body --jq .body でスクラッチパッドに書き出し、Read → Edit で該当セクションだけを差し替えてから反映する。
gh issue edit <番号> --body-file <スクラッチパッド>/issue-<番号>.md- タスク一覧:sub-issue へのリンク一覧(
- [ ] #123 タイトル) - 完了条件:「すべての sub-issue が close されていること」
- 実装フロー(使用するSkill):「sub-issue を順に処理する」
- 作るもの:親のスコープ全体としてそのまま残す
- この変更が必要な理由・今回作らないこと・トレース・確定済みの決定:そのまま残す
「この変更が必要な理由」と「作るもの」を消してはならない。子はスコープの一部しか持たないので、全体の意図を保つ場所が親だけになる。
Phase 7: 報告する
- 親 Issue:#<番号>(umbrella 化済み/変更なし)
- 子 Issue:#<番号> ×N(ラベル・ブロッカー付き)
- 紐付け:成功/失敗した子の番号
- 親から消えた節:子へ移したタスク・完了条件
エラーハンドリング
- 対象 Issue が close 済み:割らずに終了する(close 済みの Issue は着手対象ではない)
- 対象が既に他の Issue の sub-issue:割ってよいか
AskUserQuestionで確認する(入れ子が深くなるため)。--from-issue-checkなら確認せずに割る addSubIssueが失敗する:その子の番号を報告に残し、他の子の処理は続けるgh issue editが失敗する:親の作り替えを中断し、起票済みの子の番号を添えて報告する。紐付けにも失敗した子があれば、その子の本文末尾に親 Issue 番号を追記して親子を辿れるようにする- 親 Issue に別セッションの更新が入っている:上書きせず中断し、その事実を報告する
使用方法
/issue-split 123
/issue-split 123 --from-issue-check--from-issue-check は /issue-check だけが付ける引数である。判定と確認をどちらも飛ばすので、人間が打つときは付けない。
引数: $ARGUMENTS