モノレポはClaude Codeのデフォルト動作と相性が悪い傾向があります。Claude Codeはプロジェクトルートの CLAUDE.md を一度読み込み、どこで作業していても同じコンテキストを持ちます。これはフロントエンド開発者がデータベースマイグレーションのアドバイスを受け、バックエンドサービスがデザイントークンの指示を受ける状況を生みます。コンテキストがノイズだらけになり、トークンバジェットが膨らみ、Claude が関係のない指示に基づいて判断を下し始めます。
このガイドでは、モノレポでClaude Codeを効果的に動かすためのフルセットアップを解説します:ネストされたCLAUDE.mdファイルの構造化、パッケージスコープのサブエージェント構築、トークンバジェット管理、チームへの設定展開。
モノレポが抱える根本的な問題
単一プロジェクトのCLAUDE.mdが機能するのは、コンテキストが一貫しているためです。ファイルの内容は常にすべて関連しています。
モノレポでは、これがすぐに崩れます。典型的な構成を考えてみましょう:
my-monorepo/
packages/
api/ # Node.js + PostgreSQL
web/ # Next.js + Tailwind
mobile/ # React Native + Expo
shared/ # 共有TypeScript型
infra/ # Terraform + AWS
.github/ # CI/CDワークフロー
すべてを1つのルートCLAUDE.mdに入れると、Prismaスキーマ規約、Tailwindユーティリティパターン、Expoビルドの注意点、Terraformステート管理、GitHub Actionsの構文を同時に説明するファイルができあがります。Claudeはどこで作業していても、これをすべてセッション開始時に読み込みます。
結果として、肥大化したコンテキストウィンドウ、混乱した優先順位、間違ったパッケージで間違った規約を適用するClaude になります。コミュニティのある開発者は、CLAUDE.md が 47,000 語(Claudeの推奨上限40,000語)を超えるまで膨らんだ後、応答品質の低下を経験したと報告しています。
解決策は階層的コンテキスト読み込みです——Claude Codeがネイティブにサポートするパターンです。
ネストされたCLAUDE.mdの読み込み動作
Claude Codeは現在の作業ディレクトリからツリーを上方向にたどり、見つかったすべてのCLAUDE.mdを読み込みます。読み込み順:
- グローバル:
~/.claude/CLAUDE.md(マシン上のすべてのプロジェクトに適用) - プロジェクトルート:
./CLAUDE.md - サブディレクトリ: そのディレクトリ内で作業する際に読み込み
ファイルは追加型です——すべてのレベルがマージされ、コンテキストに同時に注入されます。サブディレクトリのファイルはルートファイルを置き換えるのではなく、拡張します。競合する指示がある場合、より深いファイルが優先されます。
packages/api/ 内で作業するClaude が持つコンテキスト:
- グローバル個人設定
- モノレポ全体の規約(ルートCLAUDE.md)
- API固有のルール(
packages/api/CLAUDE.md)
重要なのは、packages/web/CLAUDE.md のコンテキストはそのセッションに持ち込まれないことです。
CLAUDE.md階層の設計
ルートファイル:モノレポ全体のルールのみ
ルートCLAUDE.mdには、リポジトリのすべてのパッケージに適用されるルールのみを入れます。コンパクトに保ちます。200〜300行のルートファイルは健全です。500行を超えたら、そのコンテンツがサブディレクトリに属していないか見直しましょう。
# my-monorepo
## リポジトリ構造
- packages/api — Node.js REST API(PostgreSQL、Prisma)
- packages/web — Next.jsフロントエンド(Tailwind、shadcn/ui)
- packages/mobile — React Nativeアプリ(Expo)
- packages/shared — 共有TypeScript型とユーティリティ
- infra/ — Terraformインフラ(AWS)
## 共通ルール
- TypeScriptを徹底。プレーンJavaScriptファイルなし
- すべてのコミットはConventional Commits形式に従う
- シークレットをコミットしない。すべての認証情報には環境変数を使う
- 新機能にはテスト必須。コミット前に `pnpm test` を実行
## ツール
- パッケージマネージャー: pnpm(ワークスペース)
- ビルド: turbo
- Lint: @my-org/eslint-config を使ったeslint
- フォーマット: prettier(ルートの .prettierrc で設定)
## モノレポコマンド
- `pnpm build` — 全パッケージのビルド
- `pnpm test` — 全テストの実行
- `pnpm lint` — 全パッケージのLint
- `turbo run build --filter=@my-org/api` — 単一パッケージのビルド
## やってはいけないこと
- npmやyarnでパッケージをインストールしない——pnpmを使う
- package.jsonに追加せずにパッケージ間でインポートしない
- shared/ を変更する前にすべての利用側を確認する
パッケージレベルのファイル:ドメイン固有のコンテキスト
各パッケージには、そのコンテキストでのみ意味を持つルールを記載した CLAUDE.md を用意します。
packages/api/CLAUDE.md
# APIパッケージ
## スタック
Node.js 22 + Express 5 + Prisma 6 + PostgreSQL 16
## データベース規約
- すべてのデータベースアクセスはPrismaクライアント経由(生のSQLは使わない)
- マイグレーション: `pnpm prisma migrate dev --name <説明>`
- 既存のマイグレーションファイルは変更しない。新しいものを作成する
- シードデータ: `pnpm prisma db seed`
## ルート規約
- RESTルートは src/routes/ に配置——リソースごとに1ファイル
- ルートハンドラーは薄くする。ビジネスロジックは src/services/ に
- すべてのルートはvalidateRequestミドルウェアでzodバリデーションを使う
- エラーハンドリング: ApiErrorをthrow——エラーミドルウェアがフォーマットを処理
## テスト
- フレームワーク: Vitest
- 統合テストはテストデータベースを使用(TEST_DATABASE_URL)
- 実行: `pnpm test` または `pnpm test:watch`
- テストデータのファクトリ関数は tests/factories/ に
packages/web/CLAUDE.md
# Webパッケージ
## スタック
Next.js 15(App Router)+ Tailwind CSS 4 + shadcn/ui + React Query
## コンポーネントルール
- デフォルトはServer Components。"use client" は必要な場合のみ(インタラクティビティ、フック)
- UIプリミティブにはshadcn/uiを使う。shadcnがカバーするものをゼロから作らない
- Tailwindユーティリティクラスのみ——本当に必要な場合を除きカスタムCSSファイルなし
- テストはコンポーネントと同じ場所に配置: Button.tsx → Button.test.tsx
## ディレクトリ構造
- app/ — Next.js App Routerのページとレイアウト
- components/ui/ — shadcn/uiコンポーネント(編集しない)
- components/ — カスタムコンポーネント
- lib/ — ユーティリティ、フック、APIクライアント
- types/ — TypeScript型(非共有)
infra/CLAUDE.md
# インフラ
## スタック
Terraform 1.9 + AWS + Terragrunt
## ルール
- terraform apply を直接実行しない。CIパイプラインを使う
- ステートはS3に存在する(backend.tf を参照)。ステートを手動で変更しない
- すべての変更はapply前にプランレビューが必要
- すべてのリソースにタグを付ける: Environment、Team、CostCenter(locals.tf 参照)
## センシティブな値
- シークレットはAWS Secrets Managerに入れる。Terraformのステートには入れない
パッケージスコープのサブエージェント
サブエージェントはネストされたコンテキストパターンをさらに一歩進めます。パッケージに適切な指示を与えるだけでなく、そのパッケージのドメインの専門家であり、タスクに適切なツール制限を持つエージェントを作成できます。
プロジェクトのサブエージェントは .claude/agents/ に保存し、バージョン管理にコミットします。これによりチームの全員が同じエージェントを使えます。
DBマイグレーションエージェント
.claude/agents/db-migrator.md
---
name: db-migrator
description: Prismaデータベースマイグレーションの作成・レビュー・適用に使う。スキーマ変更、マイグレーションファイル、データベースシーディングを処理する。
tools: Read, Write, Edit, Bash, Glob
model: sonnet
color: blue
---
このモノレポのデータベースマイグレーション専門家です。
担当範囲: packages/api/prisma/
マイグレーション作成時:
1. 現在の状態を理解するためにschema.prismaを読む
2. 要求された変更を理解する
3. マイグレーションを生成: pnpm --filter @my-org/api prisma migrate dev --name <説明>
4. 生成されたマイグレーションファイルの正確性を確認
5. prisma/seed.tsの更新が必要かチェック
安全ルール:
- 既存のマイグレーションファイルを変更しない
- データ損失リスク(列/テーブルの削除)を常にチェックする
- 破壊的変更の場合、リスクを説明してより安全なマルチステップアプローチを提案する
- prisma migrate deploy を実行しない(CIのみで使用)
フロントエンド監査エージェント
読み取り専用のエージェントで、Webパッケージのアクセシビリティ、パフォーマンス、一貫性の問題を検出します。
.claude/agents/web-auditor.md
---
name: web-auditor
description: アクセシビリティ・パフォーマンス・Tailwind/shadcn一貫性の問題についてReactコンポーネントとNext.jsページをレビューする場合に使う。
tools: Read, Glob, Grep
model: haiku
color: green
---
packages/webディレクトリのフロントエンドコード品質監査者です。
読み取り専用です。編集は提案せず、所見を報告します。
チェック項目:
**アクセシビリティ**
- 可視テキストのないインタラクティブ要素にaria-labelがない
- altがない画像
- ラベルが関連付けられていないフォーム入力
**パフォーマンス**
- "use client" が不要なコンポーネントに付いている
- Server/Clientの境界に分割できる大きなコンポーネント
- next/imageを使っていない画像
**一貫性**
- Tailwindユーティリティで対応できる場所のカスタムCSS
- lib/api-client.ts外での直接fetch()呼び出し
- shadcnコンポーネントの再実装
インフラプランナーエージェント
Terraform作業向けのplan専用エージェントです。誤った apply を防ぎます。
.claude/agents/infra-planner.md
---
name: infra-planner
description: Terraform変更のレビュー、インフラ状態の理解、インフラ変更の計画に使う。変更は適用しない。
tools: Read, Glob, Grep, Bash
model: sonnet
permissionMode: plan
color: orange
---
インフラ計画の専門家です。Terraform設定を分析し、変更点・リスク・依存関係を説明します。
planモードで動作します。Terraform変更を適用しません。
インフラ変更のレビュー時:
1. 関連する.tfファイルを読む
2. リソースの依存関係を確認する
3. 潜在的なリスクを特定する(ダウンタイム、データ損失、コストへの影響)
4. マルチステップ変更の最も安全な実行順序を提案する
常にこれで終わらせてください:「この変更を適用するには、ローカルではなくCIパイプラインを実行してください。」
トークンバジェット管理
トークンコストはモノレポのサイズに比例して増加します。使用量を管理するためのパターンを紹介します。
大きなパッケージファイルの分割
単一パッケージの CLAUDE.md が200〜300行を超えた場合、@ 参照を使って別ドキュメントファイルに分割します:
# APIパッケージ
## クイックリファレンス
- スタック: Node.js 22 + Express 5 + Prisma 6
- テストコマンド: pnpm test
- Lintコマンド: pnpm lint
## 詳細ガイド
@docs/database-conventions.md
@docs/error-handling.md
@docs/testing-guide.md
重要な区別:CLAUDE.md内の @ 参照は条件付き読み込みです。セッション開始時にすべてのコンテンツを読み込むのではなく、Claude が必要な時に取得します。これによりセッション開始時のコンテキストが大幅に削減されます。
探索サブエージェントにHaikuを使う
読み取り専用でコードベースを探索するカスタムサブエージェント(上記の web-auditor など)には、model: haiku を明示的に設定します。深い推論を必要としないタスクでは、Opusより25倍安価です。
フォーカスされたサブエージェントにmaxTurnsを設定する
スコープが狭いサブエージェントには、暴走するセッションを防ぐためにターン数を制限します:
---
name: pr-description-writer
description: 現在のgit diffに基づいてプルリクエストの説明を書く必要がある場合に使う。
tools: Bash, Read
model: sonnet
maxTurns: 5
---
git diffに基づいて明確で簡潔なプルリクエストの説明を書いてください。
`git diff main...HEAD` で変更を取得し、以下を作成してください:
1. Conventional Commitsに従う1行タイトル
2. 主要な変更のビュレット一覧
3. テスト手順(手動で確認すべきこと)
チームへの展開
バージョン管理に含めるもの
チーム全体で一貫性を保つべきすべてのもの:
.claude/
agents/ # プロジェクトサブエージェント——コミットする
db-migrator.md
web-auditor.md
infra-planner.md
settings.json # プロジェクト全体のClaude設定——コミットする
settings.local.json # 個人設定——.gitignoreに追加
CLAUDE.md # ルート——コミット
packages/api/CLAUDE.md # パッケージ——コミット
packages/web/CLAUDE.md # パッケージ——コミット
packages/mobile/CLAUDE.md # パッケージ——コミット
infra/CLAUDE.md # パッケージ——コミット
.claude/settings.local.json を .gitignore に追加します。これはAPIキーの上書き、個人のMCPサーバー、共有すべきでない個人設定のためのファイルです。
チーム一貫性のためのsettings.json
.claude/settings.json ファイルは共有のデフォルトを強制します。モノレポで使える設定例:
{
"model": "sonnet",
"permissions": {
"deny": [
"Bash(npm install:*)",
"Bash(yarn:*)",
"Bash(git push --force:*)",
"Bash(terraform apply:*)"
]
},
"env": {
"CLAUDE_CODE_MAX_OUTPUT_TOKENS": "8000"
}
}
これにより npm install(pnpmを強制)、yarn(同様)、force push、直接的な terraform apply がブロックされます——チームメンバーの個人設定に関わらず。
新しいチームメンバーのオンボーディング
ルートCLAUDE.mdにClaude自身向けのセットアップ説明セクションを追加します:
## 新しいチームメンバーへ
これはTurborepoを使用するpnpmモノレポです。開始するには:
1. `pnpm install` — 全依存関係をインストール
2. `pnpm dev` — 全パッケージを開発モードで起動
3. `cp .env.example .env.local` — 環境変数をセットアップ
各パッケージには固有のCLAUDE.mdがあります。
packages/api で作業する場合は packages/api/CLAUDE.md でDB・API規約を確認してください。
packages/web で作業する場合は packages/web/CLAUDE.md でフロントエンド規約を確認してください。
よくあるミス
すべてをルートCLAUDE.mdに入れてしまう。ルートファイルには横断的な関心事のみを含めます。1つのパッケージにのみ適用されるルールは、そのパッケージのCLAUDE.mdに属します。
パッケージファイル間で規約を重複させる。同じTypeScriptルールを3つのパッケージのCLAUDE.mdに書いているなら、それはルートに属します。
サブエージェントに明確な委任シグナルを設けない。Claudeはどのサブエージェントを使うかを description フィールドに基づいて選択します。曖昧な説明は、間違ったエージェントが選ばれたり、エージェントが選ばれなかったりする原因になります。説明は「これは何か」ではなく「いつこれを使うか」という形式で書いてください。
リスクのあるサブエージェントで isolation フラグを無視する。ファイルを変更するサブエージェントに対しては isolation: worktree を設定します。これにより、変更が問題であれば、ワーキングツリーに影響を与えることなくワークツリーを破棄できます。
サブエージェントファイルをコミットしない。.claude/agents/ ディレクトリがバージョン管理に含まれていなければ、チームの開発者全員が同じエージェントを個別に再作成しなければならなくなります。
完全なリポジトリ構造の参照
Claude Codeが完全に設定されたTypeScriptモノレポの参照構造:
my-monorepo/
├── CLAUDE.md # モノレポ全体のルール
├── .claude/
│ ├── agents/
│ │ ├── db-migrator.md # Prismaマイグレーション専門家
│ │ ├── web-auditor.md # フロントエンドコード品質(Haiku)
│ │ ├── infra-planner.md # Terraformプランニング(planモード)
│ │ └── pr-description-writer.md # PR説明生成
│ ├── settings.json # チーム設定(コミット済み)
│ └── settings.local.json # 個人設定(gitignored)
├── packages/
│ ├── api/
│ │ ├── CLAUDE.md # API固有のルール
│ │ └── docs/ # CLAUDE.mdから参照
│ │ ├── database-conventions.md
│ │ └── testing-guide.md
│ ├── web/
│ │ └── CLAUDE.md # Web固有のルール
│ ├── mobile/
│ │ └── CLAUDE.md # Mobile固有のルール
│ └── shared/
│ └── CLAUDE.md # 共有パッケージのルール
└── infra/
└── CLAUDE.md # インフラのルール
よくある質問
Claude Codeはモノレポでネストされた CLAUDE.md ファイルを自動的に読み込みますか?
はい。Claude Codeがサブディレクトリのファイルを読み書きする際、そのファイルの場所からツリーを上方向にたどり、見つかったすべての CLAUDE.md を読み込みます。競合するルールについては、最も近い CLAUDE.md が優先されます。
CLAUDE.mdの階層はどこまで深くすべきですか?
ほとんどのモノレポはルート、パッケージレベル、場合によってはフィーチャー/モジュールレベルの2〜3階層で上手く機能します。4階層を超えると、ルールが細かすぎてインラインコメントやAGENTS.mdのサブエージェント定義として表現する方が良いことが多いです。
ルートCLAUDE.mdとpackages/*/CLAUDE.mdの違いは?
ルートは普遍的なルール(ツール、コミット規約、セキュリティポリシー、ワークスペーストポロジー)を保持します。パッケージレベルはスタック固有のルール(フレームワークバージョン、ORM規約、テストアプローチ)を保持します。ルートをコンパクトで安定した状態に保ち、パッケージが独自の規約を発展させていきましょう。
異なるパッケージで完全に異なる規約を使えますか?
はい。モノレポは TypeScript React フロントエンドと Python ML サービスを、それぞれ独自のスタイルガイド・テストアプローチ・依存関係ポリシーで持つことができます。
複数のパッケージCLAUDE.mdファイル間でルールの重複を避けるには?
共通のルールをルートに移動します。3つのパッケージがすべて「pnpmを使い、npmを使わない」というルールを必要としているなら、それはルートCLAUDE.mdに属します。
CLAUDE.mdの継承はTurborepo / Nx / pnpmワークスペースでも機能しますか?
すべてのモノレポツールで同じように機能します。CLAUDE.mdの読み込みはワークスペース設定ではなくファイルシステム階層に基づいています。