Free

Хороший CLAUDE.md не описує функції — він фіксує лише те, чого Claude не побачить, читаючи код

Хороший CLAUDE.md — не README. У ньому інваріанти, які Claude не виведе з коду. 6 обов'язкових, 4 зайві, 5 запитань.


У моєму проєкті Pickful є децентралізована система громадського журі, криптоплатежі x402, Sign-In with Ethereum, multi-database, push у реальному часі — усе стеки, що з'явилися за останні один-два роки. Claude реалізує ці функції швидко й чисто.

Але відкрийте CLAUDE.md проєкту — і побачите: система журі та x402 — жодного разу не згадані.

Це не недогляд. Роль CLAUDE.md ніколи не була «описувати функції». Вона в тому, щоб фіксувати те, чого Claude ніколи не виведе, читаючи код.

Описи функцій — це злив токенів

Той, хто пише CLAUDE.md уперше, часто ставиться до нього як до README — описуючи кожну ключову функцію:

  • «Система журі дозволяє користувачам скаржитися на контент; поскаржене йде на публічне голосування, присяжні обираються з...»
  • «Платежі x402 запускають on-chain перекази через HTTP-статус 402...»
  • «Лайки дають очки; за 400 очок користувач стає VIP...»

Такий вміст Claude, відкривши topic_review_service.rb / x402.rb / like_points_service.rb, прочитає точніше, ніж ви опишете. Тисячу слів бізнес-логіки Claude зчитує з коду за кілька сотень токенів — без інтерпретаційного зсуву. Код — факт. Опис — інформація з других рук.

По-справжньому Claude спотикається на цих 6 категоріях.

6 категорій, які справді рятують

1. Контр-інтуїтивні архітектурні рішення

У CLAUDE.md Pickful є такі рядки:

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 за замовчуванням припускає:

  • Статичні активи йдуть через Sprockets (інерція старих проєктів)
  • JS через Webpacker або esbuild
  • Фронт — React або мікс Stimulus + Turbo
  • Rich text — рідний ActionText

Без цих рядків у CLAUDE.md, попросивши Claude додати нову JS-функцію, велика ймовірність отримати встановлення Webpacker, правки package.json, конфіг бандлера — усе неправильно, і неправильно тихо (застосунок працює, але пайплайн активів забруднено).

Ці рядки у CLAUDE.md кажуть Claude: не вгадуй, вже вирішено.

2. Розподіл multi-database

PostgreSQL with 4 separate databases:
- primary - Main application data
- cache   - Solid Cache storage
- queue   - Solid Queue jobs
- cable   - Action Cable subscriptions

Проста форма — але може зекономити цілу ніч. Multi-DB за замовчуванням у Rails 8 — нова поведінка, Claude сам не піде перевіряти, скільки баз ви використовуєте. Здавалося б нешкідлива міграція опускається в неправильну базу, у dev помилки немає (усі чотири — PostgreSQL, schema мігрує будь-де). Але в продакшні таблиця job із Solid Queue потрапляє у бекап primary, або модель primary робить запит до cache-бази — баги, що спливають тижнями.

Два рядки в CLAUDE.md проти цілого дня debugging продакшну.

3. «Невидимі умовляння» URL-роутингу

/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 символів, 3-4 символи) поховані в slug-генерації моделей або сервісів. Попросіть Claude додати новий тип короткого посилання — найімовірніше, він згенерує 6-символьний slug, UUID-подібний або чисто цифровий — поза візуальною мовою всієї системи.

Риса цих «умовлянь»: їх порушення не дає помилки, але наступний читач коду відчує, що щось не так. Писати обов'язково.

4. Зашиті бізнес-пороги

VIP status at 400+ points
Posts with 15+ likes are "hot" posts

Обидва числа живуть десь у коді (User#vip?, scope Post#hot?). Проблема: коли Claude торкається чогось сусіднього — править нагороди в очках, додає сповіщення «майже VIP», пише cron для закріплення hot-постів — він не вирівняє пороги в інших місцях автоматично.

Наслідок: за задачу ви даєте 500 очок, а копія каже «можеш стати VIP» (400 достатньо); або сідите дані для нової функції з малою кількістю лайків, і поріг 15 ніколи не перетинається.

Здібності Claude до коду сильні, але системного числового чуття у нього немає. Розміщення ключових порогів у CLAUDE.md призводить до того, що кожна бесіда починається зі знанням: «400 і 15 — особливі числа».

5. Вказівник auth/authz стеку

- Devise (authentication) + Pundit (authorization)
- Pundit policies in app/policies/
- Check UserPolicy, PostPolicy, etc. for permission rules

Завдання цього рядка — навігація, не опис.

Без нього, коли Claude треба додати новий контроль прав, три можливості:

  • Пише unless current_user.admin? прямо в контролері
  • Викопує залишки CanCan, що вже не використовуються
  • Вигадує власний метод authorize? у моделі

Із рядком «Pundit policies in app/policies/» Claude щоразу йде прямо в app/policies/ додавати policy-файл — стиль однорідний.

Один рядок позбавляє Claude «детективної роботи» щоразу.

6. Зовнішні обмеження рівня проєкту

Supported locales: en, zh-CN, zh-TW
Testing stack: RSpec + FactoryBot + Capybara + Shoulda Matchers

Додаючи нову функцію, defaults Claude такі:

  • Тільки англійські рядки
  • Тести на Minitest + fixtures (default Rails)

А ваш проєкт реально вимагає:

  • Переклади на 3 locale
  • RSpec + FactoryBot, не fixtures

Порушення цих «зовнішніх обмежень рівня проєкту» породжує дрібне доробування — переклади добирати, тести переписувати. Запис у CLAUDE.md фіксує раз і назавжди «що треба робити щоразу».

Зворотний бік: оце — чиста трата

Як важливо «треба писати», так само важливо «не писати». Категорії нижче — побачили = видалили:

1. Опис функцій

«Система журі: користувачі можуть скаржитися на порушливий контент, поскаржене йде на публічне голосування, присяжні обираються з...»

→ Claude відкриє topic_review_service.rb і прочитає точніше, ніж ви написали. Засовувати це в кожну нову бесіду — чиста трата.

2. Те, що миттєво читається з дерева каталогів / Gemfile

«app/models/ містить моделі ActiveRecord», «Rails 8», «БД — PostgreSQL»

→ Claude кидає погляд на корінь проєкту та Gemfile — і знає.

3. Загальні програмістські знання

«Controllers should be thin, delegate to services», «Уникайте N+1», «Пишіть тести на основні функції»

→ Це вже в тренувальних даних Claude. Пишіть це, лише якщо ваш проєкт нетиповий — наприклад «ми принципово не використовуємо service layer; логіка живе в контролерах».

4. Контекст поточного завдання

«Зараз ми рефакторимо платіжну систему; фокус на...»

→ Це контекст бесіди, не факт проєкту. Кинути у CLAUDE.md — забруднити всі інші бесіди.

Польовий аудит: мій власний CLAUDE.md теж можна скоротити вдвічі

Доказ «я можу це зробити» — перед проповіддю. Після написання розділу вище я прогнав CLAUDE.md Pickful — 238 рядків — через 5 питань. Результат: приблизно половина — трата.

Що різати (~120 рядків):

Більша частина блоку dev-команд (70 рядків → 10): bin/setup / bin/rails db:migrate / bundle exec rspec / bin/rubocop / bin/brakeman — усе стандартні Rails-команди, уже у тренуванні Claude. Лишити три специфічні для проєкту: bin/jobs (worker Solid Queue), bin/importmap pin (специфічний для ImportMap), bin/kamal deploy.

Список Core Domain Models (35 рядків → прибрати повністю): перерахувати 20 моделей із ролями — класичний приклад «CLAUDE.md у стилі README» — Claude запустить ls app/models/ або прочитає один файл моделі й знатиме. Кидати в кожну бесіду — чиста трата.

Стандартні пункти 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 vs. model specs — Claude робить це за замовчуванням. Зайве спалювання токенів.

Залишається ~100 рядків: конвенції URL-роутингу, розподіл 4 DB, пороги VIP 400 / Hot 15, override Lexxy, анти-default архітектурні рішення, вказівник Pundit, список locale, FactoryBot (не fixtures).

Але важливіше: яких інваріантів ще немає?

Під час аудиту я усвідомив кілька пунктів, які мав додати й не додав:

  • Числа, сховані в системі журі (поріг голосування, критерії придатності присяжного) — в CLAUDE.md не висвітлені взагалі
  • Якщо в x402 є chain id, адреса контракту, обов'язкові env var — без цього Claude не піде grep-ати конфіг і вигадає значення
  • Особливі обмежувальні правила в сервісах point-trading / Referral

238 рядків стиснути до 100–120, плюс 5–10 рядків раніше упущених інваріантів — це ближче до «правильної щільності» CLAUDE.md.

Це не туторіал. Це аудит мого власного проєкту — і я теж написав неправильно. Правильна форма CLAUDE.md — постійно видаляти й постійно додавати — будь-який проєкт, що трохи дозрів, має мати дедалі коротший і щільніший CLAUDE.md.

5 питань перед внесенням правила

Щоразу, перш ніж щось додати у CLAUDE.md, проганяю цей чек-лист:

  1. Чи може Claude вивести правило, прочитавши 3 файли? Може — не пишіть, нехай читає.
  2. Правило контр-інтуїтивне? (Незвичайні пороги, немейнстримний вибір бібліотеки, конфіг проти upstream-defaults.) Так — обов'язково писати.
  3. Це інваріант рівня codebase, чи впливає на один файл? Один файл — у коментар до коду, не у CLAUDE.md.
  4. Чи призведе порушення до тихої помилки Claude? (Без помилки, але семантика неправильна — не та БД, пропущений переклад, обійдена policy.) Так — обов'язково.
  5. Можна пояснити в 3 рядках? Ні — ви самі ще не оформили думку. Поки не пишіть.

Правила, що пройшли всі 5, залишаються; на одне-без-відповіді — видалити або переписати.

Підсумок в один рядок

Правильне використання CLAUDE.md — це не «презентація проєкту», а стиснення прихованого знання між вами та кодовою базою, яке Claude ніколи не заповнить читанням коду — незвичайні рішення, невидимі пороги, конвенції проти defaults, зовнішні обмеження рівня проєкту.

Кожен доданий рядок має відповідати на питання: «Це те, чого Claude не прочитає з коду?» Не прочитає — лишити. Прочитає — видалити.

CLAUDE.md, написаний так, зазвичай менше половини чернетки, але на кожну бесіду цінніший за тисячі слів опису функцій. І він завжди «ще не закінчений» — кожна нова випущена функція підсвічує черговий інваріант, який мав бути всередині, і черговий абзац, який тепер можна вирізати. Видаляти й додавати, видаляти й додавати — це щоденне обслуговування CLAUDE.md.