ルートに1つだけAGENTS.mdを置いたモノレポは、法務チームにも倉庫スタッフにも同じ社員ハンドブックを渡している会社のようなものだ。ないよりはましだが、ほとんどの場面でほとんどの人にとって間違っている。
「パッケージごとに1つ」という解決策は一見明快に見える——が、気づくと12ファイルを管理していて、その80%が同じ内容であり、テストランナーのコマンドを変更するたびに全ファイルを触る羽目になる。
このガイドでは実際に機能するパターンを解説する:継承に近い挙動を持つ階層的AGENTS.mdファイル、ワークスペース対応のツール設定、そして適切なコンテキストをAIエージェントに渡しながら重複によるメンテナンスコストを抑える構造の作り方。
階層的AGENTS.md解決の仕組み
Claude CodeとOpenAI Codexはどちらも、複数レベルのAGENTS.mdを読む。エージェントがpackages/api/src/routes/内のファイルを操作する場合、解決順序は以下の通り:
packages/api/AGENTS.md(最も具体的)packages/AGENTS.md(存在する場合)- リポジトリルートの
AGENTS.md(フォールバック)
一致するファイルはすべてロードされ、マージされる——最も具体的なものだけではない。ここが重要なポイントだ:ルートAGENTS.mdで共有ポリシーを定義し、パッケージファイルでローカルのオーバーライドを書けば、エージェントは両方を参照できる。
Claude Codeは作業ディレクトリから上方向にたどり、見つかったすべてのAGENTS.mdを収集し、ルートから末端の順に連結する。つまり、ルートのルールは常に適用され、パッケージのルールはそれを拡張する。
ルートAGENTS.md:ここに書くべきもの
ルートAGENTS.mdに入れるのは、リポジトリ内のすべてのパッケージに本当に共通する事項だけにすること:
# AGENTS.md
## リポジトリ概要
pnpmワークスペースのモノレポ。パッケージは`packages/`、アプリは`apps/`に置く。
ルートビルド: `pnpm turbo build`
ルートテスト: `pnpm turbo test`
ルートリント: `pnpm turbo lint`
## ワークスペースルール
- `npm install`や`yarn install`は使わない——必ず`pnpm install`を使う
- `packages/shared-types`への変更後は`pnpm turbo build --filter=shared-types`を実行しないと
他パッケージのTypeScriptが正しく解決されない場合がある
- ロックファイルは`pnpm-lock.yaml`——`pnpm install`を実行せずにコミットしない
## クロスパッケージ規則
- 内部パッケージは`@company/package-name`として参照する
- `../../packages/...`のような相対パスでパッケージ境界をまたいでインポートしない
- 共有ユーティリティは`packages/utils`にある——新たに実装する前に必ず確認する
## CI
- CIはNode 20 LTSでテストを実行する
- CI環境変数は`.env.ci`(コミット済み)にある——ローカルの上書きは`.env.local`(gitignore済み)
- シークレットをハードコードしない。`process.env.VAR_NAME`を使う
## ここに書かないもの
パッケージ固有のビルドコマンド、テストパターン、フレームワーク規則、
ファイル構造ルールは各パッケージのAGENTS.mdを参照。
何が書かれていないかに注目:フレームワーク固有のルール、パッケージレベルのコマンド、API規則。それらは階層の下位に属する。
パッケージレベルAGENTS.mdのパターン
フロントエンドアプリ(Next.js)
# AGENTS.md — apps/web
## パッケージコマンド
- Dev: `pnpm dev`(ポート3000)
- Build: `pnpm build`
- Test: `pnpm test`(Vitest)
- Lint: `pnpm lint`(ESLint + Prettier)
- 型チェック: `pnpm type-check`
## スタック
- Next.js 14 App Router(Pages Routerは使わない)
- Tailwind CSS——CSSモジュール不使用
- shadcn/uiコンポーネントは`src/components/ui/`にある——そこからインポートし、再実装しない
- React Server Componentsがデフォルト。必要な場合のみ`'use client'`を追加
## ファイル規則
- ページ: `app/(routes)/[route]/page.tsx`
- レイアウト: `app/(routes)/[route]/layout.tsx`
- サーバーアクション: `app/(routes)/[route]/actions.ts`
- コンポーネント: `src/components/[ComponentName]/index.tsx`
- コンポーネントにdefault exportを使わない——常にnamed export
## APIレイヤー
- すべてのAPI呼び出しは`src/lib/api/`を経由する——コンポーネントから直接fetchしない
- ミューテーションはサーバーアクション。GETデータ取得はReact Server Componentsで行う
## テスト
- ユニットテスト: ファイルと同じ場所に`.test.ts`
- 統合テスト: `src/__tests__/`
- 実装の詳細をテストしない——動作をテストする
バックエンドAPI(Node.js / Fastify)
# AGENTS.md — packages/api
## パッケージコマンド
- Dev: `pnpm dev`(ポート8080、tsx watchでホットリロード)
- Build: `pnpm build`(dist/に出力)
- Test: `pnpm test`(Vitest)
- 特定ファイルのテスト: `pnpm test src/routes/users.test.ts`
- DBマイグレーション: `pnpm migrate:up` / `pnpm migrate:down`
## アーキテクチャ
- FastifyベースのHTTP API
- ルートは`src/routes/`に定義——リソースごとに1ファイル
- ビジネスロジックは`src/services/`——ルートに書かない
- DBアクセスは`src/repositories/`——サービスがリポジトリを呼ぶ(逆は禁止)
## データベース
- `@company/db`経由のPostgreSQL(Drizzle ORMのラッパー)
- スキーマは`packages/db/schema/`
- マイグレーション実行にはローカルDBが必要——ルートの`docker-compose.yml`を参照
## 認証
- JWTは`src/middleware/auth.ts`経由——保護対象ルートすべてに適用する
- ミドルウェア実行後、`req.user`は`AuthUser`型になる
- ルートハンドラーに認証ロジックをインライン化しない
## エラーハンドリング
- すべてのエラーレスポンスは`src/lib/errors.ts`の`createError()`を使う
- RFC 7807形式で返す: `{ type, title, status, detail }`
共有パッケージ(型 / ユーティリティ)
# AGENTS.md — packages/shared-types
## パッケージコマンド
- Build: `pnpm build`(他パッケージがインポートする前に実行が必要)
- 型チェック: `pnpm type-check`
- テストランナーなし——型はtscで検証される
## ルール
- このパッケージはTypeScript型のみをエクスポートする——ランタイムコードなし
- すべての型は`src/index.ts`からエクスポートする
- サードパーティ依存なし——このパッケージはゼロ依存を維持する
- 破壊的変更はメジャーバージョンアップと全消費者の更新が必要
## ここに型を追加するタイミング
- 2つ以上のパッケージで共有する型はここに置く
- 1パッケージのみで使う型はそのパッケージに置く
- すでにここにある型を複製しない
TurborepoとNx:タスク固有のコンテキスト
Turborepoでうまく機能するパターンの一つが、タスク固有のコンテキストを各パッケージのdocs/agent-context/ディレクトリに保存し、AGENTS.mdから参照する方法だ:
# AGENTS.md — packages/api
## コマンド
- Test: `pnpm test`
- テストパターンと注意点は`docs/agent-context/testing.md`を参照
- DBマイグレーションワークフローは`docs/agent-context/db.md`を参照
AGENTS.md自体を短くスキャンしやすい状態に保ちながら、詳細なドキュメントをオンデマンドで利用可能にできる。Claude Codeは@docs/agent-context/testing.mdというインポート構文に対応しているため、エージェントが参照先を推測する必要がない。
Nxワークスペースではプロジェクトごとのコンフィグはproject.jsonに既にあり、AGENTS.mdファイルはその上に自然に重なる:
# AGENTS.md — apps/dashboard
## Nxコマンド
- Build: `nx build dashboard`
- Test: `nx test dashboard`
- 影響を受けるテスト(CIから): `nx affected --target=test --base=main`
## Nx固有の動作
- Nxはビルド出力をキャッシュする——変更が反映されない場合は`nx reset`を実行する
- ライブラリの境界はESLintの`@nx/enforce-module-boundaries`で強制される
- クロスパッケージ変更前に`nx graph`で依存関係チェーンを確認する
重複問題の対策
典型的な失敗パターン:ルートAGENTS.mdに「テストはVitestを使う」と書いてあり、各パッケージのAGENTS.mdにも同じことが書いてある。テストランナーを移行するとき9ファイルを更新して3ファイルを見落とす。
解決策は、技術的な制約ではなくチームのルールとして関心の分離を厳格に適用することだ:
| ルートAGENTS.md | パッケージAGENTS.md |
|---|---|
| ワークスペースマネージャー(pnpm) | フレームワーク(Next.js、Fastify) |
| ルートレベルスクリプト | パッケージレベルスクリプト |
| クロスパッケージ規則 | 内部ファイル構造 |
| CI環境の情報 | パッケージ固有の環境変数 |
| 共有ツールのバージョン | ローカル開発セットアップ |
ルートとパッケージの両方に同じ内容が現れる場合、それはコピーペーストではなく、パッケージがルートポリシーをオーバーライドまたは拡張しているからであるべきだ。
エージェントが実際に参照するコンテキストを計測する
AGENTS.md階層を確定する前に、連結結果を印刷してエージェントが受け取るトークンコンテキストを確認しておく価値がある:
# packages/api/src/内で作業する場合にエージェントが参照するものをシミュレート
find . -name "AGENTS.md" -path "*/packages/api/*" -o -name "AGENTS.md" -maxdepth 1 | \
sort | xargs cat | wc -w
実際のプロジェクトでは、ルートとパッケージのAGENTS.mdを連結すると通常600〜1200ワードになる。2000ワードを超えると、自分のコードとコンテキストを競い合うことになる。その上限に近づいてきたら、まず例示を削り(ルールは残してイラストを削除)、次に参照ドキュメントを上記のdocs/agent-context/パターンに移動する。
Claude Codeのコンテキストウィンドウは十分に大きいためこれがハードリミットになることは稀だが、命令の優先度には影響する——連結ファイルの末尾付近のコンテンツは重みが低くなる傾向がある。
テンプレートからAGENTS.mdを生成する場合のパターン
大規模な組織でAGENTS.mdをテンプレートから生成している場合、ソースを示すコメントを追加しておくと良い:
# AGENTS.md — packages/api
# 生成元: scripts/templates/api-package-agents.md
# 最終更新: 2026-04-01 by @yourusername
# この行以下の手動追記は再生成時に保持される
これはエージェント(と人間)に対して、基本コンテンツは正規版であり、その下の内容は意図的なローカルカスタマイズであることを示す。