1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

エージェントに「仕様」を渡す — 受託案件をタスクに割るまで

1
Posted at

「これぐらい分かってくれるだろう」で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 エージェントを使った受託開発の実装と運用を担当している。この記事は、社内で書き溜めていた失敗ノートの一本目を、公開できる形に整えたものだ。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?