概要
「まず計画をドキュメントに書かせてから実装させる」──この流れ自体は、各種コーディングAIの Plan モードも出てきて、だいぶ定番になってきました。私も spec-kit で Spec→Plan→Tasks→Implementation を回しているのですが、使っていて感じたのは spec-kitだけだと、Plan と Tasks の間で抜けが出る という点です。
典型的には、Tasks通りに実装しても画面が出ない/ボタン押下後の処理が繋がらない/プロセス間通信が噛み合わない、みたいな「動くまでの道筋」が抜けます。
そこで、人間の設計でいう “ユースケース粒度とクラス粒度の間” を埋める発想を借りて、arc42 Runtime View × C4 の枠組みで「粗い全体シーケンス」を作らせるフェーズを追加しました。結果、AIの迷走もレビューの手戻りもかなり減ったので、その作り方と組み込み方を共有します。
狙い: SDD/spec-kit既存ユーザー向けに、抜けやすい工程の正体と実装可能な対策を示す
最初に結論まとめ
- Plan と Tasks の間に不足しているのは、ドメインレベルくらいの荒い用語同士を繋ぐシーケンスだと思う
- この間を埋めるという考え方は、ICONIXプロセスでいうところの、ロバストネス分析に似ている
- とは言えロバストネス分析はAIにやらせづらいので、その考え方を別の方法で実現すれば良い
- arc42 Runtime View × C4という既存の名称を借りて、AIへ端的に説明(独自の説明より学習済み名称が伝わりやすい)
- そのドキュメントを作成するためのGitHub Copilot Agent定義を作り、PlanとTasksの間で実行するようにした
- AIの迷走がだいぶ減り、人間によるレビューも精度が上がった!
説明
各コーディングAI系にPlanモードが実装されたりなどもあって、「まず先に計画をドキュメントに書かせてから、コードを書かせる」というのはだいたいベストプラクティスとして確定してきたのかなと思います。じゃあ、spec-kitを使えば問題解決!かと思えば、そこまで万能では無さそうです。私の運用ではもう一工夫加えることで、かなりコードの精度が上がりました。
spec-kit について軽く
spec-kit は、めっちゃざっくり言うと「仕様→計画→タスク→実装」を、Instructionやスクリプトで与えて回す仕組みです。こんな感じです。
- Specify:要求仕様(ゴール)を書く
- (オプション)Clarify:曖昧な点を洗い出して埋める
- Plan:実現方法の方針・構造を書く(フレームワーク選定などもここ)
- Tasks:Plan を実装タスク一覧に落とす
- (オプション)Analyze:Spec〜Tasksの対応付けの漏れ、矛盾、曖昧さをチェック
- Implementation:Tasksに従って実装
※最初のConstitutionはこの記事の趣旨とちょっとズレるので省略しました
ただし、Plan と Tasks の隙間で漏れが出やすい
私が引っかかったのはここです。
- Plan:実現したい機能が書いてある(何を作るかは分かる)
- Tasks:クラス名やファイル名レベルで箇条書きされる(何をいじるかも分かる)
- でも、その間にあるはずの 「クラスや関数が、どう繋がって、機能を実現するのか」 が抜けがち
結果として、Tasks通りに実装しても部品はできるが動く物にならない。
Windowsアプリだと例えば、
- 画面が出てこない
- ボタンを押した後の一連の処理が繋がってない
- プロセス間通信が噛み合わずにエラー
といった抜けが出やすい印象です。
ユースケース粒度とクラス粒度の間を埋めてロバストにする
何が足りないのかと考えていくと、ユースケース記述の荒い粒度から一気にクラス図・シーケンス図の細かい粒度に落とすのは難しいという、古くからある設計の問題だと気付きます。
人間向けの解決策の例でいうと、ICONIXプロセスの「ロバストネス分析」がまさにこの穴埋めです。
- ユースケース(文章)の曖昧さを
- Actor / Boundary / Entity(+Control)の責務に割り振って
- 漏れ抜けが無いように対応関係を保ちながらクラス図・シーケンス図まで詳細化していく
といった感じの考え方です。(私の理解で要約してます)
AI向けにも同様に、間を埋めるフェーズを入れることで、問題が改善します。
LLM向けのロバストネス分析は何が良いか
とはいえ、プロセスをAIへ全部説明するわけにもいきません。LLM相手には、新しく説明するよりも学習済みの単語を伝えた方が話が早いです。また、人間のために曖昧さを許容するロバストネス図よりも、曖昧さのないシーケンス図の方がLLMには向いていそうです。
というわけで、次の2つを選びました。
- arc42 Runtime View を「何を書くかの枠」にする(主要シナリオの相互作用を書く)
- C4 を「名前の粒度の枠」にする(System / Container / Component などのレベル感)
どちらもWeb上で情報が手に入りやすく定義も明確なので、LLM向きだと思います。
Plan と Tasks の間に挟む「粗い Runtime View」
実際に書かせてみると、次のようなものが出てきます。
全体を見たい場合はこちらのMarkdownファイルです。PlantUMLで書かれているので、 VSCode の Markdown Preview Enhanced などでプレビュー出来ます。
ちなみにもう少し複雑なサンプルとして、プロセス間通信を行うものだとこのような感じになります。
狙いの効果は出ている
Userによる「登録ボタン」という入り口からDBまでの流れがもれなく書かれていますね。LLMはドキュメント(コンテキスト)に書いてあることは高確率でちゃんとやってくれるので、このドキュメントがあれば、このシーケンスの流れの実装が抜ける確率はかなり減ります。つまり、「画面(入り口)が無い」とか「途中で繋がってない」という問題がこれでだいぶ防げます。
追加メリット
人間が見る上でも、詳細に踏み込んでいない Plan やコード作業の箇条書きまで踏み込んでしまった Tasks と比べて、だいぶコードの全体像が分かりやすいと思います。
狙いとは違った副産物ですが、この荒さで全体像が書かれているとだいぶ人間が一目でレビューしやすいので、AIの誤解にもこの段階で気付きやすくなります。
このやり方、だいぶ効果がありそうです。実際、使ってみて何度か助けられてます。
VSCode&GitHub Copilot向けの追加のAgentとして組み込む
使えそうなので、spec-kitに追加して使っていきましょう。spec-kitの既存フェーズをカスタマイズするよりも、間にこのドキュメントを作るフェーズを追加するのが良さそうです。
spec-kitはVSCodeのGitHub Copilotの場合、Agent(~.agent.md)の定義が入っていて、それを使って実行出来ます。なので、このドキュメントを作るフェーズをAgentの定義で追加すれば便利です。 runtime-evidence という名前にしました。次のリポジトリで公開しています。
これを使用して、次のように間に挟んで実行すると上手く行きます。
- speckit.plan
- runtime-evidence
- speckit.tasks
まとめ
spec-kit を使っただけでは解決しなかったPlanと実装(Tasks)の間で抜けが出る問題を、改善出来る一つの方法を確立しました。Agentとして組み込むことで、spec-kitとGitHub Copilotを使った開発プロセスに無理なく組み込めたと思います。
AIエージェントでのコーディングはかなり色々なことができそうですが、工夫して作り込んでいく必要もありそうです。どんどん工夫して改善していきましょう!



