Хороший 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 — описуючи кожну ключову функцію:
Такий вміст Claude, відкривши topic_review_service.rb / x402.rb / like_points_service.rb, прочитає точніше, ніж ви опишете. Тисячу слів бізнес-логіки Claude зчитує з коду за кілька сотень токенів — без інтерпретаційного зсуву. Код — факт. Опис — інформація з других рук.
По-справжньому Claude спотикається на цих 6 категоріях.
У 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 за замовчуванням припускає:
Без цих рядків у CLAUDE.md, попросивши Claude додати нову JS-функцію, велика ймовірність отримати встановлення Webpacker, правки package.json, конфіг бандлера — усе неправильно, і неправильно тихо (застосунок працює, але пайплайн активів забруднено).
Ці рядки у CLAUDE.md кажуть Claude: не вгадуй, вже вирішено.
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 продакшну.
/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-подібний або чисто цифровий — поза візуальною мовою всієї системи.
Риса цих «умовлянь»: їх порушення не дає помилки, але наступний читач коду відчує, що щось не так. Писати обов'язково.
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 — особливі числа».
- Devise (authentication) + Pundit (authorization)
- Pundit policies in app/policies/
- Check UserPolicy, PostPolicy, etc. for permission rules
Завдання цього рядка — навігація, не опис.
Без нього, коли Claude треба додати новий контроль прав, три можливості:
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
Додаючи нову функцію, defaults Claude такі:
А ваш проєкт реально вимагає:
Порушення цих «зовнішніх обмежень рівня проєкту» породжує дрібне доробування — переклади добирати, тести переписувати. Запис у 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 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).
Але важливіше: яких інваріантів ще немає?
Під час аудиту я усвідомив кілька пунктів, які мав додати й не додав:
238 рядків стиснути до 100–120, плюс 5–10 рядків раніше упущених інваріантів — це ближче до «правильної щільності» CLAUDE.md.
Це не туторіал. Це аудит мого власного проєкту — і я теж написав неправильно. Правильна форма CLAUDE.md — постійно видаляти й постійно додавати — будь-який проєкт, що трохи дозрів, має мати дедалі коротший і щільніший CLAUDE.md.
Щоразу, перш ніж щось додати у CLAUDE.md, проганяю цей чек-лист:
Правила, що пройшли всі 5, залишаються; на одне-без-відповіді — видалити або переписати.
Правильне використання CLAUDE.md — це не «презентація проєкту», а стиснення прихованого знання між вами та кодовою базою, яке Claude ніколи не заповнить читанням коду — незвичайні рішення, невидимі пороги, конвенції проти defaults, зовнішні обмеження рівня проєкту.
Кожен доданий рядок має відповідати на питання: «Це те, чого Claude не прочитає з коду?» Не прочитає — лишити. Прочитає — видалити.
CLAUDE.md, написаний так, зазвичай менше половини чернетки, але на кожну бесіду цінніший за тисячі слів опису функцій. І він завжди «ще не закінчений» — кожна нова випущена функція підсвічує черговий інваріант, який мав бути всередині, і черговий абзац, який тепер можна вирізати. Видаляти й додавати, видаляти й додавати — це щоденне обслуговування CLAUDE.md.