Claude Code がCLAUDE.mdを読まないとき — セッション開始時に確実に反映する3層の設定

「CLAUDE.mdにしっかり書いたのに、新しいセッションを開いたら無視されていた」——Claude Codeを複数プロジェクトで運用していると、このパターンに必ず遭遇します。
CLAUDE.mdを読まない、というよりも正確には**「読んだけど優先されなかった」か、「そのセッションの文脈では届いていなかった」**という状態です。これは設定ミスではなく、CLAUDE.mdというファイルが持つ構造的な特性です。
この記事では、masatoman.netプロジェクト(記事200本規模、Claude Code自動運用中)で実際に採用している3層の設計と、その背景にある仕組みを整理します。
結論
CLAUDE.mdだけに頼るのではなく、3層で確実性を担保します。
| 層 | 仕組み | 読まれるタイミング |
|---|---|---|
| 1層: @import | CLAUDE.mdから別ファイルを参照 | セッション開始時・コンテキスト読み込み時 |
| 2層: SessionStart Hook | settings.jsonのhookでセッション開始時に実行 | 必ずセッション開始時(LLM判断と独立) |
| 3層: メモリファイル | すべてのプロジェクトのセッションで参照 |
層が下に行くほど「確実に実行される」が、「書けることが限られる」というトレードオフがあります。
この記事の前提
- 運用構成: masatoman.net(Next.js 16 + MDX)をClaude Codeで自動記事生成・デプロイまで一貫運用
- CLAUDE.md規模: プロジェクトルートのCLAUDE.mdが@AGENTS.md importで2ファイル構成
- hook実装: UserPromptSubmit / Stop / PreCompact の3種を運用中
- 本記事のスコープ: セッション「開始時」に指示が届かない問題に絞る(コンテキスト長で破れる「ソフトウォール」の話は参照)→
別記事
読者のよくある詰まり
「CLAUDE.mdにプロジェクトの制約を書いた。次のセッションで試したら、また同じミスをした」
これは多くの場合、以下のどれかです:
- CLAUDE.mdが読まれる前に別の指示が勝っている — システムプロンプトや他のファイルの優先順位
- CLAUDE.mdが長くなりすぎて、後半が"薄く"読まれている — トークン上限に近いと全文注意が払われない
- セッション開始の直後はまだ文脈が薄い — ファイルは読んでいるが、最初のプロンプトでは優先されにくい
そして見落とされがちな4つ目が:
- CLAUDE.mdに書いたことが分散していて、関連ファイルが読まれていない — @importで参照しているファイルが実際には読み込まれていないケース
実際に起きたこと(プロジェクト構造の観察)
masatoman.netのCLAUDE.mdは冒頭がこうなっています:
@AGENTS.md
> **戦略の単一ソース**: 親の `monorepo root/STRATEGY.md` を参照...
# masatoman.net(AI業務設計の実験ログ)
...
@AGENTS.mdという1行が最初に来ています。これはClaude Codeが@ファイル名形式で別ファイルを読み込む仕組みを利用したものです。
なぜこの構造にしたか:CLAUDE.mdが単一ファイルになっていると、「このプロジェクト固有のルール」と「Next.jsバージョン固有の注意」が混在して長くなる。長くなるほど、後半の指示が優先されにくくなります(トークン実測記事
AGENTS.mdを別ファイルに分けて@importすることで、「Claude Codeとして必ず守るべきこと(Next.jsの破壊的変更への注意)」と「このプロジェクト固有の戦略」を分離しています。
Claude Code GitHub Issue #36959でも、複数の独立したユーザーが「CLAUDE.mdが特定の条件でスキップされる」という問題を報告しています。これは本記事の方法で完全に解決するわけではありませんが、3層設計で確実性を高められる根拠になっています。
原因分析:なぜCLAUDE.mdだけでは不十分か
CLAUDE.mdは「LLMがコンテキストとして読む」ものです。これは確率的な動作を意味します:
- 読む確率:高い(ほぼ毎回)
- 優先される確率:コンテキスト量・プロンプト内容によって変動
- セッション開始時の確実性:高い方だが、100%ではない
一方、hooks
- 実行確率:定義されたタイミングで必ず実行(LLMの判断と独立)
- セッション開始時の確実性:SessionStart hookなら100%
この違いが3層設計の根拠になります。
判断軸:何を3層のどこに書くか
1層: CLAUDE.md + @import(コンテキスト系)
書くもの: プロジェクトの戦略・ルール・技術スタック・禁止事項
@AGENTS.md ← フレームワーク固有の注意事項を別ファイルに
@docs/style-guide.md ← スタイルガイドが長い場合は分割
分割の判断基準:
- 更新頻度が違うなら分ける(プロジェクトルールは月1更新、フレームワーク注意は年1更新)
- CLAUDE.md単体が60行を超えてきたら@importで分割を検討
- 「これだけ読めばこのタスクはできる」という単位で分ける
2層: SessionStart Hook(ハーネス系)
書くもの: セッション開始時に必ず実行したいコマンド
{
"hooks": {
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "bash -c 'echo \"[Session] Project: $(basename $(pwd)) | Branch: $(git branch --show-current 2>/dev/null || echo none)\"'"
}
]
}
]
}
}
注意:「SessionStart」という専用hookはClaude Codeには現時点で存在しません。代わりにUserPromptSubmit(最初のプロンプト受信時)を使います。これはLLMのコンテキスト読み込みとは独立して、ハーネスが直接実行します(hot-reload記事
ここに書かない方がいいもの: 長いルールの列挙(hookはコマンド実行のため)
3層: グローバルメモリ(全プロジェクト共通)
書くもの: どのプロジェクトでも共通して守りたいこと
~/.claude/CLAUDE.md に書けば、すべてのプロジェクトのセッションで参照されます。
## 全プロジェクト共通ルール
- ファイル削除の前は必ずgit statusを確認する
- コミットメッセージは日本語で書く
今日やること(3つ以内)
-
CLAUDE.mdが60行を超えているか確認する — 超えていたら@importで分割できる部分を探す(フレームワーク固有の注意、スタイルガイド等)
-
settings.jsonにUserPromptSubmitのhookが入っているか確認する — なければ最小構成(プロジェクト名とブランチ名を表示するだけ)を追加する
-
「毎回同じことを説明している」内容を探す — それはグローバルの
~/.claude/CLAUDE.mdに書くか、hookで自動注入する候補
3層すべてをいきなり整備する必要はありません。まず「CLAUDE.mdが長くなってきた」なら@import分割、「絶対に忘れてほしくない確認がある」ならhookを先に入れる、という順番で十分です。
masatoman のメルマガ — 毎週月曜の朝に手紙を 1 通
masatoman.net の今週の記事 1 本を、読者目線で深掘りした手紙が毎週月曜 9:00 に届きます。「これ自分のことだ」が見つかる予告編。登録特典に「個人開発の収益化チェックリスト 15 項目」。
masatoman のメルマガ — 毎週月曜の朝に 1 通
masatoman.net で今週公開した記事の中から 1 本を、読者目線で深掘りした手紙が届きます。「自分も同じことやってる」「ここで詰まってた」が見つかる予告編。