Я не могу использовать CRON на реальной кодовой базе
Несколько дней назад в Claude Code появился CRON. Регулярные задачи, нативно, прямо из коробки. То, о чём мы мечтали с первых AI-кодинг-демо — запланировал агента, лёг спать, проснулся — PR смёржены. Инженер, который работает, пока ты не работаешь.
И я понимаю… я даже не могу это использовать. Не в проде. Не на работе. Я работал в archive.com четыре года — мы прошли через три дизайн-системы. Начинали с Shopify Polaris, перешли на Ant Design, когда выросли из Shopify, потом мигрировали на shadcn/ui и Tailwind, потому что Ant Design сам стал легаси. Четыре года, три UI-фреймворка, конвенции, которые жили в головах у людей, бизнес-правила, которые никто никогда не записывал. Направишь на это агента — он побежит. Выдаст код. Красивый, идиоматичный, адский код — тот, что импортирует из всех трёх дизайн-систем в одном файле и каким-то чудом проходит все проверки.
И что делать? Всё ревьюить невозможно. Замедлять агентов нельзя. И уж точно нельзя надеяться, что они сами разберутся, какую дизайн-систему использовать.
Эта статья — о том, что реально работает. Я пользуюсь Claude Code, поэтому примеры отсюда — но паттерн одинаковый, используй ты Cursor, Copilot, Codex или Devin.
Старый цикл vs новый
Старый цикл: пишешь или ревьюишь код, замечаешь код-смеллы по опыту, оставляешь комментарии с объяснением замысла, обещаешь починить «потом» — что обычно значило «никогда».
Новый цикл: зафиксировать правила один раз, дать агентам работать в их рамках, наблюдать, что падает, ужесточать ограничения. Меньше «запомни на следующий раз», больше «это физически не может произойти».
Агенты ломают старый цикл полностью. Когда код генерируется непрерывно, ручное ревью становится самым слабым звеном.
Настоящий враг: незаметная деградация
Самая опасная проблема в системах с агентами — это не явная поломка, а незаметная деградация. Код, который компилируется, проходит все тесты, выглядит совершенно разумно на ревью — и молча нарушает архитектурные договорённости, которые ты считал нерушимыми.
Простой пример: агент добавляет форму на страницу, которую ты мигрировал на shadcn/ui. Он тянет <Form.Item> из Ant Design — потому что другая форма на этой же странице всё ещё его использует. Компилируется. Рендерится. Твоя миграция только что откатилась на один компонент, и ничего в пайплайне этого не заметило.
Или смотри, как это происходит с CSS. Агент пишет новый компонент на Tailwind-утилитах — правильно, по текущему стандарту. Но копирует значение отступа из старого Ant Design-компонента по соседству: p-[24px] вместо шкалы p-6. Одно магическое число не убьёт. Пятьдесят — убьют. Каждый коммит выглядел нормально по отдельности. Деградация была невидима, пока не стала очевидной.
Люди ловят это интуицией. Агенты — нет. Им нужны детерминированные, мгновенные сигналы. Без них ты просто пишешь «всё ещё сломано» в пятнадцатый раз.
Source: ProgrammerHumor.io
Вся игра — в том, чтобы затянуть фидбек-луп: чем меньше времени между ошибкой и сигналом о ней, тем лучше.
Инструкции — лишь пожелания, линтеры — закон
Большинство разработчиков, активно использующих AI, всё ещё живут в старой реальности. CLAUDE.md. Библиотеки скиллов. Аннотации в документах. Опишешь достаточно чётко, думают они, и агент всё сделает. Даже Vercel выпустил библиотеку скиллов — 40+ правил React-производительности, красиво написанных, структурированных как SKILL.md-файлы для AI-агентов. Это действительно отличная работа и реальный шаг вперёд для экосистемы.
Но одних инструкций недостаточно. Не для надёжности. Ты деплоишь слишком много кода, чтобы люди могли всё отловить.

Инструкции важны — они помогают агенту попасть в точку с первой попытки, и хороший CLAUDE.md значительно сокращает цикл итераций. Но «помогает» и «гарантирует» — разные вещи. CLAUDE.md — это пиратский кодекс. А мы надеемся, что вероятностная система будет попадать в яблочко каждый раз. Иногда да. Иногда получаешь красивый, идиоматичный код с первой попытки. А иногда она добавляет неиндексированный запрос в нагруженный эндпоинт, и ты узнаёшь об этом, когда база плавится в 2 ночи в пятницу.
Вот в чём дело: мы уже решили эту проблему. Мы десятилетиями учились, что «просто пишите хороший код» не масштабируется. Мы изобрели юнит-тесты, потому что люди забывают граничные случаи. Мы изобрели линтеры, потому что люди не могут договориться о стиле. Мы изобрели CI, потому что «у меня на машине работает» перестало быть смешным после третьего инцидента на проде. Каждый из этих инструментов существует, потому что благие намерения не выживают при встрече с реальной кодовой базой.
И теперь мы делаем ровно то же самое с LLM. «Просто напиши очень хороший CLAUDE.md.» «Просто добавь больше skills.» Это то же магическое мышление, только с более модной технологией. Мы уже знаем, чем это заканчивается.
CLAUDE.md объясняет «зачем» и помогает агенту сделать правильно с первого раза. Lint-правило гарантирует, что он не накосячит. Skills ускоряют. Линтеры не дают схалтурить. Если можно выбрать только одно — бери линтер.
Guardrails: сложность — главное ограничение
Вот что запускается на каждое изменение:
- ESLint — потому что у агента нет десяти лет набитой руки с твоими конвенциями импортов
- SonarJS — целые классы багов убиваются на корню
- Строгий TypeScript — если типы нестрогие, агент воспользуется каждой трещиной
- Строгие React-ограничения — никаких «креативных» паттернов компонентов в 3 часа ночи
- Prettier — обязательно, без обсуждений, больше никогда не думай о форматировании
Но самый эффективный способ заставить агентов писать чистый код — это жёстко-строгие лимиты на сложность. Не стилевые правила — структурные ограничения на то, насколько большим и запутанным коду разрешено быть.
В ESLint есть строгие правила именно для этого: complexity ограничивает цикломатическую сложность функции, max-depth — вложенность, max-lines-per-function и max-lines заставляют декомпозировать на уровне функций и файлов, max-params держит интерфейсы узкими, max-statements не даёт функции делать двенадцать вещей одновременно. SonarJS добавляет cognitive-complexity — более умную метрику, которая штрафует вложенные условия и разрывы потока сильнее, чем простое ветвление.
LLM по умолчанию идут по пути наименьшего сопротивления. Получив задачу, агент с радостью сгенерирует одну функцию на 150 строк с шестью уровнями вложенности, тремя ранними return'ами и switch внутри try-catch внутри цикла. Оно компилируется. Проходит тесты. Даже работает. Но это нереально поддерживать, и следующий агент, который это тронет, сделает только хуже. Поставь max-lines-per-function: 40, complexity: 10, max-depth: 3, добавь --max-warnings=0 — и агент вынужден декомпозировать. Он выделяет хелперы, именует промежуточные шаги, разделяет ответственности. Конкретные числа менее важны, чем сам факт их наличия — подстрой под свою кодовую базу, но начинай строго и ослабляй только когда правило реально мешает. Ты поставил число, и машина разобралась сама.
Стек не важен — RuboCop, Ruff, clippy работают по тому же принципу. Думай об этом как о функциональном программировании — хороший код минимизирует возможные состояния, и хорошая AI-инфраструктура делает то же самое. Но готовые линтеры убирают споры о синтаксисе. Архитектурные решения требуют чего-то кастомного.
Прежде чем писать что-то кастомное, прошерсти экосистему. SonarJS, unicorn, perfectionist — проверенные временем плагины, до которых у большинства команд никогда не доходили руки. Это было дёшево, пока люди писали весь код сами. Это дорого, когда агент находит каждый пробел, который ты оставил открытым. Пять минут, recommended-конфиг, целые классы багов исчезают. Обычный блокер — сотни существующих нарушений при включении нового правила — перестаёт быть проблемой. Агент может разобрать их оптом: починить простые, сгруппировать остальные по паттерну, расставить точечные eslint-disable там, где фикс пока не оправдан.
Можно ли из этого сделать lint-правило?
Каждый раз, когда видишь что-то, что не должно повториться, спроси: можно ли из этого сделать lint-правило? Этот вопрос — и есть настоящий сдвиг. Он превращает тебя из ревьюера в архитектора, который строит постоянные guardrails — как команда архитектуры, работающая 365 дней в году и никогда ничего не забывающая.
Порог входа реальный — первое правило самое трудное. Но как только паттерн установлен, правила накапливаются и дают кумулятивный эффект. У нас агенты добавляли console.log в продакшн-код вместо нашего кастомного логгера, который шлёт логи в Datadog. Lint-правило на 10 строк это починило — запретить console.log, предложить logger.error. Как только это в линтере, проблема исчезает навсегда.
Люди пугаются 50 кастомных правил. Хорошо — этот дискомфорт и есть сигнал. И некоторые правила будут неидеальными. Это нормально. Правила улучшаются так же, как законы — кто-то не согласен, предлагает изменение, и система становится лучше через спор. Кто-то натыкается на правило, раздражается, открывает PR — и вот у тебя происходит архитектурная дискуссия, которой раньше не было. Кодовая база с плохими правилами — в состоянии, которое можно улучшить. Кодовая база без правил — это просто vibes. А когда правило требует миграции существующего кода, AI + кодмоды делают очистку возможной за часы, а не за кварталы.
Но линтинг — лишь одна форма детерминированного enforcement'а. Тестирование — другая, и AI сделал его написание радикально дешевле. Детальные спецификации, исчерпывающие граничные случаи, property-based тестирование — вещи, которые людям было слишком трудоёмко писать тщательно, теперь тривиально генерируются. Линтинг ловит структурные нарушения. Тесты ловят поведенческие. Вместе они покрывают то, что никакая документация никогда не покроет.
Правила ловят то, что ты уже видел. А как насчёт сбоев, о которых ты ещё не думал?
Что на самом деле ловит CI
Каждый пуш запускает полную проверку — не потому что я не доверяю агенту, а потому что я не доверяю ничему, что не было проверено.
Визуальная регрессия. Playwright-скриншот-тесты проверяют, что UI выглядит как задумано — а не просто что тесты зелёные. Они ловят вещи, невидимые для юнит-тестов: регрессия z-index, которая хоронит модалку под оверлеем, сдвиг макета из-за рефакторинга flex-контейнера, кнопка, которая рендерится, но абсолютно некликабельна. Chromatic делает то же самое для Storybook-воркфлоу — визуальные диффы на каждый PR, никакого ручного QA. Суть одна: если никто не смотрит на экран, экран сломается.
Property-based тестирование. Вместо ручного написания отдельных тест-кейсов ты определяешь свойство, которое должно выполняться всегда: «эта функция никогда не должна возвращать отрицательное число» или «кодирование, а затем декодирование всегда должно возвращать оригинальный вход». Фреймворк генерирует сотни случайных входов и пытается его сломать. Невероятно эффективно для поиска граничных случаев — но большинство команд так и не внедрили, потому что написание хороших определений свойств было трудоёмким. AI это перевернул. Агент может прочитать твой код, вывести, какие свойства должны выполняться, и сгенерировать тесты. Одна команда запустила агентов на 933 модулях — 984 баг-репорта, 56% валидных, примерно $10 за реальный баг. Это фидбек-луп, работающий внутри CI.
Структурная безопасность. DryRun Security протестировали Claude Code, Codex и Gemini при создании двух приложений — 87% PR содержали хотя бы одну уязвимость. Не синтаксические баги. Структурные пробелы: WebSocket-эндпоинты без аутентификации, хотя REST API был защищён, rate-limiting middleware, определённый в файле, но так и не подключённый. Агент написал middleware правильно — он просто не знал, что оно не работает. Статический анализ видит, что файл существует. Он не может определить, что файл не подключён. Нужен CI, который запускает приложение и проверяет поведение, а не только код.
Мониторинг рантайма. Sentry и Datadog прокидывают продакшн-сигналы в очередь задач. Когда что-то падает в 2 ночи, это становится задачей, а не загадкой.
Много механизмов — линтеры, тесты, визуальная регрессия, сканирование безопасности, мониторинг рантайма. Поговорим о том, сколько это стоит — и сколько стоит без этого.
Инвестиция
Настоящая цена — не токены и не SaaS-подписки, а инженерное время на создание инфраструктуры. Написание кастомных lint-правил. Настройка скриншот-тестов. Подключение observability к очереди задач. Ничего из этого не бесплатно, и ничего из этого не деплоит фичи.
Source: Memedroid
Но посмотри, за что ты платишь без этого. CodeRabbit проанализировал 470 GitHub PR и обнаружил, что AI-сгенерированный код содержит в 1.7 раза больше багов, чем написанный людьми. В 2.74 раза больше уязвимостей безопасности. Их вывод: «У нас больше нет проблемы создания. У нас проблема уверенности».
Да, ты платишь за токены. Таксисты платят за бензин — и за машину, за лицензию, за страховку — при марже 5–10%, и никто не задаётся вопросом. Это стоимость ведения бизнеса. В софте мы немного избалованы: 80%+ валовая маржа, а всё средство производства — ноутбук и стул, которые у тебя уже есть. Тул за $200/мес, который ловит хотя бы один продакшн-баг в квартал, уже окупился десятикратно.
Senior-инженер в США обходится компании в $150–200/час. Баг на продакшне, найденный клиентом — это дни расследования, экстренные фиксы и доверие, которое не вернуть. Кастомное lint-правило пишется за полдня и ловит этот класс багов на каждом коммите, навсегда. Playwright-скриншот-сьют настраивается за день и ловит визуальные регрессии, которые никакое ручное ревью не поймает в масштабе. Вопрос никогда не был «можем ли мы позволить себе тулинг?» — вопрос в том, можем ли мы позволить себе без него.
И вот что даёт кумулятивный эффект: каждый добавленный guardrail умножает то, что агент может шипить автономно. Ещё одно правило — на один failure mode меньше для ревью. Десять правил — и целые категории деградации просто перестают происходить. Инфраструктура — это не оверхед, это то, что превращает агента из liability в рычаг.
Цель — получить рычаг от использования агентов, но без компромиссов в качестве софта. — Карпати
Рычаг не даётся бесплатно — ты получаешь его, инвестируя в фидбек-инфраструктуру, которая делает рычаг безопасным.
Организм
Вот к чему всё это вело. Собери всё вместе — и система начнёт сама себя улучшать:
┌─────────────────────────────────────────┐
│ │
▼ │
Agent ──▶ Rules ──▶ CI ──▶ Observability │
│ │
▼ │
Tasks ────────┘
Вот как это работает на практике. Агент открывает PR. Кастомное lint-правило ловит нарушение barrel-файлов — агент исправляет. CI запускает Playwright; скриншот показывает сдвиг макета — агент корректирует CSS. Sentry сообщает о росте 404-х на staging-деплое — создаётся новая задача. Агент подхватывает её. Каждый сбой ужесточил систему. Ни один человек не написал ни строчки кода.
Каждый баг, дошедший до CI, становится правилом, предотвращающим следующий. Система не просто сопротивляется сбоям — она становится сильнее от них. Это не тулчейн. Это организм.
Это не теория. Spotify построили фонового кодинг-агента Honk поверх фидбек-инфраструктуры, в которую инвестировали с 2022 года — за три года до AI-части. Результат: 650+ PR от агентов, смёрженных в продакшн ежемесячно. Merge rate у Devin удвоился с 34% до 67%, когда улучшили понимание кодовой базы — не модель, а контекст.
Паттерн везде одинаковый: побеждают не те команды, которые запускают лучшие модели. Побеждают те, у кого более плотный фидбек-луп.
С чего начать
Где ты сейчас?
| Уровень | Как это выглядит | Признак |
|---|---|---|
| 0 — Vibes | Нет кастомного линтинга, нет CI, всё ревьюишь вручную | «Мои глаза — единственное, что стоит между агентом и продакшном» |
| 1 — Guardrails | Стандартные линтеры + CI, но без кастомных правил | «Агент проходит линт, но всё равно деградирует архитектурно» |
| 2 — Architecture as Code | Кастомные lint-правила, кодирующие конвенции команды | «Правила из CLAUDE.md мигрируют в линтер» |
| 3 — The Organism | Самоужесточающийся цикл: агент → правила → CI → observability → задачи → агент | «Я ставлю агентов на ночь и ревьюю диффы утром» |
Если ты на уровне 0, не стыдно — все там начинают. Суть не в том, чтобы прыгнуть на уровень 3 за ночь. Суть — понимать, куда ты движешься, и начать с первого кастомного правила, которое сделает твою конкретную кодовую базу честнее.
Сегодня: Возьми PR-комментарий, который твоя команда оставляет снова и снова — про конвенции импортов, или barrel-файлы, или console.log в продакшне — и преврати его в кастомное lint-правило. Это твой первый кусочек architecture-as-code.
На этой неделе: Добавь Playwright-скриншот-тесты для трёх самых критичных страниц. Удивишься, что они поймают, чего не ловят юнит-тесты.
В этом месяце: Запланируй CRON-задачу на что-нибудь безопасное — обновление зависимостей, поддержание тестов, чистка заброшенных веток. Пусть агент работает ночью. Ревьюй PR утром. Начни с Claude Code web или Codex web; когда этого станет мало, дешёвый VPS даст больше мощности для той же идеи.
Тест: Если ты можешь делегировать задачу с телефона, ревьюить дифф в дороге и доверять результату — твой фидбек-луп достаточно плотный. Фишка не в том, чтобы работать меньше. А в том, чтобы не быть привязанным к машине.
Если хочешь отправную точку — я собрал playbook с сетапами инструментов на разных бюджетах, и companion-репо — vigiles — которое автоматизирует часть паттернов enforcement из этой статьи.
Заключение
Три дизайн-системы за пять лет. Агент не знает, какую из них использовать — если ты не скажешь ему детерминированно, на каждом коммите.
Вот и весь инсайт, по сути. Агент, который вроде бы простаивал, ждал не лучшую модель — он ждал лучшие сенсоры.
LLM по природе вероятностны. Они угадают в большинстве случаев, а на реальной кодовой базе это значит — недостаточно часто. Никакой prompt engineering этого не изменит. Это не баг, который можно починить; это архитектура.
Так что хватит гнаться за умными промптами. Гонись за скучным, детерминированным, занудным фидбеком — тем, что срабатывает независимо от того, смотрит ли кто-то, тем, которому плевать, насколько уверена была модель.
Линтеры не спят. Тесты не забывают. CI не устаёт.
Название — отсылка к "Attention Is All You Need" (Vaswani et al., 2017) — статье, представившей архитектуру Transformer.