Claude Codeモノレポ設計 — CLAUDE.md階層とパッケージ単位の権限スコープ
モノレポでのClaude Code運用は、CLAUDE.md階層・claudeMdExcludes・権限のパッケージスコープ・追加ディレクトリの組み合わせで決まります。設定の使い分けを実践シナリオで解説します。
Claude Codeをモノレポで運用する際に組み合わせる設定は、次の4つです。
- CLAUDE.mdの階層配置
claudeMdExcludesによるスコープ限定- パッケージ単位の権限(allow/deny)
additionalDirectoriesや--add-dirによるアクセス拡張
どれか1つを選ぶのではなく、4種類を独立したレイヤーとして積み上げる設計です。パッケージ構成に合わせて必要な分だけ重ねます。本稿では、これらの設定をpackages/{api,web,shared}という3パッケージ構成のモノレポを例に、どの順で・何のために使うかという実践シナリオに沿って扱います。
なお、ここで扱う「モノレポ」は単一リポジトリをパッケージマネージャ(npm/pnpm workspaceやTurborepo)で管理する構成を指します。独立したGitリポジトリをシンボリックリンクで束ねる運用パターンは対象外です。同じ設定の積み重ねは、複数パッケージを持たない大規模な単一ツリーのコードベースにもそのまま当てはまります。Claude Code自体のインストールや基本機能はClaude Code完全ガイドで扱っており、本稿はモノレポ特有の設定に絞って掘り下げます。
Claude CodeはモノレポのCLAUDE.mdをどう読み込むか
Claude Codeは起動時に、作業ディレクトリから上位へたどりながら各階層のCLAUDE.mdとCLAUDE.local.mdを探索し、見つかったファイルをすべて連結してコンテキストに載せます。上書きではなく連結なので、ファイルシステムのルートに近い内容から先に並び、起動したディレクトリに近い指示ほど後ろに置かれます。後から読まれる指示のほうが直近の文脈として効きやすい、という順序です。
サブディレクトリのCLAUDE.mdは起動時には読み込まれません。Claudeがそのサブディレクトリ配下のファイルを実際に読んだタイミングで、遅延的に取り込まれます。この2つの挙動を組み合わせると、モノレポでの起動場所ごとの見え方が決まります。
| 起動場所 | 起動時に読み込むCLAUDE.md | ファイルアクセス範囲 |
|---|---|---|
| リポジトリルート | 起動時に読み込むCLAUDE.mdルートのCLAUDE.mdのみ(サブディレクトリのものはClaudeがそこを読んだ時点でオンデマンド) | ファイルアクセス範囲リポジトリ全体 |
パッケージのサブディレクトリ(例: packages/api) | 起動時に読み込むCLAUDE.mdそのディレクトリと全ての祖先ディレクトリ | ファイルアクセス範囲明示的に許可を広げるまでそのサブツリーのみ |
CLAUDE.mdの分量にも目安があります。1ファイルあたり200行未満が目安です。長いファイルはコンテキストを消費するだけでなく、指示への追従度も下げます。対策になるのがパス限定ルール(path-scoped rules)で、ファイルパターンを絞って特定の指示だけを効かせられます。なお@importによるファイル分割は整理には効きますが、起動時に読み込まれる点は変わらないためコンテキスト消費そのものは減りません。ルートCLAUDE.mdを薄く保ち、パッケージ固有の指示は各パッケージ配下のファイルに分散させる設計が、この目安と整合します。
CLAUDE.mdには4つの配置スコープ(managed policy / user / project / local)があり、自動メモリとも関係します。この仕組み全体の解説はClaude Code memoryの三層構造に譲ります。本稿はモノレポという複数パッケージ構成に焦点を絞ります。
実際にどのCLAUDE.mdが読み込まれているかは、セッション中に/contextを実行し「Memory files」の欄で確認できます。
パッケージ単位でCLAUDE.mdを配置し、claudeMdExcludesで他チームの指示を止める
3パッケージ構成のモノレポでは、ルート直下に全体方針を書いたCLAUDE.mdを1つ置きます。packages/api・packages/web・packages/sharedそれぞれには、そのパッケージ固有の規約を書いたCLAUDE.mdを配置します。これが基本形です。ルートから起動すると、作業中に触れたパッケージのCLAUDE.mdが次々とコンテキストに追加されます。
ここで問題になるのが、自分のチームが担当していないパッケージのCLAUDE.mdまで拾ってしまうケースです。claudeMdExcludesは、こうした無関係なファイルを明示的に除外する設定です。
自分だけの除外にしたいなら、この設定は.claude/settings.local.jsonに置きます。
{
"claudeMdExcludes": ["**/packages/web/**"]
}パターンは絶対パスに対してglob構文でマッチします。相対パス感覚で書くと拾えません。**/から書き始めないと、ツリーのどこにもマッチしないためです。ルートのCLAUDE.mdを残しつつパッケージ単位でだけ除外したい場合は**/packages/*/CLAUDE.mdを使います。特定パッケージ配下をまるごと除外するなら、**/packages/legacy-*/**のような指定も使えます。
配列は設定レイヤー間でマージされます。ただしmanaged policyのCLAUDE.mdだけは除外の対象になりません。複数のプロジェクトで同じルールを共有したい場合は、.claude/rules/配下にシンボリックリンクを張れば、共通ルールをリポジトリ横断で使い回せます。
.claude/rules/はpathsのfrontmatterでファイルパターンを限定できるため、「このルールはpackages/api配下のTypeScriptファイルにだけ効かせる」といった細かい絞り込みも可能です。設定ファイルの構文やフィールドはClaude Code設定ガイドで扱っています。
起動場所がファイルアクセスと設定範囲を同時に決める
Anthropicの公式ブログは、モノレポでもリポジトリルートではなくパッケージのサブディレクトリから始めることを勧めています。公式ドキュメントの表は用途で使い分ける形で、タスクが複数パッケージにまたがる場合はルート起動を挙げています。多くのツールはルートアクセスを前提にするため直感に反しますが、Claude Codeは起動ディレクトリから上位へ辿ってCLAUDE.mdをすべて連結するため、サブディレクトリから起動してもルートの文脈は失われません。失われるのは、次に説明する.claude/settings.jsonなどプロジェクト設定(project settings)の適用範囲だけです。
プロジェクト設定は起動したディレクトリからしかロードされません。CLAUDE.mdのように親ディレクトリから継承されることはなく、リポジトリルートの.claude/settings.jsonは、ルートから起動したときにだけ適用されます。
つまり、packages/apiから起動すると、packages/api/.claude/settings.jsonは読み込まれますが、リポジトリルートの.claude/settings.jsonは無視されます。ルートの権限ルールをパッケージ起動でも効かせたい場合、選択肢は3つあります。
- パッケージ側の設定ファイルにも同じルールを書く
- リポジトリルートの
.claude/settings.local.jsonに書く(v2.1.211以降は起動場所によらずリポジトリ内のどのセッションでも読み込まれます) - 管理設定(managed settings)に書く
この起動場所依存は.claude/settings.jsonとフックに固有の挙動で、Claude Codeの設定モデル全体を貫く原則ではありません。コマンドと出力スタイル(output style)は起動ディレクトリの親をたどって探索されますし、.claude/settings.local.jsonもv2.1.211以降はリポジトリルートから読み込まれます。
パッケージごとに権限を分ける — allow/denyとディレクトリスコープの掛け合わせ
モノレポの各パッケージに異なる権限(このパッケージは自由に編集してよい、あのパッケージは読み取り専用にする)を与えたい場合、パスパターンは4種類に分かれます。
| パターン | 意味 |
|---|---|
//path | 意味絶対パス |
~/path | 意味ホームディレクトリ相対 |
/path | 意味設定ソース相対(プロジェクト設定なら<プロジェクトルート>/path) |
path または ./path | 意味カレントディレクトリ相対 |
見落としやすいのが、同じパターンでもallowルールとdeny/askルールでディレクトリ名のマッチ深度が異なる点です。Edit(src/**)は、allowルールとしては起動ディレクトリ直下のsrcにしかマッチしませんが、deny/askルールとしては任意の深さのsrcにマッチします。生成物やvendorコードを一律で読み取り拒否にするような設定は、この深度差を踏まえて書く必要があります。
v2.1.210以降、ファイル権限のパスルールとして実際に参照されるのはEdit(path)とRead(path)だけです。Write(...)・NotebookEdit(...)・Glob(...)のようなパスルールは設定としては受理されますが参照されず、起動時に警告が表示されます。パッケージごとに書き分けるときは、Write(packages/web/**)ではなくEdit(packages/web/**)と書きます。
{
"permissions": {
"deny": [
"Read(./**/dist/**)",
"Read(./**/build/**)",
"Read(./**/*.generated.*)",
"Read(./vendor/**)"
]
}
}Claude Codeのコンテンツ検索は既定で.gitignoreに従います。node_modules/・dist/・build/のような多くのリポジトリですでに.gitignoreに載っているパスは、追加設定なしで検索結果から外れます。denyルールが本当に必要なのは、チェックインされている生成物やベンダーSDKなど.gitignoreの外にあるパスです。
もう1点、denyルールの適用範囲には注意が必要です。denyルールはClaude組み込みのファイルツールと、Claude Codeが認識するBashのファイルコマンド(cat・head・tail・sedなど)に適用されます。PythonやNodeのスクリプトのように、ファイルを自前で開く任意のサブプロセスには適用されません。全プロセスを対象パスへのアクセスから遮断したい場合は、サンドボックスを有効にします。
denyルールと同じ「Claudeが読む量を減らす」文脈に位置づけられるのが、コードインテリジェンスプラグイン(LSP)です。TypeScriptのような静的型付き言語なら、/plugin install typescript-lsp@claude-plugins-officialでLSPプラグインを導入できます。導入後は、Claudeがファイル全体を開かずにシンボル参照や型定義を正確に辿れるようになります。生成物を読ませない設定と、必要なシンボルだけを正確に読ませる設定は、どちらも無駄なコンテキスト消費を削るという同じ狙いの表裏です。
設定の優先順位は次のとおりです。
| 優先度 | 設定 |
|---|---|
| 1(最優先) | 設定管理設定(managed settings) |
| 2 | 設定コマンドライン引数 |
| 3 | 設定ローカルのプロジェクト設定(local project settings、.claude/settings.local.json) |
| 4 | 設定共有のプロジェクト設定(shared project settings、.claude/settings.json) |
| 5 | 設定ユーザー設定(user settings) |
プロジェクト設定のallowルールとadditionalDirectoriesは権限を付与する設定であるため、そのワークスペースでworkspace trustのダイアログを承認するまでは適用されません。パッケージごとに権限を分けたつもりでも、trustを承認していなければ意図した制御は効きません。
additionalDirectoriesと--add-dirでパッケージ横断のアクセスを渡す
packages/apiから起動しつつ、共有ライブラリのpackages/sharedやフロントエンドのpackages/webにも手を伸ばしたい場合に使うのが、アクセス範囲を広げる方法です。
{
"permissions": {
"additionalDirectories": ["../shared", "../web"]
}
}追加ディレクトリのファイルは、元の作業ディレクトリと同じ権限ルールに従います。ただしadditionalDirectoriesで広げるのはファイルアクセスだけです。追加したディレクトリのSkills・CLAUDE.md・rulesは既定では一切ロードされません。
一方、--add-dirフラグやセッション内の/add-dirコマンドは、ロードされる範囲が変わります。
| 追加方法 | CLAUDE.md・rules | Skills・サブエージェント |
|---|---|---|
additionalDirectories(settings) | CLAUDE.md・rulesロードしない(ファイルアクセスのみ) | Skills・サブエージェントロードしない |
--add-dir / /add-dir | CLAUDE.md・rules環境変数CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1を設定したときだけロード | Skills・サブエージェント常にロード |
CLAUDE.local.mdの読み込みにはlocal設定ソースが有効である必要があります。既定で有効です。通常は意識しなくて済みます。.claude/settings.json・.claude/settings.local.json自体は、enabledPluginsとextraKnownMarketplacesの2キーだけが対象です。
この差を知らずにadditionalDirectoriesを設定すると、「追加したディレクトリのCLAUDE.mdやサブエージェントが効かない」と混乱しがちです。よくあるつまずき方です。モノレポで兄弟パッケージのサブエージェントを使いたいときは、この違いが実務上の分かれ目になります。
text /add-dir ../shared
パッケージごとのSkillsをどこまで見せるか
.claude/skills/もパッケージ単位で配置できます。たとえばpackages/api/.claude/skills/api-testing/SKILL.mdのように、APIパッケージ固有のテスト手順をSkillとして持たせられます。paths frontmatterを使えば、特定のファイルパターンに触れたときだけ自動ロードする、という絞り込みも可能です。
可視範囲は起動場所で変わります。サブディレクトリから起動した場合は、そのディレクトリと全ての祖先ディレクトリ、それにuser/enterpriseレベルのSkillsが見えます。リポジトリルートから起動した場合は、ルートのSkillsに加えて、セッション中に実際に触れた全サブディレクトリのSkillsが積み上がっていきます。大きなモノレポをルートから触り続けるセッションでは、これが数百件規模に膨れることがあります。
skillの数が増えると、descriptionが短縮され、Claudeが選択時に手がかりにするキーワードが失われることがあります。複数ディレクトリで共有したいskill(PRレビュー規約やデプロイ手順など)は、リポジトリルートの.claude/skills/に置いておけば、どこから起動しても読み込まれます。リポジトリを跨ぐ・独自にバージョン管理したいskillは、プラグイン化するのも一つの方法です。プラグイン化するとplugin-name:skill-nameという名前空間になり、パッケージ単位のskillと衝突しません。
パッケージ横断の変更は1セッションで進める
packages/sharedの関数名を変更し、packages/apiとpackages/webの呼び出し側を追従させる、といったパッケージ横断のリファクタリングでは、ポイントが2つあります。1つは、変更全体を1つのセッションでClaudeに渡すこと。もう1つは、編集を始める前に計画をファイルへ保存しておくことです。
長いセッションはcompact(要約による圧縮)が入るため、最初に立てた計画が会話履歴の中に埋もれて失われることがあります。計画をファイルに書き出しておけば、compact後もClaudeが参照し直せます。パッケージをまたぐ変更ほど、この一手間の効果が大きくなります。
worktree.sparsePathsで巨大なモノレポのworktreeを軽くする
数百パッケージ規模のモノレポでは、git worktreeを素朴に使うと、無関係なパッケージまで含めた巨大なチェックアウトが並列セッションの数だけ複製され、ディスクと時間を圧迫します。worktree.sparsePathsは、worktree作成時にチェックアウトするパスをあらかじめ絞り込む設定です。
{
"worktree": {
"sparsePaths": [".claude", "packages/api", "packages/shared"],
"symlinkDirectories": ["node_modules"]
}
}sparsePathsで必要なディレクトリだけをsparse checkoutし、symlinkDirectoriesでnode_modulesのような重い依存ディレクトリをシンボリックリンクにして複製を避けます。
sparsePathsのパスはリポジトリルート相対です。どのサブディレクトリから起動していても解釈は変わりません。package.jsonやロックファイルのようなルート直下のファイルは、指定したディレクトリと一緒に常にチェックアウトされます。ただしルート直下のディレクトリは自動では含まれません。上の例で.claudeを明示しているのはこのためです。指定しないと、リポジトリルートの.claude/settings.json・.claude/rules/・.claude/skills/がworktree内から見えなくなります。
1セッション内のworktreeはすべて同じsparsePathsを共有します。サブエージェントが別パッケージにも触れる設計なら、両方の列挙が必要です。なお、sparse checkout中はextensions.worktreeConfigが有効化されます。v2.1.207より前のバージョンでは最後のworktreeを削除したあともこの設定が残り、teaのようなgo-git系ツールがリポジトリを開けなくなる不具合がありました。
worktree自体の作り方や、隔離セッションで起きがちな落とし穴はClaude Code Worktree実践ガイドで扱っています。
--worktreeでClaude Codeにworktreeを作らせた場合、作成後のセッションの作業ディレクトリはworktreeのルートに移ります。そのためプロジェクト設定は、worktreeルートの.claude/settings.jsonから読み込まれます。ただしsparsePathsとsymlinkDirectoriesだけは、worktree作成前の起動ディレクトリから読まれる点が異なります。worktreeセッションにも効かせたい権限ルールやフックは、リポジトリルートの.claude/settings.jsonに置いておくのが安全です。
モノレポ運用でよくあるつまずき
ここまでの設定を組み合わせる際、実際にぶつかりやすい点を挙げます。
- 他チームのCLAUDE.mdが混入する: ルートから起動して作業範囲が広がると、自分の担当外のパッケージのCLAUDE.mdまで拾ってしまいます。
claudeMdExcludesを設定しないままだと、無関係な指示がコンテキストを圧迫します。 - ルートCLAUDE.mdが肥大化する: 全パッケージの規約をルートに書き足していくと、200行という目安をすぐに超えます。パッケージ固有の内容は各パッケージのCLAUDE.mdに移すのが筋ですが、それでも規約が増え続けて階層だけでは捌ききれなくなることがあります。その出口が、パッケージ横断で繰り返し使う規約やワークフローをSkills・Plugins・MCPサーバーへ切り出す方法です。階層を増やすのではなく、規約そのものを1箇所にまとめて配布する発想に切り替えます。
- additionalDirectoriesで追加したのに指示が反映されない: ファイルは読めるのに、そのディレクトリのCLAUDE.mdやSkillsが効いていないと感じたら、
additionalDirectoriesはファイルアクセスのみを広げる設定だったことを思い出す必要があります。設定を読ませたいなら--add-dirと環境変数の組み合わせに切り替えます。 - workspace trustを承認し忘れる: allowルールや
additionalDirectoriesは、trustダイアログを承認するまで適用されません。パッケージごとの権限設計が「効いていないように見える」原因の多くは、ここにあります。 - ルールの置き場所が担当チームごとに散らばる:
.claude/rules/をパッケージごとに個別管理すると、共通ルールが重複したりズレたりします。共有したいルールはシンボリックリンクで1箇所から配ると、更新の手間が1回で済みます。
組織展開では、基盤チームや単一の担当者が先行してモノレポ全体のCLAUDE.md構成を設計する進め方のほうが速く広がります。設定の見直しは3〜6か月ごとを目安にし、主要モデルのリリース後に手応えが鈍ったと感じたときにもあわせて行います。パッケージごとに担当チームが個別にCLAUDE.mdや権限設定を追加していく分散型の進め方は、初速は出ますが、上に挙げた散逸や重複を招きやすい構造です。
よくある質問
サブディレクトリから起動するとルートのCLAUDE.mdは読まれますか
読まれます。起動時に読み込まれるのは起動したディレクトリと全ての祖先ディレクトリのCLAUDE.mdなので、packages/apiから起動すればリポジトリルートも祖先として読み込まれます。読み込まれないのは、リポジトリ内にある他の兄弟パッケージのCLAUDE.mdです。
additionalDirectoriesを設定したのに追加先のCLAUDE.mdが効かないのはなぜですか
additionalDirectoriesがファイルアクセスだけを広げる設定で、CLAUDE.md・rules・Skillsをロードしないためです。追加先のCLAUDE.mdやSkillsも効かせたいなら、--add-dirフラグやセッション内の/add-dirコマンドに切り替えます。CLAUDE.mdとrulesには環境変数CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1も設定します。
ルートのsettings.jsonをパッケージ起動でも効かせるには
方法は3つあります。パッケージ側の設定ファイルにも同じルールを書くか、リポジトリルートの.claude/settings.local.jsonに書くか、管理設定(managed settings)に書くかです。プロジェクト設定は起動したディレクトリからしかロードされないため、この3つ以外の方法ではルートの設定はパッケージ起動時に届きません。
sparsePathsに.claudeを入れないとどうなりますか
ルート直下のディレクトリは自動チェックアウトに含まれません。そのためリポジトリルートの.claude/settings.json・.claude/rules/・.claude/skills/がworktree内から見えなくなります。権限ルールやSkillsをworktreeでも使いたいなら、sparsePathsに.claudeを明示的に加える必要があります。
まとめ
モノレポでのClaude Code運用に、単一の正解はありません。CLAUDE.mdの階層配置を土台に、claudeMdExcludesでノイズを止め、permissionsのallow/denyでパッケージごとの触れてよい範囲を分けます。そのうえでadditionalDirectoriesや--add-dirで必要なときだけアクセスを広げ、大規模ならworktree.sparsePathsでチェックアウトを絞ります。どの設定も独立していて、パッケージ構成に合わせて必要な分だけ積み上げていく形です。
CLAUDE.mdの書き方の実践パターンは、Claude CodeのCLAUDE.mdを実用に引き上げる10のパターンが詳しいです。
起動場所ひとつで、CLAUDE.mdの見え方も、権限の効き方も、worktreeの中身も変わります。モノレポでの設計は、この起動場所依存を前提に組み立てるところから始まります。