コーディングエージェントに一段落ぶんの意図を伝えると、数分で数百行のコードが返ってくる。そんな時代になった。

では、そのコードは頼んだとおりに動くのだろうか。書くのは簡単になったが、「意図どおりか」を確かめる作業は今も難しい。

これまで仕様書は、手間ばかりかかるものと見られがちだった。書いた端からコードとずれていく文書だったからだ。

エージェントが実装を書くようになると、事情が変わる。機械が実装を担うなら、「何を作りたいのか」を記した文書がいちばん大事な成果物になる。

OpenSpecは、その文書を実用的にしようとする試みだ。仕様駆動開発のための、軽くて設定しやすいフレームワークである。変更が何をするべきかを記録し、今の挙動との違いをはっきり示す。

人間とエージェントが同じ資料を見られるようにもする。古くからある問いが、新しい場面でまた顔を出す。

どこまでなら構造が助けになるのか。どこからは足かせになるのか。目新しさが薄れたあとも、この習慣は続くのだろうか。

この記事のポイント

  • エージェントがコードを書く時代、仕様は意図を残せる唯一の記録であり、人間がエージェントの速さで確認できる唯一のものでもある。
  • Gitで管理するテキストの仕様なら、コードと同じレビュー、差分、履歴の道具をそのまま使える。
  • 「現在の正しい状態」と「提案された変更」を分けると、コードができる前に意図を承認できる。

なぜ仕様がまた大事になったのか

チャットで進める開発では、意図はプロンプトの中にしかない。セッションが終われば、そのプロンプトも消える。

誰もレビューせず、版も管理せず、あとから監査することもない。エージェントが読み違えたとき、手がかりは生成されたコードだけだ。

ところがコードを1行ずつ読むやり方では、エージェントの速さに追いつけない。

仕様は、この状況を逆転させる。残り、版を管理でき、レビューと監査ができ、人間がじっくり読める短さに収まる。

目的は、見栄えのいい文書を作ることではない。失敗を未然に防ぐことだ。あいまいなプロンプトを渡すと、エージェントはもっともらしいが間違った選択に流れやすい。

「キャッシュを追加して」と頼んだとしよう。エージェントは、違う層にキャッシュを置くかもしれない。

無効化の方法に危うい手を選ぶかもしれない。ほかの部品が頼りにしている挙動を変えてしまうかもしれない。

ひとつひとつの選択は、単体で見ればもっともらしい。仕様があれば、コードが生まれる前に選択肢を絞れる。勘違いは、直すのが安いうちに見つかる。

次の表は、意図を運ぶ2つの方法を比べたものだ。

観点会話のプロンプト版管理された仕様
寿命セッションとともに終わるリポジトリとともに残る
レビューほとんどされないプルリクエストで確認される
監査あとから再現しにくい版管理に全履歴が残る
範囲の管理際限がない書かれた要件で区切られる
共有される資料1人と1つのエージェントにしか見えないチーム全員とすべてのエージェントに見える

仕様には、本番で動くエージェントのために標準的な土台をそろえる、という大きな流れも関わっている。

コーディングエージェント向けにGitと結びついた永続的な記憶を持たせる手法も、同じ要請から生まれた。ただし、2つの道具の役割は違う。

  • 記憶のツールは、エージェントがコードベースについて学んだことを残す。
  • 仕様のフレームワークは、エージェントが何を頼まれ、それはなぜだったのかを残す。

両方がそろうと、エージェントはセッションをまたいでも、構造のある長続きする文脈のもとで確実に働ける。

左側は会話型プロンプト方式を示し、ユーザが直接プロンプトを入力してAIエージェントがコードを生成するが、セッション終了で履歴が消失する流れ。右側は仕様書ベースワークフローを示し、ユーザが仕様書を作成し、レビュープロセスを経てAIエージェントが生成したコードをGitで管理し、監査可能な状態で履歴が保持される流れ。両者の違いが視覚的に対比されている。

図2:会話型プロンプトと仕様書ベースのワークフロー比較

「軽い」と「設定できる」は実際に何を指すのか

OpenSpecの中心にある主張は、こうだ。

仕様のフレームワークは、儀式めいた手続きを増やさず、チームのほうに合わせて形を変えるべきだ。この主張が頼りにする「軽い」と「設定できる」という2つの言葉には、それぞれ具体的な約束があり、具体的な危うさもある。

この節のポイント

  • 軽いとは、仕様をGitにテキストで置き、言葉数を絞り、特定の製品に縛られないこと。
  • 設定できる自由には、統一感を失う代償がある。選択肢の多さより、良い初期設定のほうが大切だ。
  • 構造と柔軟さの釣り合いは、チームが何を作っているかで変わる。

「軽い」の中身

「軽い」には、3つの具体的な約束がある。

  • コードのそばにあるテキスト。 仕様はリポジトリの中にあり、別のツールには置かない。
  • 少ない語彙。 先に学ぶ必要のある重い書式ではなく、ひと握りの概念だけで動く。
  • 縛られないこと。 特定のエディター、モデルの提供元、ホスト型サービスに依存しない。

仕様がGitのテキストなら、コードと同じプルリクエストの流れに乗る。

差分も取れる。変更は履歴にも残る。衝突の解消のしかたも、コードと変わらない。

仕様の変更は、別の場所で管理する別の文書ではなく、コミット履歴の一部になる。要件を変えることが、記録に残り、レビューできる出来事になるわけだ。

設定できることの代償

柔軟さがあれば、チームは自分たちの領域に合わせて、テンプレート、ディレクトリの構成、作業の段階を調整できる。

ただし、設定できる項目が増えるたび、統一感が崩れる場所も増える。 チームごとに使い方が違うと、同じコードベースの中でも仕様の見た目がそろわなくなる。

すると、エージェントもレビュアーも、共通の構造という恩恵を失う。

難しいのは、良い初期設定を選ぶことだ。フレームワークは、利用者の代わりにほとんどの判断を済ませておき、本当に役立つ選択肢だけを残すのがよい。そうしないと、判断を支えるどころか、先送りするだけになる。

構造が少なすぎる場合と多すぎる場合の釣り合いは、チームによって違う。

失敗の型現れ方結果
簡素すぎるチームが独自の決まりを作る仕様がばらばらになり、エージェントへの入力も不ぞろいになる
決めすぎるどんな変更にも重いテンプレートと段階が要る技術者が負担と感じ、迂回するようになる
ほどよい強い初期設定と、意味のある少数の選択肢小さな変更を遅らせずに、仕様の統一感を保てる

どんな組織にもぴったり合う設定は存在しない。決済基盤を作るチームなら、社内ツールを試作するチームより、多めの構造を受け入れるかもしれない。

フレームワークの役目は、どちらのチームも、相手のやり方を押しつけられずに使えるようにすることだ。

提案から実装まで:変更のライフサイクル

エンジニアリングの仕事の多くは、ゼロから作ることではなく、既存のシステムを変えることだ。だから、使える仕様フレームワークは、変わらない完成形を書くだけでなく、変更そのものを扱えなければならない。

この節のポイント

  • 変更は、全面的な書き直しではなく、現在の仕様との差分として書く。
  • 「現在の正しい状態」と「提案された差分」を分けると、コードができる前に承認できる。
  • 仕様が役立つかどうかは、変更の種類しだいだ。

4つの段階

OpenSpecのライフサイクルは、4つの段階で進む。

  1. 差分を提案する。 変更を、現在の仕様との違いとして書く。全面的な書き直しにはしない。
  2. 影響をはっきりさせる。 提案の中で、どの既存の挙動が変わり、どれが変わらず、何がそれに依存しているのかを示す。
  3. 実装タスクを導き出す。 承認された差分から、人間やエージェントが取り組む具体的なタスクを作る。
  4. 変更を本体に戻す。 承認されて実装が終わったら、差分を本体の仕様に統合する。それが新しい「現在の正しい状態」になる。

「現在の正しい状態」と「提案された差分」を分けておくと、エージェントを使う場面では、次の3つの点で特に効く。

  • レビュアーが、区切られた成果物を見られる。 コードができる前に、変更の明確な説明を承認できる。
  • 勘違いが早く表に出る。 差分の中の誤った前提なら、コメント1つで直せる。同じ前提がマージ済みのコードに入り込むと、やり直しの1サイクルが必要になる。
  • エージェントが、要件をこっそり書き換えられない。 仕様が、レビューを受けた別の成果物であれば、エージェントは自分が作ったものに合わせて要件を調整できない。

この習慣が報われるのはいつか

この習慣には、負担もある。1行の修正や誤字なら、差分を書く手間のほうが大きいかもしれない。仕様を書く価値のある変更と、その場で直したほうが早い変更とを、チームではっきり分けておく必要がある。

レビューの関門にも、似た緊張がある。承認の段階は、明確な判断を迫るので、結果を良くすることがある。

一方で、レビュアーが仕様をよく読まずに承認するなら、形だけの儀式に落ちてしまう。関門が役立つのは、そこに立つ人が中身と向き合うときだけだ。

中心の問いは、差分を書くことが結果を良くするのか、それとも実装を遅らせるだけなのか、である。答えはおそらく、変更の種類で変わる。

実務者の報告では、あいまいさが大きい場面ほど効果が大きいという。上の議論とは合う話だが、厳密に測られたわけではない。

変更の種類仕様の価値の見込み理由
複数のシステムやチームにまたがる高い影響の分析で、システム間の破綻を見つけられる
受け入れ基準があいまい高い基準を書くことで、あいまいさが表に出る
公開されている挙動やAPIを変える高い利用する側に、明確な記録が要る
影響が限られ、よく分かっている修正低い手間が効果を上回りそうだ
試作段階の実験低い〜中程度要件がすぐ変わるのが前提になる

人間とエージェントをつなぐ窓口としての仕様

良い仕様は、3つの仕事を同時にこなす。ひとつめは、あいまいな意図を区切られたタスクに変えて、エージェントの選択肢を絞ること。ふたつめは、「完了」をエージェントが確かめられる形で定めること。

みっつめは、生成された行を全部読まなくても、人間がレビューできる記録を残すことだ。ここには、読み手が2種類いるという難しさがある。

機械が動けるほど正確でありながら、プロダクトオーナーが承認できるほど読みやすくなければならない。

この節のポイント

  • 仕様は、あいまいな目標ではなく、検証できる基準を書くと効く。
  • エージェントは、出力を確かめて絞り込む制約の中のほうが、よく働く。
  • 監査できる仕様があれば、失敗したとき、何が悪かったのかを推測に頼らず調べられる。

基盤の側でも、エンジニアは似た問題に直面している。

エージェントが確実に使えるように、データの層やAPIを設計する場面だ。そこでは、意味の明確さと、はっきり定義された取り決めが、エージェントの成否を左右する。要件も同じである。

仕様書が人間とエージェント双方の理解を統一するインターフェースとして機能する構造を示す図。仕様書は4つの要素(現在の状態、提案される変更、検証基準、制約条件)で構成され、これらが共通理解の統一を通じて実行・検証へと導く流れを表現している。

図6:OpenSpec仕様書の構造要素と人間・エージェント間の理解統一メカニズム

大事なのは形式より明確さ

最大の危険は、根拠のない安心感だ。きれいに整った仕様でも、間違った前提を含むことはある。

「性能を改善する」という要件は、エージェントにも人間にも役立たない。形式ばって見えるだけだ。構造は助けになるが、実際の働きをするのは明確さである。

検証できる場面と、はっきりした要件の書き方は、書かれたことと意図したこととの隔たりを縮める。ただし、なくしてしまうことはできない。その差がいちばんよく現れるのが、受け入れ基準だ。

あいまいな要件検証できる要件
「もっと速くする」「検索クエリの95パーセンタイル応答時間を100ミリ秒未満にする」
「エラーをうまく処理する」「上流がタイムアウトしたら、retry-afterヘッダー付きのHTTP 503を返す。部分的な結果は決して返さない」
「より多くのユーザーに対応する」「同時5,000セッションを維持し、エラー率を0.1%より上げない」
「セキュリティを向上させる」「有効なトークンのないリクエストは拒否し、拒否のたびに送信元IPと時刻を記録する」

良い仕様は、制約とトレードオフも、はっきり書く。書かれていなければ、エージェントは間違った目標に向かって最適化するかもしれない。誰も書き留めなかった一貫性の保証を捨てて、遅延の目標を満たすことがある。

テストの入力だけを特別扱いして、テストを通すこともある。何を変えてはいけないかを書くことは、何を変えるべきかを書くことと同じくらい大切な場合が多い。

ハーネスがエージェントの働きを高める

本番向けのエージェントに関する最近の取り組みからは、より大きな教訓が見えてくる。

エージェントは、自由に推論させるより、出力を制約し、確認し、ふるいにかける「ハーネス」の中に置いたほうが、よい成果を出しやすい。1

仕様は、計画と実装の段階のためのハーネスにあたる。エージェントには、定められた目標、確認できる「完了」の定義、判断を記録する場所が与えられる。

どれもが、もっともらしいが間違った出力の入り込む余地を狭める。

チームが期待する効果は、はっきりしている。やり直しの回数が減り、レビューが分かりやすくなり、実装中のあいまいさも減る。

ところが、仕様駆動開発でその効果が出るという証拠は、今のところ大半が体験談にとどまる。きちんと評価するなら、仕様がある場合とない場合でエージェントの出力を、多数のタスクにわたって比べる必要がある。

モデルの能力とプロンプトの質も、そろえなければならない。この種の研究は、まだ大規模には行われていない。

それまでは、改善したという主張は、もっともらしい仮説として受け取ったほうがよく、確立した結果とは言えない。

仕様を監査できるようにする

ハーネスの考え方からは、フレームワーク自体も監査できるべきだ、という結論も出てくる。エージェントの出力がおかしくなったとき、チームは次の3つを再構成できなければならない。

  • エージェントが受け取った仕様。 要件が間違っていたのか、読み違えたのか。
  • エージェントが決めたこと。 仕様が何も語っていない部分で、どんな選択をしたのか。
  • そう決めた理由。 記録された理由があったのか、それとも隙間を推測で埋めたのか。

この記録がなければ、エージェントの失敗を調べる作業は、当て推量になる。記録があれば、失敗は次の仕様を良くする教訓になる。

導入の現実、残された問い、これから

設計が良いだけでは、フレームワークは成功しない。目新しさが薄れたあとも、チームが使い続けてこそ成功と言える。仕様駆動開発には、実際の現場で表に出てくる、いくつかの現実的な障害がある。

  • 同期。 速く動くコードに仕様を合わせ続けるのは難しい。古くなった仕様が1つあるたび、ほかの仕様への信頼も削られる。
  • 古くなった文書。 本体に戻されず、廃止もされない仕様がたまっていく。人もエージェントも、それに惑わされかねない。
  • 最初にかかる手間。 エージェントのおかげで、コードを書くのがほぼ無料のように感じられる。そのため、技術者は、遅くなりそうに見える手順に抵抗する。
  • 価値の証明。 チームが取り入れるのは、レビューが速くなり、バグが減り、引き継ぎが明確になる道具だ。作業手順が整うだけでは、支持はなかなか得られない。

この節のポイント

  • 仕様が定着するのは、コードとの同期が保たれ、実際に役立つと示せたときだけだ。
  • 規模の拡大と、チームやツールをまたぐ標準化は、まだ決着していない。
  • 今問われているのは、仕様がどんな形になるのか、そしてチームが一貫して使うのか、ということだ。

ちょっと立ち止まって

エージェントや同僚が、動きはするけれど意図とは違うものを作った。そんな最近の場面を思い出してみてほしい。すれ違いは、どこから始まっていただろうか。

コードの中だっただろうか。それとも、その前に交わされた言葉の中だっただろうか。仕事を始める前に、「完了」とは何かを書き留めていたら、その一文で問題に気づけていただろうか。

提案から実装までの変更ライフサイクルを示すフロー図。提案者が仕様書を作成し、人間レビュアーが意図を確認した後、AIエージェントがコード生成を行う。生成されたコードは品質検証を経てコードレビューに進み、承認後にマージ・デプロイされて本番環境に反映される。各ステップでの検証ポイントと差し戻しループを明示している。

図4:提案から実装までの変更ライフサイクル(OpenSpec準拠)

OpenSpec導入の4段階ロードマップを示す図。フェーズ1(パイロット導入)では小規模チームでの試験的運用と80%以上の満足度達成、フェーズ2(ベストプラクティス確立)ではガイドライン作成と改善提案の実施、フェーズ3(組織全体展開)では95%以上の導入率と30%の業務効率向上、フェーズ4(継続的改善)では90%以上の定着率と改善サイクルの確立を目指す。各フェーズで主要活動と成功指標が明記されている。

図9:OpenSpec導入のロードマップ(4段階フェーズ別展開計画)

脚注

  1. GoogleのMantis脆弱性スキャンのハーネスは、報告されている一例だ。より優れたモデルを使ったことだけでなく、エージェントの仕事を構造化したことで、厳しいセキュリティの現場で誤検知を減らした。https://research.google/blog/mantis-a-novel-approach-to-vulnerability-discovery/ ↩