Claude Code Desktop — мощный инструмент. Он умеет читать ваш проект целиком, редактировать десятки файлов за один заход, запускать тесты, делать коммиты. Именно поэтому без дисциплины он легко превращается в генератор хаоса: за час можно получить «работающий» прототип, который потом неделю стабилизируется. Эта статья — про правила, которые удерживают проект в порядке силами агента и человека-надсмотрщика. Без этих правил возможностями Claude Code невозможно пользоваться долго.
Типичный сценарий выглядит так. Вы открываете Claude Code в пустой папке, кладёте туда Excel-таблицу с заказами и пишете один большой промпт: «сделай мне веб-систему: приёмка заказов, расчёт распилов, материалы, прибыль; стек Kotlin + Ktor + Postgres + React». Через час у вас есть проект на двадцать тысяч строк кода. Сборка проходит. Юнит-тесты на моках — зелёные. Вы радуетесь.
Через неделю начинается разгребание. OrderCalculationService
считает прибыль, но почему-то с ошибкой в копейках. Чините — ломается
OrderService. Чините его — баг в копейках возвращается. Тесты
зелёные, но в браузере на реальном Postgres цифры не сходятся: моки в
тестах не воспроизводят поведения настоящей базы. В build.gradle.kts
тридцать зависимостей, половина из них вам не нужна, но удалить страшно
— вдруг что-то отвалится. CLAUDE.md в проекте нет. История решений нигде
не записана. В каждом новом чате Claude Code заново узнаёт про проект и
каждый раз делает чуть-чуть по-разному.
Это не редкая история. Это типичный финал работы с Claude Code «без правил». Хорошая новость: чтобы не попасть в это состояние, нужно совсем немного дисциплины — не больше, чем требует обычная разработка. Дальше — конкретные правила.
CLAUDE.md — это файл с инструкциями для Claude Code. Кладётся
в корень проекта (можно дополнительно класть в подпапки — для специфичных
подсистем). Claude Code подтягивает его автоматически в каждый чат внутри
этого проекта. Это самый важный артефакт для удержания проекта в порядке:
без него каждый новый чат начинается с нуля.
Что туда писать (для Ваниного проекта):
OrderService,
OrderCalculationService, MaterialService,
OrderRepository — чтобы Claude не выдумывал свои.BigDecimal, не Double.IntegrationTestBase, суффикс *IT.
Моки — только для внешних HTTP-вызовов.Минимальный пример (10–15 строк) — этого уже хватает на старте:
# CLAUDE.md
Веб-система управления производством деревянных лестниц.
Стек: Kotlin 2.x + Ktor + JDBI + PostgreSQL 16 + React 18.
## Конвенции
- Деньги: BigDecimal, scale=2, RoundingMode.HALF_UP. Никогда Double.
- Репозитории: JDBI (OrderRepository, MaterialRepository). Не JPA.
- Миграции: Flyway, V<номер>__<имя>.sql. Схему руками не править.
- Денежные поля в БД: numeric(18,2).
## Тесты
- Интеграционные: реальный локальный Postgres, наследуют IntegrationTestBase, суффикс *IT.
- Моки только для внешних HTTP. Сервисы между собой — без моков.
## Чего не делать
- Не добавлять новые зависимости без обсуждения.
- Не править markupMaterialsPct и формулы прибыли без явной задачи.
- Не переписывать существующие сервисы целиком — только точечные изменения.
CLAUDE.md — живой документ. Решили, что денежные поля в БД — numeric(18,2)?
Записали. Перешли с моков на реальный Postgres? Записали. В идеале CLAUDE.md
обновляется в том же коммите, в котором меняется поведение проекта.
Plan mode — это режим работы Claude Code, в котором агент сначала пишет план изменений и не трогает файлы, пока вы план не одобрите. Это режим, а не slash-команда: включается тогл-кнопкой в интерфейсе или горячей клавишей. В plan mode Claude может читать код, искать по проекту, задавать вопросы — но писать и редактировать ему запрещено.
Когда обязательно включать plan mode:
Что делать с планом, когда он появился. Не нажимать «approve» рефлекторно. Прочитать. Проверить:
OrderService»? Если да — попросите убрать.Если план не нравится — это нормально. Пишете «давай сначала сделаем только шаг 1, без шагов 2–4», и Claude переделывает план. Это дёшево по сравнению с откатом плохого коммита.
Claude Code умеет втянуть в контекст десятки файлов одновременно. Это выглядит мощно, но имеет цену: чем больше всего в контексте, тем хуже модель удерживает важные детали. Десять файлов в одном чате почти всегда хуже, чем три.
Практическое правило: одна задача — одна подсистема. Например:
markupMaterialsPct в MaterialService
и провести его до расчёта в OrderCalculationService» — это одна задача,
два-три файла.
Не нужно надеяться, что Claude сам подтянет нужные файлы. Подтягивайте
вручную через @: @src/main/kotlin/.../OrderService.kt,
@src/test/kotlin/.../OrderServiceIT.kt. Это работает в любом
чате — модель сразу читает указанный файл целиком, и это лучше, чем «найди
сам и почитай».
/clear и /compactДве команды для управления контекстом — стоит их различать.
/clear — полностью очищает контекст текущего чата. Модель
«забывает» всё, кроме CLAUDE.md (он подтянется заново). Использовать,
когда задача принципиально новая и связь с предыдущим
обсуждением не нужна.
/compact — сжимает контекст: Claude сам делает summary
того, что обсуждалось, и продолжает с этим summary вместо полного
лога. Использовать, когда чат разросся, но смысловая связь
нужна — например, вы посередине длинной фичи, уже обсудили
архитектуру и не хотите проговаривать её заново.
На практике /compact применяется заметно чаще: он дешевле
по «потерям памяти». /clear — это явный жест «новая задача,
забыли всё».
Чёткие триггеры — и не нужно героически тянуть один чат бесконечно:
/compact или новый чат.
Это пункт, который Ваня выстрадал лично. Юнит-тесты с моками для
репозиториев — зелёные, легко пишутся, выглядят солидно. Они не ловят
почти ничего из того, что ломается в реальности: NULL
в неожиданном поле, неверный тип в SQL, отсутствие миграции, неправильное
округление в numeric, проблемы с транзакциями. Всё это
вылезает только на настоящем PostgreSQL.
Принцип:
IntegrationTestBase,
на реальном Postgres, файлы с суффиксом *IT (например,
OrderServiceIT, OrderCalculationServiceIT).JwtFilterTest — там БД не нужна).
Когда просите Claude написать тест — явно говорите: «интеграционный,
наследуй IntegrationTestBase, суффикс IT, без
моков на репозитории». Иначе по умолчанию он напишет юнит с моками — это
его привычка из общих практик.
Claude Code умеет коммитить сам. Этим стоит пользоваться, но с оговорками. Главная — сообщение коммита.
Плохо: fixes, update, wip,
обновил код. Через месяц, когда нужно будет понять, в каком
коммите сломалась прибыль, такие сообщения бесполезны.
Хорошо: add markupMaterialsPct field to MaterialService,
fix OrderCalculationService rounding for partial orders,
migrate orders.total to numeric(18,2). Сразу видно, что и где.
Рабочий приём:
Частые мелкие коммиты с понятными сообщениями — это страховка от
ситуации «всё сломалось, не знаю когда». git bisect на
осмысленной истории работает за минуты, на каше из fixes —
не работает вообще.
У модели в Claude Code Desktop есть выпадающий список с уровнем усилия
(effort). Это не slash-команда, это настройка интерфейса
рядом с выбором модели. У Opus уровни: low, medium,
high, xhigh, max. У Sonnet:
low, medium, high.
Практически:
medium — хватает на 80% задач.high — задача с риском (трогаем деньги, схему БД,
многошаговый рефакторинг). Стоит чуть дороже и медленнее, ловит
больше тонких ошибок.xhigh / max — задача плохо понимаема,
или это рефакторинг, где риск регрессии большой, или вы три раза
попросили на high и каждый раз получили не то.
Дороже, медленнее, но обычно стоит того.low — для совсем тривиальных правок (переименовать
переменную, добавить лог). Обычно не нужен.Полминуты на проверку — экономят часы на разгребании.
/clear или новый чат.OrderService, OrderRepository, миграция».
Если совсем не понимаете — сначала plan mode без исполнения, потом задача.Claude Code Desktop — не магия. Это очень быстрый, очень внимательный исполнитель, которому нужны границы. CLAUDE.md задаёт правила игры. Plan mode не даёт ему уходить в свободное плавание. Узкий скоуп удерживает контекст в форме. Реальные тесты на реальном Postgres ловят то, что моки пропускают. Понятные коммиты делают историю восстанавливаемой. Этого набора хватает, чтобы проект не превращался в свалку — даже если кода становится много.