株式会社ホコサキ

github/spec-kitで学ぶ仕様駆動開発とAI出力品質の関係

天京祐輔
天京祐輔
github/spec-kitで学ぶ仕様駆動開発とAI出力品質の関係

Claude CodeやCursorを使っていると、同じような機能追加を依頼しても、セッションが変わるたびに微妙に違う実装が返ってくる経験、ありませんか。
エラーハンドリングの粒度が違う、ファイル分割の方針が変わる、命名規則がなんとなく揺れる。
「モデルが不安定なのかな」と思いがちですが、実はそれ、モデルの問題ではないことがほとんどです。

AIエージェントの出力がブレる、その構造的な理由

AIエージェントは、入力に含まれていない情報を「確率的に補完」して動きます。
仕様が曖昧なまま「ユーザー認証機能を追加して」と伝えると、エージェントはセッションIDの管理方法、トークンの有効期限、エラー時の挙動といった無数の前提を、その場で独自に判断して埋めていきます。

この補完の結果は、プロンプトの微妙な言い回し、会話の流れ、モデルの内部状態によって変わります。
同じ機能追加を5回依頼すれば、5通りの実装が返ってくる——これは誇張ではなく、AIエージェントの設計上の必然です。

LinkedInで話題になったAmeyaKanitkar氏の投稿では、同じspecを使ってClaudeとCodexに5回ずつ実装させると、実装が分岐する箇所が一致することを指摘しています。
「エージェントが意見を割る箇所こそ、specが曖昧な箇所だ」という観察は、実務的にかなり鋭い視点です。

GitHubが2,500件超のエージェント設定ファイルを内部分析した結果も、同じ方向を示しています。
出力品質のばらつきを説明する要因として、モデルの選択よりも 仕様の質 のほうが大きかった、というものです。
「どのモデルを使うか」より「何を渡すか」が先に効いてくる。

「同じプロンプトで複数回走らせたときに実装が分岐する箇所」は、仕様の曖昧さを可視化するシグナルです。
そのシグナルを無視してモデルを変えたり、プロンプトを微調整したりしても、根本は変わりません。
解決すべきは仕様のレイヤーにあります。

Spec-Driven Developmentとは何か、従来の仕様書と何が違うか

Spec-Driven Development(SDD)は、実装を始める前に「何を・なぜ」を文書化し、その仕様をソース・オブ・トゥルースとして扱う開発スタイルです。
コードは仕様から生み出されるものであり、仕様はコードの付属物ではない——これがSDDの根本にある考え方です。

従来の仕様書と何が違うのか、というのが正直気になるところですよね。
一番の違いは、 誰が読むか という設計思想にあります。

従来の仕様書は「人間が読む完成ドキュメント」として書かれます。
レビューを経て承認され、変更するには手続きが要る。
SDDのspec.mdは違います。
「AIが読むコンテキスト」として設計されていて、変更前提で、不明点は [NEEDS CLARIFICATION] というタグで残しながら段階的に明確化していくアジャイルな性質を持ちます。

半年後の改修シナリオで考えてみると、この違いがよくわかります。
従来の開発では、半年前に書いたコードを読み解き、実装意図を推測しながら修正を加えます。
SDDでは、spec.mdを更新して計画フェーズと実装フェーズを再実行するだけで済む。
AIが書いたコードを読み解く必要がなく、仕様が変わったことをエージェントに伝えれば、整合した実装が得られます。

TDDとの関係も整理しておきます。
SDDは「外側のループ」です。
仕様を固め、計画を立て、実装へと進む大きな流れを指します。
TDDは「内側のループ」で、Red→Green→Refactorの実装フェーズの品質サイクルです。
両者は対立しません。
SDDで仕様を固めてからTDDで実装品質を積み上げる、という組み合わせが自然な形です。

github/spec-kitのファイル構成を読み解く

spec-kitが生成するディレクトリ構成は、大きく二層に分かれます。

.
├── .specify
│   ├── memory
│   │   └── constitution.md
│   ├── scripts
│   │   └── bash
│   │       ├── check-prerequisites.sh
│   │       ├── common.sh
│   │       ├── create-new-feature.sh
│   │       ├── setup-plan.sh
│   │       └── setup-tasks.sh
│   └── templates
│       ├── spec-template.md
│       ├── plan-template.md
│       └── tasks-template.md
└── specs
    └── 001-create-taskify
        └── spec.md

.specify/ 配下はプロジェクト横断の「型」を管理する場所で、specs/ 配下に機能ごとのspec.mdが積み上がっていきます。

constitution.md は、このツールキットの中で最も重要なファイルです。
プロジェクトの技術スタック、アーキテクチャ上の制約、命名規則、テスト方針といった「変えてはいけない前提」を記述します。
全フェーズで参照される「プロジェクトの憲法」として機能するため、ここがしっかり書かれていれば、個々のspec.mdで繰り返し書く必要がなくなります。

spec-template.mdの設計思想で面白いのは、 WHATとWHYだけを書き、HOWを書かない という制約です。
「どう実装するか」はplanフェーズで決める。
specフェーズでHOWを書いてしまうと、エージェントが仕様と実装の境界を混同して暴走しやすくなります。
不明点は [NEEDS CLARIFICATION] タグで残しておき、clarifyフェーズで埋めていく。

## Overview
ユーザーがタスクを作成・完了・削除できるWebアプリケーション

## Problem Statement
現状、タスク管理をスプレッドシートで行っており、
複数人での更新が競合する問題がある

## Functional Requirements
- ユーザーはタスクを作成できる
- ユーザーはタスクを完了済みにマークできる
- ユーザーはタスクを削除できる

## Open Questions
- [NEEDS CLARIFICATION] 削除したタスクは物理削除か論理削除か
- [NEEDS CLARIFICATION] タスクの優先度設定は必要か

planフェーズへ進む前には、Phase -1 Gatesと呼ばれる入場チェックがあります。
代表的なものを挙げると、Simplicity Gate(プロジェクト数は3つ以内か、未来の拡張性を先取りしていないか)、Anti-Abstraction Gate(フレームワークを直接使っているか、独自の抽象レイヤーを作っていないか)、Integration-First Gate(API仕様を先に定義しているか)の3つです。
ゲートを通らない場合は、plan.mdにその旨を記録して先へ進む設計になっています。

フロー全体は clarify → specify → plan → tasks → implement の順です。
clarifyで曖昧さを潰し、specifyでspec.mdを生成し、planでplan.mdとしてHOWを決め、tasksでtasks.mdに実装単位を分解し、implementで実際のコードを生成する。
各フェーズの成果物がファイルとして残るため、意思決定の履歴が自然に蓄積されます。

スキルファイル・DESIGN.mdとの役割の違いと、実務での始め方

Cursorの .cursor/rules/ やClaude CodeのCLAUDE.mdを使っている方は多いと思います。
これらとspec-kitは何が違うのか、「どちらを使うべきか」と迷う場面もあるはずです。
結論から言うと、 どちらかを選ぶのではなく、上流から下流の順に書く という使い分けです。

上流から下流へのレイヤーを整理するとこうなります。

  • constitution.md:プロジェクト全体の技術的前提・制約。全フェーズで参照される不変の原則
  • spec.md:機能単位のWHAT(何を作るか)とWHY(なぜ作るか)。実装前に書く
  • plan.md:HOW(どう作るか)の技術計画。アーキテクチャ選定・技術的判断を記述する
  • DESIGN.md:より詳細な設計書。plan.mdと役割が近いが、既存プロジェクトでの慣習として使われることが多い
  • スキルファイル(.cursor/rules/ や CLAUDE.md):実装レイヤーへの指示。コーディングスタイル・ツール設定・エージェントの振る舞いを制御する

spec.mdはWHATの仕様書、DESIGN.mdはHOWの設計書という役割分担です。
スキルファイルはさらに下流にあり、「どう書くか」の実装指示を担います。
上流が曖昧なまま下流だけ整備しても、エージェントの出力品質は安定しません。

既存プロジェクトへの適用も現実的な選択肢です。
既存コードを逆引きしてspec.mdを書くことで、次の改修から仕様ドリフトを防ぐ入口になります。
「このコードは何のために存在するのか」をspec.mdとして書き起こす作業は、コードレビューよりも本質的な議論を引き出すことが多いです。

では実際にどう始めるか。
「全部書いてからでないと実装できない」という誤解が、SDDの導入を遠ざけがちです。
実際には、 specを書いてclarifyを回してからplanに進む という最小ループを、新機能単位で回すのが現実的な入口です。

まずconstitution.mdを作るところから始めます。
最小限の記述でも、エージェントへの入力品質は大きく変わります。

# Project Constitution

## Tech Stack
- Language: TypeScript
- Framework: Next.js 15 (App Router)
- Database: PostgreSQL (Prisma)
- Testing: Vitest

## Constraints
- Node.js 20以上
- 外部APIへの直接依存は services/ 配下に隔離する
- 環境変数は .env.local で管理し、コードにハードコードしない

## Principles
- シンプルさを優先する。抽象レイヤーは必要になってから追加する
- テストは実装と同じPRに含める

constitution.mdができたら、次の新機能でspec.mdを試作します。
冒頭セクションだけでも書いておくと、clarifyフェーズで穴が見えてきます。

# Spec: ユーザー通知機能

## Overview
ユーザーが設定した条件を満たしたとき、メール通知を送る

## Problem Statement
重要なイベントをユーザーが見逃すケースが発生している

## Functional Requirements
- ユーザーは通知条件を設定できる
- 条件を満たしたとき、登録メールアドレスに通知が届く
- ユーザーは通知のオン/オフを切り替えられる

## Open Questions
- [NEEDS CLARIFICATION] 通知の遅延許容時間はどの程度か
- [NEEDS CLARIFICATION] 通知の重複送信をどう防ぐか

このspec.mdをエージェントに渡してclarifyを実行すると、[NEEDS CLARIFICATION] の箇所を中心に質問が返ってきます。
その回答を埋めてからplanへ進む——このループが「AIに渡す前にやること」の実体です。

チーム開発では、specのレビューがPRレビューより重要になります。
「エージェントが実装の分岐点で迷う箇所=specの曖昧な箇所」という視点でレビューすると、コードレビューでは見えなかった仕様の穴が浮かび上がります。
半年後の改修でも、spec.mdを更新してplanとimplementを再実行するだけで済む。
「仕様を先に書く」という習慣は、短期の開発速度だけでなく、長期のコードベースの保守性にも効いてくる投資です。


株式会社ホコサキは、山口県宇部を拠点にWeb制作・業務システム開発・AI活用支援を手がけています。
AIエージェントを使った開発プロセスの整備や、spec-kitのような上流設計の導入支援も対応しています。
気になることがあれば、お気軽に お問い合わせ からどうぞ。

    github/spec-kitで学ぶ仕様駆動開発とAI出力品質の関係 | 株式会社ホコサキ