良い CLAUDE.md は機能説明ではない。Claude がコードから推測できない invariant だけ書く。必須 6 類、不要 4 類、5 つの問い。
私の Pickful プロジェクトには、分散型コミュニティ陪審システム、x402 暗号通貨決済、Sign-In with Ethereum、マルチデータベース、リアルタイムプッシュ——どれもここ 1〜2 年で出てきた技術スタックが入っている。Claude はこれらの機能を速く、きれいに仕上げる。
ところがプロジェクトの CLAUDE.md を開くと、陪審システムと x402 という単語は一度も登場しない。
これは手抜きではない。CLAUDE.md の役割は「機能を説明する」ことではなく、Claude がコードを一度読んだだけでは決して見抜けないものを書くことだ。
CLAUDE.md を初めて書く人は、ほぼ README 感覚ですべての主要機能を一通り説明しがちだ。
こうした内容は、Claude が topic_review_service.rb / x402.rb / like_points_service.rb を開いた方があなたの文章より正確に把握する。千字で書いたビジネスロジックを Claude はコード経由で数百トークンで読み取り、しかも解釈のブレがない——コードは事実、説明は二次情報だ。
Claude が本当につまずくのは、以下の 6 種類だ。
Pickful の CLAUDE.md にはこんな行がある:
Propshaft (not Sprockets)
ImportMap (no JavaScript bundler)
Hotwire: Turbo Frames, Turbo Streams, Stimulus
Lexxy gem overrides ActionText:
config.lexxy.override_action_text_defaults = false
どの行もデフォルトの推測に逆らっている。Rails プロジェクトを見た Claude はデフォルトで以下を想定する:
これらを CLAUDE.md に書かないまま、Claude に新しい JS 機能を追加させると、高確率で Webpacker を入れ、package.json を書き換え、bundler 設定を書き始める——全部間違いで、しかも静かに間違える(アプリは動くが、アセットパイプラインが汚染される)。
これらの数行は Claude に言っている:推測するな、決まっている。
PostgreSQL with 4 separate databases:
- primary - Main application data
- cache - Solid Cache storage
- queue - Solid Queue jobs
- cable - Action Cable subscriptions
地味な書き方だが、潰せる落とし穴は丸ごと一晩分あり得る。Rails 8 のマルチ DB は新しい挙動で、Claude は自発的に DB 数を確認しない。一見無関係な migration が間違った DB に落ちても開発時にはエラーにならない(4 つとも PostgreSQL、schema はどこでも通る)。だが本番で Solid Queue の job テーブルが primary バックアップに紛れたり、primary のモデルが cache を見に行ったり——この種のバグは時間が経って初めて浮上する。
CLAUDE.md 上の 2 行 vs 本番障害 1 日。
/p-{slug} - Short post URLs (4-5 char alphanumeric)
/t-{slug} - Topic URLs (3-4 char alphanumeric)
/s-{code} - Short URL redirects (3-4 char alphanumeric)
/r-{referral} - Referral links
Claude は routes.rb からルート自体は読めるが、長さの規約(4-5 chars、3-4 chars)はモデルや service の slug 生成ロジックの中に埋まっている。新しい短縮 URL タイプを追加させると、6 桁、UUID 風、あるいは純数字で slug を生成しがちで——システム全体の視覚的整合性から浮く。
この種の「慣例」は特性が厄介だ:違反してもエラーは出ない。ただ後続の読み手が「なんか違う」と感じる。だから書くしかない。
VIP status at 400+ points
Posts with 15+ likes are "hot" posts
数字はどちらもコード中のどこか(User#vip?、Post#hot? の scope)にある。問題は、Claude が関連機能を触るとき——ポイント付与の調整、「もうすぐ VIP」通知の追加、Hot Posts を pin するジョブの作成——他所の閾値と整合させようと自発的にはしないこと。
結果、あるタスク完了で 500 点を付与しつつコピーは「VIP になれます」(実は 400 点で足りる)。新機能のシードデータを用意するのにいいねが不足して 15 の閾値に永遠に届かない。
Claude のコーディング力は高いが、システム全体としての数字の感覚はない。重要な閾値を CLAUDE.md に置くと、毎回の会話開始時点で「400 と 15 は特別な数字」と知った状態で始まる。
- Devise (authentication) + Pundit (authorization)
- Pundit policies in app/policies/
- Check UserPolicy, PostPolicy, etc. for permission rules
この行の役割はナビであって説明ではない。
これが無いと、Claude が新しい権限制御を追加するとき 3 通りの可能性が生じる:
unless current_user.admin? を直書きauthorize? メソッドを追加「Pundit policies in app/policies/」の一行があれば、Claude は毎回 app/policies/ に policy ファイルを追加する——スタイルが揃う。
一行で Claude の毎回の「探偵仕事」を削れる。
Supported locales: en, zh-CN, zh-TW
Testing stack: RSpec + FactoryBot + Capybara + Shoulda Matchers
新機能を追加するとき、Claude のデフォルトは:
だが実際に必要なのは:
この種の「プロジェクト範囲の外部制約」を破ると、翻訳補完・テスト書き直しという細かな後始末が大量発生する。CLAUDE.md に書くことで「毎回必ずやること」を一発で固定できる。
「絶対書く」と同じくらい重要なのが「書かない」。以下を見つけたら即削除:
1. 機能説明
「陪審システム:ユーザーは違反コンテンツを通報でき、通報後は公開投票フェーズに入り、陪審員は……」
→ Claude は topic_review_service.rb を開けばあなたより正確に読み取る。毎回新しい会話にこれを詰め込むのは純粋な無駄。
2. ディレクトリ構造 / Gemfile から即読めること
「app/models/ に ActiveRecord モデル」「Rails 8 を使用」「DB は PostgreSQL」
→ プロジェクトルートと Gemfile をチラ見すれば分かる。
3. 一般的なプログラミング常識
「Controllers should be thin, delegate to services」「N+1 クエリを避ける」「主要機能はテストする」
→ これらは Claude の訓練データに既に入っている。あなたのプロジェクトが異常なときだけ書く——たとえば「我々は意図的に service 層を使わず、ロジックは controller に書く」。
4. 現在タスクの文脈
「今は決済システムをリファクタリング中、焦点は……」
→ これは会話の文脈であってプロジェクトの事実ではない。CLAUDE.md に突っ込むと他の全会話を汚染する。
「自分もできる」を証明してから説く。上のセクションを書き終えた後、自分の 5 つの質問で Pickful の CLAUDE.md——238 行——を一周した。結果:ほぼ半分が無駄だった。
削るべき部分(約 120 行):
開発コマンドのセクションの大部分(70 行 → 10 行):bin/setup / bin/rails db:migrate / bundle exec rspec / bin/rubocop / bin/brakeman は全部標準 Rails コマンド、Claude の訓練データ内。プロジェクト特有の 3 本だけ残す:bin/jobs(Solid Queue worker)、bin/importmap pin(ImportMap 専用)、bin/kamal deploy。
Core Domain Models のリスト(35 行 → 全削除):20 個のモデル名とその役割を並べるのは「README スタイル CLAUDE.md」の典型——Claude は ls app/models/ かモデルを 1 ファイル読めば把握する。毎回の会話に積むのは純粋な浪費。
Tech Stack の標準項目(28 行 → 8 行):Rails 8 / Devise / Pundit / Tailwind / pg_search は全部 Gemfile から即読める。反直感的なものだけ残す:Propshaft / ImportMap / Lexxy / x402-rails / Grover。
散らばった一般常識:「Controllers should be thin」「Use app/jobs/ for async processing」、request specs / model specs がそれぞれ何を検証するか——これは Claude がデフォルトでやる。トークンの浪費。
残す約 100 行:URL ルーティング慣例、4 DB 分担、VIP 400 / Hot 15 の 2 つの硬い閾値、Lexxy override、反デフォルトのアーキ選定、Pundit ナビ、Locale リスト、FactoryBot(not fixtures)。
だが、より重要なのは:まだ書かれていない invariant はどれか?
監査中に気付いた、追加すべきで追加していないもの:
238 行 → 100〜120 行、さらに 5〜10 行の漏れていた invariant を追加——これで「正しい密度」の CLAUDE.md に近づく。
これはチュートリアルではなく、自分のプロジェクトへの監査だ。自分でも書き切れていなかった。CLAUDE.md の正しい形は削り続け、足し続けること——プロジェクトが成熟するほど、CLAUDE.md は短く、密になっていくべきだ。
CLAUDE.md に何かを加えようとするたび、次のチェックリストを通す:
5 項目を通過したルールは残す;一項目でも答えられないルールは削除か書き直し。
CLAUDE.md の正しい用途は「プロジェクト紹介」ではなく、あなたとコードベースの間にある、Claude がどう読んでも補完できない暗黙知を圧縮すること——異常な選定、不可視の閾値、デフォルトに反する規約、プロジェクト範囲の外部制約。
書く一行ごとが、この問いに答えているべきだ:「このこと、Claude はコードから読み取れないのか?」 読み取れない——残す。読み取れる——消す。
こうして書かれた CLAUDE.md は初稿より半分以上短くなる。それでいて、毎回の会話に対する価値は、数千字の機能説明より圧倒的に大きい。そしてそれは常に「まだ書き切れていない」——新機能を出すたびに、入れ損ねていた invariant に気付き、以前書いたパラグラフが削れることに気付く。削り続け、足し続ける——それが CLAUDE.md の日常メンテナンス。