Я не могу запустить агентов по расписанию на реальной кодовой базе
Несколько дней назад в Claude Code появились агенты по расписанию. Регулярные задачи, нативно, прямо из коробки. То, о чём мы мечтали с первых 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. Одно магическое число не убьёт. Пятьдесят — убьют. Каждый коммит выглядел нормально сам по себе. Через три недели ты по уши в несогласованности.
Человек бы это поймал. Посмотрел бы на импорт и сказал «стоп, зачем мы тянем Ant Design сюда?» У агентов нет этого чутья. Без жёстких сигналов ты просто пишешь «всё ещё сломано» в пятнадцатый раз.
Source: ProgrammerHumor.io
Тогда я и начал зацикливаться на фидбек-лупах. Как быстро агент может узнать, что ошибся?
Твой CLAUDE.md — пожелание. Твой линтер — нет.
Мой первый инстинкт был такой же, как у всех. Пиши инструкции получше. 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-params держит интерфейсы узкими. max-statements не даёт функции делать двенадцать вещей одновременно. SonarJS добавляет cognitive-complexity, которая умнее обрабатывает вложенные условия. Жалею, что не включил это много лет назад.
Я понял это забавным способом. Без лимитов агент радостно генерирует одну функцию на 150 строк с шестью уровнями вложенности, тремя ранними return'ами и switch внутри try-catch внутри цикла. Компилируется. Проходит тесты. Даже работает. Потом следующий агент это трогает, делает хуже, и поздравляю — у тебя теперь две функции на 150 строк. Поставь max-lines-per-function: 40, complexity: 10, max-depth: 3, добавь --max-warnings=0 и посмотри, что будет. Агент вынужден декомпозировать. Начинает выделять хелперы, нормально именовать вещи, разделять ответственности. Как будто он всегда умел писать чистый код, просто нужно было настоять. Конкретные числа менее важны, чем сам факт их наличия. Начинай строго, ослабляй только когда реально мешает.
Я всё про ESLint, потому что это мой мир, но стек реально не важен. RuboCop, Ruff, clippy — тот же принцип. Готовые линтеры убирают споры о синтаксисе. Твоя архитектура? Для неё нужно что-то кастомное.
Что меня удивило: прежде чем писать что-то кастомное, я нашёл кучу пользы, просто включив плагины, до которых мы годами не доходили. SonarJS, unicorn, perfectionist. Обычная отговорка была «слишком много нарушений чинить». С агентом эта отговорка не работает. Направляешь его на нарушения, он разбирает оптом. Пять минут, recommended-конфиг, целые классы багов исчезают.
Можно ли из этого сделать lint-правило?
В какой-то момент я поймал себя на мысли: а можно ли из этого сделать lint-правило? Каждый раз, когда что-то шло не так. Это стало почти автоматическим. И когда этот переключатель в голове щёлкает, ты больше не ревьюер. Ты тот, кто делает так, чтобы ошибка не могла повториться. Никогда.
Первое — самое трудное. Дальше они снежным комом. Реальный пример: наши агенты радостно пихали console.log в продакшн-код вместо кастомного логгера, который шлёт логи в Datadog. Каждый. Раз. Lint-правило на 10 строк это починило. Запретить console.log, предложить logger.error. Всё. Больше никогда об этом не думал.
Люди слышат «50 кастомных правил» и пугаются. Я тоже пугался. Некоторые правила будут неправильными. Но вот что происходит: кто-то натыкается на плохое правило, раздражается, открывает PR на его изменение. И вдруг у тебя происходит архитектурная дискуссия, которой раньше не было. Этот PR ценнее самого правила. Кодовая база с плохими правилами — в состоянии, которое можно улучшить. Кодовая база без правил — это просто vibes. А когда правило требует миграции существующего кода, AI + кодмоды делают очистку возможной за часы, а не за кварталы.
Линтинг — одна сторона. Тестирование — другая, и честно говоря AI сделал тесты неприлично дешёвыми. Те самые дотошные, исчерпывающие тест-сьюты, которые я всегда говорил, что напишу «потом»? Агент выбивает их за минуты.
Только вот даже со всем этим, правила ловят лишь то, что ты уже видел. Всё, что тебя ещё не кусало, по-прежнему бродит где-то рядом.
Что на самом деле ловит CI
Каждый пуш запускает полную проверку. Ничего личного к агенту — я не доверяю ничему, что не было проверено. Включая свой собственный код, если что.
Playwright-скриншот-тесты стали для меня открытием. Штуки, которые они ловят — это что-то: регрессия z-index, которая хоронит модалку под оверлеем, сдвиг макета из-за рефакторинга flex-контейнера, кнопка, которая рендерится, но абсолютно некликабельна. Ничего из этого не видно в юнит-тестах. Chromatic делает то же для Storybook-воркфлоу. Если никто не смотрит на экран, экран сломается, и ох как я это выучил на собственном опыте.
Я годами игнорировал property-based тестирование. Вместо ручного написания отдельных тест-кейсов определяешь свойство, которое должно выполняться всегда: «эта функция никогда не должна возвращать отрицательное число» или «кодирование, а затем декодирование всегда должно возвращать оригинальный вход». Фреймворк генерирует сотни случайных входов и пытается сломать. Невероятно эффективно, но я так и не внедрил, потому что писать хорошие определения свойств было муторно. AI это перевернул. Теперь я просто направляю агента на код, и он сам определяет, какие свойства должны выполняться. Одна команда запустила агентов на 933 модулях и получила 984 баг-репорта, 56% валидных, примерно $10 за реальный баг.
Безопасность — то, что меня по-настоящему напугало. DryRun Security протестировали Claude Code, Codex и Gemini при создании двух приложений — 87% PR содержали хотя бы одну уязвимость. Не синтаксические баги. Структурные пробелы: WebSocket-эндпоинты без аутентификации, хотя REST API был защищён, rate-limiting middleware, определённый в файле, но так и не подключённый. Агент написал middleware правильно. Он просто не знал, что оно не работает. Это меня зацепило — статический анализ видит, что файл существует, но не может определить, что файл не подключён. Нужен CI, который запускает приложение и проверяет поведение.
Ну и мониторинг рантайма. Мы подключили Sentry и Datadog к очереди задач. Что-то падает в 2 ночи — создаётся задача, агент подхватывает. Я просыпаюсь с фиксом, а не с пожаром.
Да, это много механизмов. Мой менеджер бы спросил: а сколько это стоит?
Инвестиция
Токены дешёвые. SaaS-подписки дешёвые. Настоящая цена — твоё время, и ничего из этого не деплоит фичи. Знаю. Я спорил сам с собой об этом неделями.
Source: Memedroid
А потом я увидел цифры. CodeRabbit проанализировал 470 GitHub PR и обнаружил, что AI-сгенерированный код содержит в 1.7 раза больше багов, чем написанный людьми. В 2.74 раза больше уязвимостей безопасности. Их слова: «У нас больше нет проблемы создания. У нас проблема уверенности».
Ну да, ты платишь за токены. Таксисты платят за бензин, за машину, за лицензию, за страховку, при марже 5-10%, и никто глазом не моргнёт. Мы в софте немного зажрались. 80%+ валовая маржа, а всё средство производства — ноутбук и стул, которые у тебя и так есть. Тул за $200/мес, который ловит хотя бы один продакшн-баг в квартал? Чувак, это уже окупилось десятикратно.
Senior-инженер обходится компании в $150-200/час. Баг на продакшне, найденный клиентом? Дни расследования, экстренные фиксы, доверие, которое не вернуть. А кастомное lint-правило пишется за полдня и ловит этот класс багов навсегда. Playwright-скриншот-сьют настраивается за день. Не знаю, почему я так долго тянул.
И это накапливается. Каждый guardrail умножает то, что агент может шипить без тебя. Ещё одно правило — на одну вещь меньше для ревью. Десять правил — и целые категории багов просто... перестают происходить.
Карпати сказал лучше, чем я смог бы: «Цель — получить рычаг от использования агентов, но без компромиссов в качестве софта». Это то, к чему я пытался подобраться всю эту статью.
Организм
Когда я наконец связал всё это вместе, что-то щёлкнуло. Система начала сама себя улучшать:
┌─────────────────────────────────────────┐
│ │
▼ │
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, я был там же год назад. Вот что я хотел бы, чтобы мне кто-то сказал:
Сегодня: тот PR-комментарий, который твоя команда оставляет снова и снова — про конвенции импортов, barrel-файлы, console.log в продакшне — преврати его в lint-правило. Одно. С этого всё начинается.
На этой неделе: добавь Playwright-скриншот-тесты для трёх самых критичных страниц. Я сам офигел, что они поймали, чего не ловили юнит-тесты.
В этом месяце: запланируй агента на что-нибудь безопасное. Обновление зависимостей, поддержание тестов, чистка заброшенных веток. Пусть работает ночью, ревьюй PR утром. Я начинал с Claude Code web; когда стало мало, дешёвый VPS дал больше мощности для той же идеи.
Как понять, что работает: можешь делегировать задачу с телефона, ревьюить дифф в дороге и доверять результату. Не работаешь меньше, просто больше не прикован к ноутбуку.
Если хочешь отправную точку — я собрал playbook с сетапами инструментов на разных бюджетах, и companion-репо — vigiles — которое автоматизирует часть всего этого. Сэкономило бы мне пару выходных.
Заключение
Три дизайн-системы за пять лет. Агент не знает, какую использовать, если ты не скажешь ему детерминированно, на каждом коммите.
Вот и всё, по сути. Тот агент, которого я не мог направить на свою кодовую базу? Он ждал не лучшую модель. Он ждал лучшие сенсоры.
LLM вероятностны. Они угадают в большинстве случаев, а на реальной кодовой базе «большинство случаев» рано или поздно испортит тебе пятницу. Я с этим смирился. Никакой prompt engineering этого не изменит.
Поэтому я перестал гнаться за умными промптами. Начал гнаться за скучным, детерминированным, занудным фидбеком. Тем, что срабатывает независимо от того, слежу я или нет. Тем, которому плевать, насколько уверена была модель.
Линтеры не спят, а CI не устаёт. Чего не скажешь обо мне.
Название — отсылка к "Attention Is All You Need" (Vaswani et al., 2017) — статье, представившей архитектуру Transformer.