Claude Code の設定ファイル CLAUDE.md に「こう書け」「これは禁止」「この順番で処理しろ」とルールを追加していったら 300行を超え、AI の出力品質がどんどん落ちていった——そんな経験を経て「99%消した。残したのは、哲学だけ。」という結論に至った話が X で話題になっている。

なぜルールを増やすと AI の性能が落ちるのか

コンテキストウィンドウの競合

LLM はコンテキストウィンドウ内のすべての情報を処理する。CLAUDE.md のルールが増えるほど、実際の作業に使える「注意力」が奪われる。コンテキストが埋まるにつれてパフォーマンスが低下するのは、LLM の根本的な特性だ。

指示の上限問題

IFScale ベンチマークの研究によると、フロンティアモデルは 150〜200個の指示 を超えたあたりから選択的注意のバイアスがピークに達し、それ以降は均一に失敗するパターンに収束する。Claude Code のシステムプロンプト自体がすでに約50個の指示を含んでいるため、ユーザーが使える枠は実質100〜150個。200行の詳細なルールを書いた時点で、すでに予算オーバーだ。

指示追従バイアス

LLM はプロンプトの 先頭と末尾 の指示に従いやすい傾向がある。中間に埋もれたルールは見落とされがちだ。ルールが増えるほど、重要な指示が中間に埋もれて無視されるリスクが高まる。

具体的に何が起こるか

例えば「見出しは H2 を必ず4つ使え」「セクションは5つ構成にしろ」というルールを設定したとする。すると AI は、本来3セクションで十分な内容でも無理やり5セクションに引き伸ばし、冗長な文章を生成してしまう。

ルールに 従うこと自体が目的化 し、最適な出力を考える余地がなくなる。これは人間の組織でも起こる現象だ。過剰なルールがかえって生産性を下げる。

「哲学だけ残す」アプローチ

細かいルールではなく方針を伝える

悪い例:

- 見出しは H2 を4つ使うこと
- 各セクションは200〜300文字
- コードブロックには必ず言語指定をつけること
- 箇条書きは最大5項目まで

良い例:

- 読者が最短で理解できる構成を優先する
- 冗長さよりも明確さを重視する

Anthropic 公式の推奨

Anthropic の公式ドキュメントでも、CLAUDE.md について以下のように推奨している:

  • 肥大化した CLAUDE.md は、実際の指示を AI に無視させる原因になる
  • Claude がすでに正しくやっていることについては、わざわざルールを書かない
  • 削除できるものは削除し、自動化できるものはフックに変換する

Progressive Disclosure パターン

すべての情報を CLAUDE.md に詰め込むのではなく、情報の見つけ方 を教える方法が効果的だ。

1
2
## テスト
テストの書き方は `docs/testing-guide.md` を参照すること。

こうすれば、AI はテストに関するタスクのときだけガイドを参照し、通常時はコンテキストを消費しない。

実践的なガイドライン

CLAUDE.md をスリムに保つコツ

  1. 普遍的なルールだけ書く — すべてのタスクに適用されるものだけを残す
  2. Claude が自然にやることは書かない — わざわざ指示しなくても正しくやることは削除する
  3. 具体的なフォーマット指定を減らす — 出力形式よりも目的と方針を伝える
  4. サブディレクトリの CLAUDE.md を活用する — フロントエンド固有のルールは frontend/CLAUDE.md に分離する
  5. 定期的に棚卸しする — 追加は簡単だが、削除には意識的な effort が必要

目安となるサイズ

Anthropic の公式ベストプラクティスに基づくと、CLAUDE.md は以下の範囲に収めるのが望ましい:

  • ルート CLAUDE.md: 50〜100行以内
  • サブディレクトリ CLAUDE.md: 各20〜30行以内
  • 合計指示数: 100個以内(システムプロンプトの50個と合わせて150個以内)

なぜ Claude Code は CLAUDE.md を大きいまま放置するのか

このノウハウが広く共有されているにもかかわらず、Claude Code 自体には CLAUDE.md の肥大化を防ぐ仕組みがない。その理由はいくつかある。

  1. 追加は簡単だが削除には判断が必要 — Claude Code は「これを覚えて」と言われれば追記するが、既存ルールが不要かどうかを自律的に判断するのは難しい
  2. 個々の追加は合理的に見える — 1行ずつ見ればどのルールも妥当だが、問題は集積効果にある
  3. 安全側に倒す設計思想 — ユーザーが明示的に書いたルールを勝手に削除して「あの設定どこいった?」となる方が、パフォーマンス低下より UX として致命的
  4. プルーニングの仕組みがない — 追記のトリガーはあるが、定期的な棚卸しや自動削除の仕組みは組み込まれていない

つまり、知識としては「少ない方がいい」とわかっていても、実装上は「勝手に消さない」方が安全 というトレードオフの結果だ。

hook で CLAUDE.md の肥大化を自動検出する

Claude Code 自体が整理を提案しないなら、ユーザー側で仕組みを作ればいい。Claude Code の hook 機能を使えば、セッション開始時に CLAUDE.md の行数を自動チェックし、閾値を超えたら警告を出せる。

なぜ CLAUDE.md への記述ではなく hook なのか

「CLAUDE.md に『100行超えたら整理を提案して』と書けばいいのでは?」と思うかもしれない。しかしここに皮肉な矛盾がある——CLAUDE.md が肥大化するほど、その指示自体も無視されやすくなる

hook はシェルスクリプトとして LLM の外で実行されるため、指示追従の問題に影響されない。確実に動作する。

hook スクリプトの実装

~/.claude/hooks/check-claude-md-size.sh として以下のスクリプトを作成する:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#!/bin/bash
# CLAUDE.md の肥大化を検出してセッション開始時に警告する hook
# SessionStart の stdout は Claude のコンテキストに注入される

THRESHOLD=100
CWD=$(jq -r '.cwd // empty' 2>/dev/null)
[ -z "$CWD" ] && CWD="$(pwd)"

total_lines=0
large_files=""

# プロジェクトの CLAUDE.md を再帰的にチェック
while IFS= read -r -d '' file; do
  lines=$(wc -l < "$file")
  total_lines=$((total_lines + lines))
  if [ "$lines" -gt 50 ]; then
    relative=$(echo "$file" | sed "s|$CWD/||")
    large_files="${large_files}\n  - ${relative}: ${lines}行"
  fi
done < <(find "$CWD" -name "CLAUDE.md" -not -path "*/node_modules/*" \
  -not -path "*/.git/*" -print0 2>/dev/null)

# グローバル CLAUDE.md もチェック
if [ -f "$HOME/.claude/CLAUDE.md" ]; then
  lines=$(wc -l < "$HOME/.claude/CLAUDE.md")
  total_lines=$((total_lines + lines))
  if [ "$lines" -gt 50 ]; then
    large_files="${large_files}\n  - ~/.claude/CLAUDE.md: ${lines}行"
  fi
fi

if [ "$total_lines" -gt "$THRESHOLD" ]; then
  echo "⚠️ CLAUDE.md 肥大化警告: 合計 ${total_lines} 行(閾値: ${THRESHOLD} 行)"
  if [ -n "$large_files" ]; then
    echo -e "大きいファイル:${large_files}"
  fi
  echo ""
  echo "整理の提案:"
  echo "  1. Claude がデフォルトで正しく行うルールを削除"
  echo "  2. 特定ディレクトリ専用のルールはサブディレクトリ CLAUDE.md に分離"
  echo "  3. 自動化可能なルールは hooks に変換"
  echo "  4. /claude-md-management:claude-md-improver で自動整理を実行"
fi

exit 0

settings.json への hook 登録

~/.claude/settings.json に以下を追加する:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "startup",
        "hooks": [
          {
            "type": "command",
            "command": "~/.claude/hooks/check-claude-md-size.sh",
            "timeout": 10
          }
        ]
      }
    ]
  }
}

動作の仕組み

  1. SessionStart イベントの startup(新規セッション開始時)にフックが発火
  2. シェルスクリプトがプロジェクト内の全 CLAUDE.md を再帰的にスキャンし、合計行数を算出
  3. 閾値(デフォルト100行)を超えていたら、stdout に警告メッセージを出力
  4. SessionStart hook の stdout は Claude のコンテキストに自動注入される ため、Claude が整理を提案してくれる
  5. 閾値以下なら何も出力しない(通常のセッション開始)

この仕組みなら、LLM の指示追従に依存せず、確実に肥大化を検出できる。

まとめ

AI への指示は「足し算」ではなく「引き算」で考えるべきだ。300行のルールを書くより、プロジェクトの哲学を数行で伝える方が、Claude Code ははるかに良い仕事をする。「99%消した。残したのは、哲学だけ。」——この直感は、LLM の特性を踏まえた合理的なアプローチだといえる。

そして、整理を「意志の力」に頼らず hook で自動検出する仕組み を入れておけば、肥大化を未然に防げる。Claude Code が自発的にやってくれないなら、自分で仕組みを作ればいい。