「これぐらい分かってくれるだろう」で1500行のdiffが返ってきた
先日、ある受託案件で「認証まわりを Cognito から自前実装に置き換えたい」と依頼された。仕様書はA4で12枚あった。読んで、要点を Claude Code に渡し、実装を任せた。翌朝、1500行超の diff が上がっていた。手元で動かすと、既存のセッション管理が半分書き換わっていて、SDK 呼び出しの層まで削り直されていた。動くには動く。しかし本番マージは無理だ。
正直に言うと、これはエージェントの暴走ではなく、筆者の失敗である。仕様書は「人間の設計者が読み進めながら判断する」前提で書かれていて、判断の余地を、エージェントはそのまま実装の自由度と読んだ。「認証まわり」というスコープが渡されれば、隣接するファイルまで整理しに行くのは、それはそれで自然な挙動だったのだ。

人間向け仕様と、エージェント向け仕様は別物である
この1年、Claude Code で受託案件を回してきて分かったのは、人間向けの仕様書はそのままではエージェントに渡せない、という単純な事実だった。書式が悪いのではない。前提が違う。
人間の開発者は仕様を読みながら「これはたぶん既存の UserService を使うんだろう」「ここは触らない方が安全そうだ」と、書かれていない判断を無意識に補う。エージェントはこの補完をしない、というより、補完のバリエーションが多すぎて安定しない。同じプロンプトで走らせても、日によって触るファイル数が変わる。
だから設計方針として、エージェントに渡す情報を「変わらないもの」と「その案件でだけ有効なもの」に分けた。
変わらないもの — リポジトリ側に置く恒久コンテキスト
プロジェクトのルートに置く CLAUDE.md は、案件のたびに書き直さない情報の置き場だ。書くべきものは3つに絞っている。
# このリポジトリで守るルール
ディレクトリの意図
src/domain/ ドメインロジック。外部依存を持ち込まない
src/infra/ DB・外部APIへの薄い層。ここ以外で SDK を呼ばない
src/app/ UI とルーティング。ここに業務ロジックを置かない
触ってはいけない
migrations/ 配下の既存ファイル(番号付き SQL)は編集しない。追記のみ
src/domain/legacy/ 以下は今回のスコープ外
package.json の dependencies に新規パッケージを追加しない(相談)
実行コマンド
test: pnpm test --run
lint: pnpm lint
build: pnpm build
ここに書くのは「今日の案件」の話ではなく、来年もこのリポジトリで有効な決定だけである。20行を超えたら、たぶん案件用コンテキストが混ざっている。切り出す。
案件ごとに書く、使い捨てコンテキスト
案件用の指示は、リポジトリには残さない。.claude/tasks/ のような一時ディレクトリを掘り、案件が終わったら消す。使い捨てだから、書き心地は雑でよい。
# 認証置き換え(案件-A / 2026-08)
背景
既存: AWS Cognito でセッション発行
今回: 自前の JWT 発行に置き換え(Cognito は残す。他社サービスがまだ参照している)
触ってよいファイル
src/infra/auth/ ここが今回の主戦場
src/domain/user/ User 型に issued_by フィールドを追加
触ってはいけないファイル
src/infra/cognito/ そのまま残す(他社が使用中)
src/app/** UI の変更は今回スコープ外
判断が必要になったとき
やらずに止めて、選択肢を提示する。実装で進めない。
最後の一行が肝で、「判断で止めて聞く」を明示しておくと、エージェントが勝手に決めて隣接ファイルを触る事故が減る。厳密にはゼロにはならない。減る、という体感である。
タスクを「調べる・作る・確かめる」に還元する
仕様を分けたあと、次にやったのはタスクの粒度をそろえることだった。案件全体を1個のプロンプトで渡すと、前述のように暴走する。かといって、細かく分けすぎるとオーケストレーションのコストが人間側に返ってくる。
いくつか試して、3種類に還元できると気づいた。
調べる: 既存コードのどこに何があるかを列挙する。変更はしない。出力はメモ
作る: 事前に固定した入出力の範囲でファイルを変更する。触ってよいファイルを列挙して渡す
確かめる: テストを走らせ、失敗したら差分を要約する。修正は次のタスクに回す
この分類のありがたいところは、それぞれ違うエージェントに渡せる点だ。「調べる」は読むだけだからサブエージェントに投げてメイン文脈を汚さない。「作る」はメインが受ける。「確かめる」もサブに任せる。この分担設計は次回で扱う。
受け入れ条件を実装より先に書く
もう一つ、地味だが効いたのが、受け入れ条件を実装前に書き切っておくことだった。書式は決めていない。テストの assert が立てば十分だし、立たなければ「筆者が目視で確認する項目」として箇条書きにする。
## 受け入れ条件(このタスクが「終わった」判定)
pnpm test --run auth が緑
既存の /api/auth/login エンドポイントが JWT を返す(Cognito トークンではない)
src/infra/cognito/ のファイル数が変わっていない(git diff --stat で確認)
dependencies に新規追加がない(package.json の変更が0行)
この4項目のうち、1と2はエージェントが自分で確認できる。3と4は「触ってはいけない」の裏返しで、生成後の差分に対して機械的に判定できる。ここまで書いておくと、Claude Code は実装の途中で「この項目に反しそうなので止まる」と言ってくることが増えた。
SDD(Spec-Driven Development)界隈でも、AI エージェントに渡す acceptance criteria は機械検証可能に、というのが2026年の合意事項になりつつある。筆者の実感でも、テスト可能な条件を「作る」より先に書くだけで、生成物のレビュー時間が体感で半分になる。ここで30分ハマる価値はある。
プロンプトの最終形
ここまでの断片をつなぐと、案件開始時に Claude Code に渡す情報はこの3層構造になる。
[常時読まれる / 案件が変わっても不変]
CLAUDE.md
ディレクトリの意図
触ってはいけないもの
実行コマンド
[このセッションで渡す / 案件固有]
.claude/tasks/2026-08-案件-A/spec.md
背景(2〜3行)
触ってよいファイル(明示)
触ってはいけないファイル(明示)
受け入れ条件(4〜6項目、機械検証可能に)
判断が必要なときは止めて聞く
[このタスクで渡す / 最も揮発性が高い]
"上記の spec.md に従い、まず調べるだけ実行。ファイルは変更しない。
変更が必要な箇所を列挙してレビューさせて。"
この3層に分けたことで、以前は1つのプロンプトに詰め込んで祈っていた情報が、それぞれの寿命に合わせて置き場を持つようになった。祈らなくていい設計、というのが個人的にはいちばんの効用だと思っている。
まとめと、次回
受託案件でエージェントに仕様を渡す、というのは、実は仕様を分割して置き場を決める作業だった。恒久と使い捨てを分け、タスクを「調べる・作る・確かめる」の3種に還元し、受け入れ条件を実装前に書く。これだけで、1500行の diff が返ってくる事故は少なくとも筆者の手元では止まった。
次回は、この分けたタスクを複数エージェントで並列に走らせたときに起きる衝突と、git worktree を使った作業分離について書く予定である。同じリポジトリで2つのエージェントが同時に触ると、片方が移動したファイルをもう片方が編集し始める、という別種の事故が始まる。そこの対処である。
筆者は 5years+ で AI エージェントを使った受託開発の実装と運用を担当している。この記事は、社内で書き溜めていた失敗ノートの一本目を、公開できる形に整えたものだ。