Мы платили 39 000 токенов за то, чтобы поправить кнопку

Продолжение истории про то, как мы делали Cursor-агента членом команды. В прошлый раз я рассказывал, как обкладывал проект правилами, hooks и доками. Теперь — про счёт, который за это пришёл, и как мы срезали его на 64%, ничего не сломав.

Симптом

Мобильное приложение, команда из шести человек. За год проект оброс: большой каталожный раздел, оффлайн-режим, гостевой доступ, сложная форма с предзаполнением, iOS home widgets, OTA-обновления, вендорные Expo skills. И параллельно рос слой, который заставляет агентов писать код как мы: CLAUDE.mdAGENTS.md, правила Cursor, доменные документы хрупких зон, hooks.

Каждый новый кусок документации решал реальную проблему. Проблема была в том, что все они грузились всегда.

Симптомы выглядели так:

  • Открываешь новый чат с агентом, пишешь «поправь отступ у кнопки на карточке» — и контекст уже заполнен наполовину до твоего вопроса.

  • Проценты использования модели в Cursor заканчивались подозрительно быстро для объёма реально сделанной работы.

  • Крупные задачи проходили через несколько циклов суммаризации. А суммаризация — это когда агент забывает половину того, о чём вы с ним договорились двадцать минут назад, и вы обнаруживаете это по результату.

  • Контекст заканчивался посреди задачи. Не на сложной — на обычной.

Я довольно долго считал это ценой качества. Логика простая: правила работают, агент пишет в нашем стиле, hooks не дают сломать нативку — значит, толстый контекст это плата за порядок. Оказалось, нет. Оказалось, я платил за дубли.

Что мы вообще измеряли

Прежде чем резать, надо было понять, сколько весит проектный слой. Тут сразу оговорка, потому что это первое, о чём спросят.

Метод грубый: 1 токен ≈ 4 байта UTF-8. Это не замер настоящим токенизатором модели и не то, что показывает Cursor Usage. Реальный fixed prompt в IDE ещё включает каталог инструментов и MCP, историю чата и много чего служебного.

Почему так: мне нужна была не точность, а воспроизводимость на одних и тех же артефактах. Размер файла на диске — метрика, которую можно померить из консоли, сравнить до и после, и которую сможет повторить любой читатель в своём репозитории за минуту. Токенизатор дал бы более честное абсолютное число и ровно такое же относительное изменение. Меня интересовало относительное.

Мерил я ровно тот слой, которым управляюCLAUDE.mdAGENTS.md, правила в .cursor/rules/, каталог skills. То, что добавляет сама IDE, — не моя зона ответственности, и срезать её я не могу.

Счёт «до»

Always-on пакет — то, что грузится почти в каждый чат

Файл

Байты

CLAUDE.md

70 287

AGENTS.md

9 352

.cursor/rules/agent-workflow.mdc

8 632

.cursor/rules/theme-colors.mdc

4 831

.cursor/rules/integration-docs-sync.mdc

5 452

.cursor/rules/expo-vendor-skills.mdc

3 354

Итого

101 908 (~25 500 токенов)

Один CLAUDE.md — 69% пакета. Семьдесят килобайт. Файл, который начинался как «короткий контекст продукта для аналитиков», за год превратился в свалку: шаблоны постановки задач, длиннющий раздел «что ломает PR», карта «где что лежит», продублированная из правил и доменных доков.

Лёгкая правка .ts или .tsx

К always-on добавляется главный кодекс проекта — app-core.mdc с glob на все TypeScript-файлы:

Байты

~токены

Always-on

101 908

~25 500

app-core.mdc

53 071

~13 300

Итого на лёгкой TS-задаче

154 979

~38 700

Вот он, заголовок статьи. Тридцать девять тысяч токенов фиксированного слоя, чтобы поправить отступ. В одном файле на 417 строк лежали правила про гостевой режим, промпты главной страницы, сложную форму, каталожный раздел, оффлайн, виджеты и OTA — всё сразу, независимо от того, что вы трогаете.

Skills

Двадцать шесть записей в skills-lock.json, каталог .agents/skills/ на 1.1 МБ, 27 папок. Это вендорные Expo skills — полезная штука, справочник по EAS и Expo API. Но их описания попадают в system prompt каталогом: чем больше skills, тем длиннее «меню» на каждом ходу. Самый тяжёлый — expo-skill-eval на 148 КБ, eval-харнесс, который в продуктовой разработке не нужен вообще.

Никто не выбирал «поставить 26 skills». Поставили пакет целиком, потому что так проще.

Что я понял не сразу

Две вещи, и обе неприятные.

Первая: много документации — не всегда хорошо. Это звучит банально, пока вы не оказываетесь автором семидесяти килобайт, каждый абзац которых когда-то был написан по делу. Каждый отдельный кусок защищаем. Проблема не в содержании — в том, что всё это грузится независимо от задачи. Документация хороша, когда она приходит в нужный момент. Всегда — это не «нужный момент», это «все моменты сразу».

Вторая, и она специфична для нашего случая: автоматизация мелких задач меняет экономику контекста.Когда агент решает две крупные фичи в день, фиксированный слой в 39k амортизируется — задача всё равно длинная. Когда у вас автоматический pipeline, который закрывает десяток мелких багов в день, каждый в отдельном чате, вы платите этот фиксированный оверхед десять раз за день. Я строил автоматизацию мелких задач и не подумал, что именно она делает фиксированный слой главной статьёй расходов.

Что сделали: четыре фазы

Фаза 1. CLAUDE.md становится индексом

Идея простая: CLAUDE.md — это оглавление, а не учебник. Стек, ключевые сущности, индекс доменных доков, топ-5 hard bans, команды проверки. Всё.

Что уехало:

  • шаблоны постановки задач и критериев приёмки для аналитиков → в docs/for-analysts.md, который грузится, только когда он нужен;

  • длинный раздел «что ломает PR» → он и так продублирован в AGENTS.md;

  • карта «где что лежит» → дубль правил и доменных доков.

Результат: 70 287 → 16 049 байт, −77%. 409 строк → 114.

Замечу: аналитики от этого не пострадали, они получили свой отдельный файл, который читают люди, а не грузит каждая агентская сессия.

Фаза 2. Сплит главного кодекса по globs

Тот самый файл на 417 строк разрезан:

  • core остаётся на **/*.{ts,tsx} — структура компонентов, импорты и алиасы, ссылка на тему, навигация, картинки, нативные баны. То, что верно для любой правки в проекте;

  • домены вынесены в отдельные domain-*.mdc с path-globs: гость, промпты главной, форма создания, каталог, оффлайн, виджеты, OTA, email-авторизация, фото профиля.

Теперь правило про каталожный раздел подтягивается, когда агент трогает его файлы, и не подтягивается, когда он правит кнопку в профиле.

Результат: core 53 071 → 15 328 байт, −71%. 417 строк → 255.

Сумма всех доменных domain-*.mdc — около 24 КБ, но они больше никогда не грузятся все сразу.

Отдельно завёл docs/agent-rules-map.md — человекочитаемую карту «зона → правило → доменный док». Иначе через месяц сам не вспомнишь, где что лежит.

Фаза 3. Гигиена alwaysApply и прополка skills

Прошёлся по правилам с флагом alwaysApply: true и задал каждому один вопрос: оно правда нужно в каждой задаче?

  • integration-docs-sync.mdc — нет. Оно про синхронизацию доков при крупной интеграции. Перевёл на globs: app.config.jsplugins/**eas.json, env-файлы, package.json. Когда агент правит кнопку, правило про интеграции ему не нужно.

  • expo-vendor-skills.mdc — да, оставил always, но сжал с 3 354 до 1 423 байт. Оно страхует от того, что вендорные skills потянут Expo Router и React Query, которых у нас нет. Короткое и высокоценное.

  • theme-colors.mdc и agent-workflow.mdc — оставил без изменений, про них ниже.

Skills прополол по критерию «гарантированно не понадобится в этом проекте»: выкинул eval-харнесс, hosting, app clips, brownfield, DOM-компоненты, web-to-native, миграцию модулей, feedback-скилл.

Результат: lock 26 → 18 записей, каталог 1.1 МБ → 716 КБ (−35%), папок 27 → 19.

Фаза 4. Привычки и защита от отката

Оптимизация, которая держится на дисциплине одного человека, живёт до первого аврала. Поэтому:

  • docs/agent-chat-habits.md — новый чат на каждую задачу, обращение к файлам через @path вместо пересказа, Ask вместо Agent там, где ничего не надо менять;

  • context-sync.mdc — при смене конвенции обновляется пара: доменное правило и соответствующий доменный док, плюс карта. Иначе они разъедутся, и мы получим два источника правды — худшее, что может быть после одного слишком толстого;

  • stop-hooks напоминают об этом: при крупной интеграции и при правке файлов из пары.

Счёт «после»

Always-on

До

После

Δ

Байты

101 908

40 823

−59.9%

~токены

~25 500

~10 200

≈ −15 300 на чат

Лёгкая UI/TS-задача

До

После

Δ

Байты

154 979

56 151

−63.8%

~токены

~38 700

~14 000

≈ −24 700

До:   ████████████████████████████████████████  ~39k
После:██████████████                            ~14k

Задача в хрупкой зоне

Самое интересное. Задача в самой сложной зоне теперь тянет always-on + core + её domain-*.mdc = 58 286 байт, ~14 600 токенов.

То есть работа в самой сложной зоне проекта сейчас легче по контексту, чем раньше была любая правка одной строки.

Чего мы сознательно не резали

Оптимизация без этого раздела превращается в вредительство.

  • Hooks. Запреты на запись в нативное дерево и соседний бэкенд, stop-hook с обязательными lint и type-check. Enforce в рантайме стоит ноль токенов и работает лучше, чем три абзаца текста с просьбой. Это главный вывод предыдущей статьи, и оптимизация его только подтвердила: дешёвое качество — это гарантии среды, а не объём инструкций.

  • Правило про цвета — осталось always. Цвета из Figma мимо темы — самая частая ошибка, а правило короткое. Высокая ценность на байт.

  • Правило рабочего процесса — осталось always. Финал сдачи, «Как тестировать», вердикт по OTA. Это то, что структурирует ответ агента на каждой задаче.

  • Доменные доки. Никуда не делись, просто приходят по требованию, когда агент в соответствующей зоне.

Что изменилось в работе

Качество осталось прежним. PR от агентов проходят ревью так же, как проходили, hooks ловят то же, что ловили, в хрупких зонах регрессий не прибавилось — за всё время после оптимизации я ни разу не поймал момент «раньше было лучше».

А вот что изменилось заметно:

Контекст перестал заканчиваться посреди задачи. Раньше обычная правка стартовала с половиной заполненного окна, и на длинной задаче агент уходил в суммаризацию — то есть терял половину договорённостей и делал не то. Теперь окно почти пустое к моменту, когда вы задаёте вопрос, и на задачу целиком его хватает.

Проценты использования модели перестали таять. Один и тот же лимит теперь закрывает существенно больше реальной работы: на каждом ходу мы не платим за двадцать пять тысяч токенов правил, из которых к задаче относится дай бог пятая часть.

Автоматика стала дешевле в разы. Мелкие баги закрываются в отдельных чатах, десяток в день — это десяток фиксированных слоёв. Срезав 25 тысяч токенов с каждого, мы срезали их со всего pipeline.

Правила стали точнее. Это неожиданный побочный эффект сплита: раньше агент получал кодекс на 417 строк, где правила про оффлайн, лиги, виджеты и гостевой режим лежали вперемешку, — и правило, относящееся к его задаче, тонуло среди восьми чужих. Теперь он видит ровно то доменное правило, в зоне которого работает.

Почему я не ждал падения качества: оно в нашей схеме держится на трёх вещах, и ни одну я не тронул — hooks, которые физически не дают сделать неправильное; доменные доки, приходящие точно в своей зоне; точечные правила по globs. Срезаны были дубли и то, что грузилось не вовремя: вычитание шума, а не сигнала.

Строгого A/B я не ставил — не прогонял один и тот же набор задач на двух конфигурациях. Но когда экономишь две трети контекста и при этом не можешь вспомнить ни одного случая, где стало хуже, вывод достаточно очевиден.

Что забрать себе

Если у вас в репозитории есть CLAUDE.mdAGENTS.md или .cursorrules, потратьте одну минуту:

wc -c CLAUDE.md AGENTS.md .cursor/rules/*.mdc

Сложите то, что грузится всегда, поделите на 4 — получите порядок в токенах. Дальше три вопроса к каждому файлу:

  1. Это нужно в каждой задаче? Если нет — globs или отдельный файл по требованию.

  2. Это уже написано в другом месте? Дубли в трёх файлах не делают правило в три раза убедительнее, они делают контекст в три раза толще.

  3. Это для людей или для агента? Шаблоны для аналитиков, онбординг, длинные объяснения «почему мы так решили» — для людей. Люди читают файл целиком один раз. Агент читает его каждый раз.

И главное, что я бы сказал себе год назад: правила — не единственный способ управлять агентом, и самый дорогой из них. Hooks стоят ноль токенов. Globs стоят ноль токенов, когда файл не подходит. Хорошая структура проекта стоит ноль токенов. Текст в always-on — единственное, за что вы платите на каждом ходу, поэтому там должно остаться только то, что действительно нужно всегда.


Предыдущая статья — про hooks, safe-list и Telegram-бота, который превращает задачу в Notion в готовый PR. Если соберусь с силами, следующая будет про то, как всё это выглядит в enterprise, где процесс спускают сверху.

Буду рад, если поделитесь своими цифрами до/после — интересно, у всех ли CLAUDE.md вырастает до семидесяти килобайт, или это только у меня.

Автор: g0007b1

Источник

Оставить комментарий