Claude Codeモノレポ設計 — CLAUDE.md階層とパッケージ単位の権限スコープ
モノレポでのClaude Code運用は、CLAUDE.md階層・claudeMdExcludes・権限のパッケージスコープ・追加ディレクトリの組み合わせで決まります。設定の使い分けを実践シナリオで解説します。
Claude Codeをモノレポで運用する際に組み合わせる設定は、次の4つです。
モノレポで重ねる4つの設定
CLAUDE.mdの階層配置
ルートに全体方針、各パッケージに固有の規約を置きます。
claudeMdExcludes
担当外のパッケージのCLAUDE.mdを読み込み対象から外します。
パッケージ単位の権限
allow/denyのパスルールで、触ってよい範囲を分けます。
アクセス拡張
additionalDirectoriesや--add-dirで、兄弟パッケージへ手を伸ばします。
4種類は独立したレイヤーで、パッケージ構成に合わせて必要な分だけ重ねます。本稿ではpackages/{api,web,shared}という3パッケージ構成のモノレポを例に、どの順で何のために使うかを実践シナリオに沿って扱います。
なお、ここで扱う「モノレポ」は単一リポジトリをパッケージマネージャ(npm/pnpm workspaceやTurborepo)で管理する構成を指します。独立したGitリポジトリをシンボリックリンクで束ねる運用パターンは対象外です。同じ設定の積み重ねは、複数パッケージを持たない大規模な単一ツリーのコードベースにもそのまま当てはまります。Claude Code自体のインストールや基本機能はClaude Codeとは — できること・料金・使い方が詳しく、本稿はモノレポ特有の設定に絞って掘り下げます。pnpmなら、検証範囲の絞り方をClaude Codeでpnpm workspaceを扱う手順にまとめています。
Claude CodeはモノレポのCLAUDE.mdをどう読み込むか
Claude Codeは起動時に作業ディレクトリから上位へたどり、各階層のCLAUDE.mdとCLAUDE.local.mdを探して連結し、コンテキストに載せます。上書きではなく連結なので、ファイルシステムのルートに近い内容から先に並び、起動したディレクトリに近い指示ほど後ろに置かれます。同じ階層ではCLAUDE.local.mdがCLAUDE.mdの後ろに付き、個人用のメモがその階層で最後に読まれます。
gitignoreしたCLAUDE.local.mdは、作成したworktreeにしか存在しません。worktree間で共有したい個人用の指示は、ホームディレクトリのファイルをimportする形にします。
サブディレクトリのCLAUDE.mdは起動時には読み込まれません。Claudeがそのサブディレクトリ配下のファイルを実際に読んだタイミングで、遅延的に取り込まれます。この2つの挙動を組み合わせると、モノレポでの起動場所ごとの見え方が決まります。
起動場所ごとの見え方
リポジトリルートから起動
起動時に読むCLAUDE.mdはルートのものだけです。ファイルアクセスはリポジトリ全体に及びます。
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 Codeで大規模コードベースを探索するコツにあります。
パッケージ単位でCLAUDE.mdを配置し、claudeMdExcludesで他チームの指示を止める
3パッケージ構成のモノレポでは、ルート直下に全体方針を書いたCLAUDE.mdを1つ置きます。packages/api・packages/web・packages/sharedそれぞれには、そのパッケージ固有の規約を書いたCLAUDE.mdを配置します。これが基本形です。ルートから起動すると、作業中に触れたパッケージのCLAUDE.mdが次々とコンテキストに追加されます。Turborepoのturbo.jsonタスクグラフとCLAUDE.mdの対応はClaude CodeでTurborepoのモノレポを設定するが詳しい内容です。
ここで問題になるのが、自分のチームが担当していないパッケージの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.mdは起動ディレクトリから上位へ辿ってすべて連結されるので、ルートの文脈は失われません。公式ドキュメントの表は、複数パッケージにまたがる作業にはルート起動を挙げています。
失われるのは、.claude/settings.jsonなどプロジェクト設定(project settings)の適用範囲です。プロジェクト設定は起動したディレクトリからしかロードされず、CLAUDE.mdのように親ディレクトリから継承されません。packages/apiから起動するとpackages/api/.claude/settings.jsonは読み込まれ、リポジトリルートの.claude/settings.jsonは無視されます。
セッション中に/cdで作業ディレクトリを移した場合は、v2.1.246以降、プロジェクト設定も新しいディレクトリから読み直されます。ルートの権限ルールをパッケージ起動でも効かせたい場合、届け方は3通りです。
ルートの設定をパッケージ起動へ届ける3通り
パッケージ側にも書く
packages/api/.claude/settings.jsonに同じルールを重ねて置きます。settings.local.jsonに書く
リポジトリルートの
.claude/settings.local.jsonは、v2.1.211以降、起動場所によらずリポジトリ内のどのセッションでも読み込まれます。管理設定に書く
managed settingsに置けば、組織全体に同じルールが届きます。
このうちsettings.local.jsonは、Claude Codeが書き込む側でもあります。権限ダイアログで「Yes, and don't ask again」を選ぶと、そのBashコマンドやWebFetchドメインの許可がallowルールとして保存されます。保存先は、packages/apiで起動していても、リポジトリルートの.claude/settings.local.jsonです。リポジトリ内のその後のセッション全体に効きます。worktreeの中で選んだ場合の保存先も、メインチェックアウトのルートです。Windowsなど、Claude Codeがリポジトリルートを使わない環境は例外です。
起動場所への依存が当てはまるのは、.claude/settings.jsonとフックです。スキルと出力スタイル(output style)は、起動ディレクトリの親をたどって探索されます。
この起動ディレクトリ依存を逆手に取る使い方もあります。SessionStartフックで起動場所を読み取り、担当チームのプラグインを案内する構成は、Claude Codeのプラグイン推奨をSessionStartフックで自動化するが詳しい内容です。
パッケージごとに権限を分ける — allow/denyとディレクトリスコープの掛け合わせ
モノレポの各パッケージに異なる権限(このパッケージは自由に編集してよい、あのパッケージは読み取り専用にする)を与えたい場合、パスパターンは4種類に分かれます。
| パターン | 意味 |
|---|---|
//path | 意味絶対パス |
~/path | 意味ホームディレクトリ相対 |
/path | 意味設定ソース相対(プロジェクト設定・ローカル設定なら、起動したディレクトリ配下のpath) |
path または ./path | 意味カレントディレクトリ相対 |
見落としやすいのが、同じパターンでもallowルールとdeny/askルールでディレクトリ名のマッチ深度が異なる点です。Edit(src/**)は、allowルールとしては起動ディレクトリ直下のsrcにしかマッチしませんが、deny/askルールとしては任意の深さのsrcにマッチします。生成物やvendorコードを一律で読み取り拒否にするような設定は、この深度差を踏まえて書く必要があります。
ファイル権限のパスルールとして参照されるのはEdit(path)とRead(path)だけです。Write(...)・NotebookEdit(...)・Glob(...)のパスルールは設定として受理されても参照されません。v2.1.210からは、起動時にその旨の警告が出ます。パッケージごとに書き分けるときは、Write(packages/web/**)ではなくEdit(packages/web/**)と書きます。
denyの側にも非対称があります。Readのdenyルールは同じパスへのEditとWriteも止め、新規ファイルの作成も含みます。一方、NotebookEditは対象外なので、どのツールにも変更させたくないパスにはEditのdenyを足します。この判定は、編集側がv2.1.208以降、書き込み側がv2.1.228以降です。
{
"permissions": {
"deny": [
"Read(./**/dist/**)",
"Read(./**/build/**)",
"Read(./**/*.generated.*)",
"Read(./vendor/**)"
]
}
}Claude Codeのコンテンツ検索は既定で.gitignoreに従います。node_modules/・dist/・build/のように.gitignoreに載っているパスは、追加設定なしで検索結果から外れます。denyルールが必要なのは、チェックインされている生成物やベンダーSDKなど.gitignoreの外にあるパスです。@メンションのファイルピッカーだけを対象にした設定はrespectGitignoreにあります。パッケージが数百を超えてGlobの探索がタイムアウトするときは、CLAUDE_CODE_GLOB_TIMEOUT_SECONDSで上限を引き上げられます。
denyルールの適用範囲にも限りがあります。対象はClaude組み込みのファイルツールと、Claude Codeが認識するBashのファイルコマンド(cat・head・tail・sedなど)です。PythonやNodeのスクリプトのように、ファイルを自前で開く任意のサブプロセスには適用されません。全プロセスを対象パスから遮断したい場合は、サンドボックスを有効にします。SQLクエリや正規表現をBashコマンドとして直接実行させる場合の権限設計はClaude Code SQLと正規表現を安全に書かせる勘所にまとめています。
Claudeが読む量を減らす手段には、コードインテリジェンスプラグイン(LSP)もあります。TypeScriptなら/plugin install typescript-lsp@claude-plugins-officialで導入できます。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のダイアログを承認するまで適用されません。denyとaskはtrustの影響を受けず、承認前から効きます。trustはgitリポジトリのルート単位で記録されるため、packages/apiで一度承認すれば、他のパッケージから起動しても再承認は要りません。サブモジュールのようにリポジトリ内にある別のgitリポジトリは別扱いです。
additionalDirectoriesと--add-dirでパッケージ横断のアクセスを渡す
packages/apiから起動しつつ、共有ライブラリのpackages/sharedやフロントエンドのpackages/webにも手を伸ばしたい場合に使うのが、アクセス範囲を広げる方法です。
{
"permissions": {
"additionalDirectories": ["../shared", "../web"]
}
}追加ディレクトリのファイルは、元の作業ディレクトリと同じ権限ルールに従います。ただしadditionalDirectoriesで広がるのはファイルアクセスだけで、--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・サブエージェント常にロード |
--add-dirで追加したディレクトリのCLAUDE.local.mdを読むにはlocal設定ソースが有効である必要があり、既定で有効です。追加先の設定ファイルから取り込まれるのは、enabledPluginsとextraKnownMarketplacesの2キーだけです。対象は.claude/settings.jsonと.claude/settings.local.jsonで、権限ルールやフックは入ってきません。
たとえば共有パッケージを追加するなら、次のようにします。
/add-dir ../sharedパッケージごとのSkillsをどこまで見せるか
.claude/skills/もパッケージ単位で配置できます。たとえばpackages/api/.claude/skills/api-testing/SKILL.mdのように、APIパッケージ固有のテスト手順をSkillとして持たせられます。具体的な書き方はClaude Codeモノレポのテスト戦略をSKILL.mdで教える手順に手順があります。paths frontmatterを使えば、特定のファイルパターンに触れたときだけ自動ロードする、という絞り込みも可能です。
可視範囲は起動場所で変わります。サブディレクトリから起動した場合は、そのディレクトリからリポジトリルートまでの祖先ディレクトリ、それにuser/enterpriseレベルのSkillsが見えます。リポジトリルートから起動した場合は、ルートのSkillsに加えて、セッション中に実際に触れた全サブディレクトリのSkillsが積み上がっていきます。大きなモノレポをルートから触り続けるセッションでは、これが数百件規模に膨れることがあります。
skillの数が増えると、名前は常に載る一方で、descriptionが丸ごと落ちるskillが出ます。Claudeが使うかどうかを決める手がかりのキーワードが、その分失われます。複数ディレクトリで共有したいskill(PRレビュー規約やデプロイ手順など)は、リポジトリルートの.claude/skills/に置いておけば、どこから起動しても読み込まれます。リポジトリを跨ぐ・独自にバージョン管理したいskillは、プラグイン化するのも一つの方法です。プラグイン化するとplugin-name:skill-nameという名前空間になり、パッケージ単位のskillと衝突しません。
ルート起動のまま特定パッケージのskillを使いたいときは、セッション中に/add-dir packages/apiのようにそのサブディレクトリを渡します。skill・コマンド・サブエージェントが、確認なしでそのセッションの残りの間ロードされます。すでに読める場所なので作業ディレクトリは増えません。v2.1.257以降の挙動です。
パッケージ横断の変更は1セッションで進める
packages/sharedの関数名を変更し、packages/apiとpackages/webの呼び出し側を追従させる、といったパッケージ横断のリファクタリングでは、ポイントが2つあります。1つは、変更全体を1つのセッションでClaudeに渡すこと。もう1つは、編集を始める前に計画をファイルへ保存しておくことです。
長いセッションではcompact(要約による圧縮)が入り、会話履歴の側から計画が欠けることがあります。plan modeで先に計画を立てると、Claudeは計画をファイルに書き出し、Claude Codeはcompactのたびにそのファイルを再投入します。そのため、計画は圧縮後も残ります。
起動フラグ側から見るモノレポの入口(v2.1.287の--help)
設定ファイルとは別に、起動フラグでも同じ範囲を調整できます。v2.1.287のclaude --helpから、モノレポに関わる4つを抜粋します。
claude --help
--add-dir <directories...> Additional directories to allow tool
access to
--bare Minimal mode: skip hooks (those defined
in settings and by installed plugins;
...
attribution, auto-memory, background
prefetches, keychain reads, and
CLAUDE.md auto-discovery. Sets
CLAUDE_CODE_SIMPLE=1.
--setting-sources <sources> Comma-separated list of setting sources
to load (user, project, local).
-w, --worktree [name] Create a new git worktree for this
session (optionally specify a name)--bareはCLAUDE.mdの自動探索を飛ばします。--helpは--add-dirをCLAUDE.mdの渡し先に挙げ、memoryのドキュメントは環境変数が要ると書いています。headlessのドキュメントは、どのマシンでも同じ結果が必要なCIやスクリプトに向くモードとして--bareを挙げています。パッケージごとの指示だけを与えたいCIでは、階層探索の結果に頼らず入力を固定する選択肢になります。
--bareはOAuthとキーチェーンを読まないため、ANTHROPIC_API_KEY(または--settingsのapiKeyHelper)を用意します。CLAUDE.mdの読み込みには前掲の表のとおり環境変数が要るので、--bareと組み合わせるときも併せて設定します。
--setting-sourcesは、user・project・localのどれを読むかを絞ります。
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のルートに移ります。プロジェクト設定も、そこの.claude/settings.jsonから読み込まれます。ただしsparsePathsとsymlinkDirectoriesだけは、worktree作成前に起動ディレクトリの設定から読まれます。worktreeセッションにも効かせたい権限ルールやフックは、リポジトリルートの.claude/settings.jsonに置いておくのが安全です。
スキルは、worktreeのチェックアウトにルートの.claude/skillsが無いとき(gitignoreしている場合など)の扱いが違います。v2.1.277以降は、メインチェックアウトのプロジェクトスキルがworktreeセッションに読み込まれます。
階層で捌ききれなくなったら、組織展開の進め方
規約が増え続けると、階層だけでは捌けなくなります。パッケージ横断で繰り返し使う規約やワークフローは、Skills・Plugins・MCPサーバーへ切り出して1箇所から配る方法があります。
Anthropicの観察では、広く配る前に少人数がツール連携を整えた展開ほど速く広がっています。設定の見直しは3〜6か月ごとが目安で、主要モデルのリリース後に手応えが鈍ったと感じたときにも行います。パッケージごとの担当チームが個別にCLAUDE.mdや権限設定を足していく分散型は、現場の熱量は生まれやすい一方、取りまとめ役がいないと散逸しやすい進め方です。
まとめ
最初に決めるのは設定の中身より、チームがどこからClaudeを起動するかです。そこで見える範囲に過不足が出た分だけを、除外・権限・--add-dir・sparsePathsで足し引きします。
CLAUDE.mdの書き方の実践パターンは、Claude CodeのCLAUDE.mdを実用に引き上げる10のパターンにまとめています。
参照した一次ソース
この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。