AI уже умеет написать метод, тест, миграцию, контроллер, исправить ошибку по трассировке стека и иногда даже самостоятельно дойти от задачи до пул-реквеста. Но есть эффект, который хорошо заметен, если работать с код-агентами не на демо-проекте, а в старой большой системе. Одна и та же модель в одном репозитории выглядит почти как сильный разработчик, а в другом начинает ходить кругами, читать случайные файлы, дублировать существующую логику и уверенно нарушать правила, которые для всей команды казались очевидными. Проблема здесь не всегда в модели.
За последние годы я всё больше прихожу к мысли, что кодовая база сама становится частью AI-инфраструктуры. Если раньше мы проектировали систему в первую очередь для бизнеса, среды выполнения и других разработчиков, то теперь появился ещё один читатель — AI-агент. Он не сидел на ваших созвонах, не помнит инцидент двухлетней давности, не знает, почему в этом месте нельзя использовать «очевидное» решение, и не слышал фразу архитектора: «этот модуль пока не трогаем, через месяц будем выносить». Агент видит только то, до чего способен добраться.
Если коротко: хорошая кодовая база для AI — это проект, который умеет объяснять сам себя. Где найти нужный код. Что он означает. Почему решение устроено именно так. Какое поведение считается правильным. Какие изменения допустимы. Как проверить результат. И в какой момент надо остановиться, а не продолжать «улучшать» систему по собственной инициативе. Такую кодовую базу я дальше буду называть agent-ready codebase.
Термин не является формальным стандартом программной инженерии, это удобная рамка для разговора о проекте, который подготовлен к работе с AI-агентами. Большая часть этой подготовки совпадает с практиками, которыми инженеры занимались задолго до появления LLM: аккуратная архитектура, понятные границы, документация, хорошие тесты, воспроизводимое окружение, линтеры, атомарная история Git. Раньше всё это называли просто хорошей инженерией; теперь от этого зависит ещё и качество работы AI.
В этой статье я хочу собрать всё это в одну практическую систему: сначала разобраться, как агент вообще видит репозиторий, затем пройтись по десяти практикам из моего опыта и в конце собрать конкретный план для легаси, шаблон задачи, модель зрелости и чек-лист. Задача не в том, чтобы придумать ещё один слой процессов вокруг AI, а в том, чтобы понять, какие части обычной инженерии становятся особенно важными, когда код начинает менять не только человек.
Почему качество AI-кода зависит не только от модели
Современные AI-агенты уже умеют писать код, но всё ещё плохо понимают системы
Написать отдельную функцию и изменить реальную систему — две разные задачи. На уровне отдельного метода LLM может видеть сигнатуру, описание и несколько соседних типов. На уровне репозитория ей уже необходимо понять архитектурные границы, найти несколько связанных файлов, восстановить бизнес-правило, разобраться с тестами, конфигурацией и иногда историей изменений. Поэтому обсуждать AI-кодинг только в терминах «какая модель сейчас лучше пишет код» малопродуктивно. Модель важна, но после определённого уровня возможностей всё сильнее влияет среда, в которую эту модель посадили.
Классический пример — реальная задача вроде «разрешить повторную отправку платежа только после определённого статуса». В маленьком примере достаточно добавить if. В боевой системе нужное правило может быть размазано между агрегатом, классом политики, обработчиком очереди, схемой БД, контрактом внешнего API и тестом, который появился после инцидента три года назад. Если агент увидит только обработчик, он вполне способен сделать локально красивое и глобально неправильное изменение.
Синтаксическую ошибку быстро находит компилятор. Неправильно понятое бизнес-правило компилируется, проходит часть тестов и выглядит правдоподобно — именно его сложнее всего заметить на ревью.
Почему одна модель даёт разный результат в разных проектах
Я много раз видел ситуацию, когда разработчики сравнивают AI-инструменты примерно так: «в этом проекте Claude работает отлично, а здесь Cursor тупит», «Codex хорошо справился с новой фичей, но сломался на легаси», «эта модель вообще не понимает наш код». Иногда такой вывод верен, иногда нет. Представьте два проекта. В первом есть понятные модули, тесты запускаются одной командой, названия отражают доменную модель, рядом лежит документация, ошибки линтера объясняют проблему, а Git-история состоит из небольших осмысленных изменений. Во втором src/Service содержит 400 классов, половина поведения спрятана в хуки жизненного цикла фреймворка, документация находится в старой вики, тесты запускаются только у одного разработчика, а последние двадцать коммитов называются fix, fix2, final, final-final.
Модель одна, но информационная среда совершенно разная. В первом проекте агент может последовательно уменьшать неопределённость: нашёл модуль, прочитал его инструкцию, увидел тест, внёс локальную правку, получил детерминированную обратную связь. Во втором он вынужден угадывать, а LLM умеет это слишком хорошо — правдоподобно достраивать недостающую информацию.
Кодовая база становится частью AI-инфраструктуры
Обычно под AI-инфраструктурой понимают модель, эмбеддинги, векторную базу данных, MCP, инструменты, песочницу и всё остальное вокруг запуска модели. Но для код-агента сам репозиторий становится одним из основных источников контекста. По сути, это база знаний, которую агент постоянно исследует во время работы. Текущий код сообщает, как система устроена сейчас. Git рассказывает, как она к этому пришла. Документация объясняет решения. Тесты фиксируют ожидаемое поведение. Бэклог показывает возможное будущее. Линтеры и CI формализуют правила, которые нельзя нарушать. Кодовая база хранит не только программу, но и часть инженерной памяти команды.
Чем больше работы мы делегируем AI, тем важнее становится качество этой памяти.
Главный дефицит — не генерация кода, а инженерный контекст
С генерацией строк кода проблем всё меньше: сотни строк можно получить за несколько минут, иногда даже слишком много. Дефицитом становится другое: корректно понять, что именно нужно менять и почему. Это хорошо видно в исследованиях генерации кода на уровне репозитория. В работе RepoCoder авторы отдельно рассматривают проблему информации, разбросанной по разным файлам репозитория. Их подход с итеративным чередованием извлечения контекста и генерации оказался заметно сильнее варианта, который смотрит только на текущий файл. Более свежие работы двигаются ещё дальше: одного поиска по сходству оказывается недостаточно, потому что зависимый код может быть семантически важен и при этом совсем не похож на текст задачи.
Например, в работе Effective and Efficient Context Retrieval via Partial Dependency Graph for Repository-Level Code Generation, принятой на ASE 2026, исследователи строят контекст вокруг частичного графа зависимостей. В их экспериментах такой подход дал существенный прирост Pass@1 относительно обычных RAG-подходов. Важны здесь не конкретные проценты, а направление: для реальной разработки недостаточно найти похожий текст, нужно восстановить связи внутри системы. Я бы сформулировал проблему так:
Чем сильнее становится генератор, тем ценнее становится способность системы предоставить ему правильный контекст и автоматически проверить результат.
Это меняет разговор об AI-разработке: вместо бесконечной оптимизации промптов возникает инженерный вопрос: насколько сам проект готов быть понятным машине?
Что такое agent-ready codebase
Простое определение agent-ready кодовой базы
Agent-ready codebase — это кодовая база, в которой AI-агент способен относительно надёжно пройти пять шагов:
- Найти место изменения.
- Понять смысл текущего поведения.
- Внести ограниченное изменение.
- Проверить результат.
- Остановиться, если уверенности или полномочий недостаточно.
Последний пункт важен: хорошо подготовленный проект не обязан давать агенту максимальную автономность. Зрелая система явно показывает, где автономность заканчивается. Если изменение затрагивает публичный контракт, платежи, права доступа, продакшен-конфигурацию или миграцию с потерей данных, нормальным результатом работы агента может быть не готовый коммит, а план и запрос подтверждения.
Чем agent-ready отличается от удобного для AI
Я бы разделял эти понятия. Удобный для AI проект просто удобно читать модели. Понятные имена, документация, небольшой размер файлов, хорошая структура. Agent-ready проект дополнительно позволяет действовать: запустить окружение, выполнить тесты, получить обратную связь, понять ограничения, не выйти за границы задачи и сформировать проверяемый результат. Читаемость здесь только первый уровень.
Можно написать идеальную документацию архитектуры, но если проект нельзя поднять локально без трёх секретных команд из головы старшего разработчика, полноценному агенту это мало поможет. Можно иметь 90% покрытия, но если тесты нестабильны и периодически падают сами по себе, агент получит плохой цикл обратной связи. Можно составить отличное руководство по стилю, но если половина правил нигде автоматически не проверяется, модель иногда будет их нарушать. Agent-ready — это про всю среду изменения кода, а не только про красивый репозиторий.
Какими свойствами должен обладать подготовленный проект
Агент может найти нужную часть системы
Навигация — первая проблема. Если задача говорит про subscription renewal, в проекте должно быть достаточно зацепок, чтобы выйти на нужный ограниченный контекст, сценарий использования, обработчик, сущность и тесты. Хорошие имена, карта модулей, стабильная структура директорий, поиск по символам, ссылки из документации и архитектурные границы сильно сокращают пространство исследования.
Агент может понять назначение найденного кода
Найти RenewSubscriptionHandler недостаточно. Надо понять, почему он разрешает одну операцию и запрещает другую, какие инварианты защищает, какие побочные эффекты запускает и какой внешний контракт обязан сохранить. Здесь начинают работать DDD, документация, ADR, тесты и история Git.
Агент может безопасно внести локальное изменение
Локальность — недооценённая характеристика архитектуры. Чем меньше область воздействия у изменения, тем проще агенту удержать причинно-следственную связь. Если для добавления одного бизнес-правила надо изменить двенадцать слоёв, три сервиса и общий вспомогательный класс, проблема не только у AI. Людям такой проект тоже тяжело менять.
Агент может самостоятельно проверить результат
У агента должен быть способ получить не субъективную, а машинную обратную связь: тесты, статический анализ, линтер, проверка типов, архитектурные проверки, контрактные тесты. В исследовании Helping LLMs Improve Code Generation Using Feedback from Testing and Static Analysis авторы показали: модели плохо находили часть собственных ошибок без внешней обратной связи, но заметно лучше исправляли код, когда получали результаты тестов и статического анализа. Вывод практичный: не стоит рассчитывать, что агент «сам всё перепроверит», — дайте ему проверяющий инструмент.
Агент знает, где должен остановиться и обратиться к человеку
Нужны явные границы: какие каталоги можно менять, какие команды запрещены, можно ли создавать миграции, можно ли менять API, нужно ли подтверждение перед удалением данных, разрешён ли доступ в сеть. Без этого автономность быстро превращается в лотерею.
Готовность кодовой базы и автономность агента — не одно и то же
Можно иметь agent-ready проект и разрешать агентам только небольшие задачи на рефакторинг. Это нормально: максимальная автономность не является самостоятельной целью. Цель — сделать изменение системы дешёвым для понимания и безопасным для проверки. А уровень делегирования уже выбирается исходя из риска.
В OpenAI при описании Codex отдельно подчёркивается похожая идея: агент лучше работает в настроенном окружении, с надёжными тестами и понятной документацией; а результат всё равно должен быть проверяемым человеком. В 2025–2026 годах AGENTS.md стал одним из практических форматов, через который код-агенты получают инструкции о структуре проекта, командах тестирования и локальных правилах. Так репозиторий постепенно становится интерфейсом между командой и агентом.
Как AI-агент видит программный проект
Контекстное окно не является полноценной памятью
У больших моделей сегодня огромные контекстные окна. Из этого иногда делают вывод, что достаточно «скормить весь репозиторий» и проблема понимания исчезнет. Она не исчезает: контекстное окно — это ёмкость входа, а не гарантия одинакового внимания ко всему содержимому. Классическая работа Lost in the Middle: How Language Models Use Long Contexts показала, что качество может заметно меняться в зависимости от позиции релевантной информации внутри длинного контекста. Нужные сведения в начале и конце контекста использовались лучше, чем информация, спрятанная в середине.
Исследование было не про кодовые агенты как таковые, но инженерный вывод хорошо переносится: доступная информация и реально использованная информация — не одно и то же. Поэтому я не люблю идею одного гигантского AGENTS.md на 8000 строк: формально агенту передали всё, фактически создали ещё один репозиторий внутри репозитория, по которому тоже надо искать.
Агент не читает весь репозиторий перед каждой задачей
Нормальная работа код-агента больше похожа на исследование. Он получает задачу, ищет упоминания сущности, смотрит дерево проекта, открывает несколько файлов, идёт по импортам или местам использования, ищет тесты, иногда обращается к Git. Затем строит гипотезу, вносит изменение и запускает проверку. У агента есть собственная «траектория внимания». Качество этой траектории зависит от того, насколько легко из одной полезной точки попасть в следующую. Хорошее имя класса ведёт к доменному понятию. Рядом лежит тест. Из теста видна фикстура. В документации есть ссылка на ADR. В сообщении коммита указана причина ограничения.
Плохой проект заставляет делать широкие поиски, открывать десятки файлов и держать в контексте много шума.
Как агент ищет файлы, символы и зависимости
В простейшем случае — обычным поиском по тексту. Затем поиск по символам, ссылкам, импортам. Более продвинутые инструменты добавляют эмбеддинги, семантический поиск, language server, AST и граф зависимостей. Научные работы подтверждают интуицию разработчика: код нельзя рассматривать только как мешок текстовых фрагментов.
GraphCoder использует граф кодового контекста и извлечение контекста от общего к частному. InlineCoder строит контекст вокруг восходящих и нисходящих зависимостей. Свежий DyRetriever идёт по частичному графу зависимостей. Разные методы, но общая мысль одна — структура отношений внутри кода несёт самостоятельную информацию. Отсюда практический вывод: архитектура проекта влияет не только на людей и рантайм. Она влияет на то, насколько качественный контекст агент сможет собрать для конкретного изменения.
Почему структура проекта влияет на качество поиска
Допустим, есть два варианта. В первом проекте:
src/
Billing/
Domain/
Application/
Infrastructure/
Tests/
Во втором:
src/
Controllers/
Services/
Managers/
Helpers/
Utils/
Первый вариант не автоматически лучше. Но если названия соответствуют реальным границам бизнеса, агент получает полезную подсказку уже из дерева файлов. Во втором случае слово Service почти ничего не сообщает о смысле. Хорошая структура сокращает энтропию поиска. Агент раньше понимает, где находится и какие соседние части системы имеют значение.
Из каких источников агент собирает контекст
Я для себя разделяю контекст проекта на несколько источников. Текущий код показывает настоящее состояние системы. Это самая близкая к истине версия реализации. Git показывает прошлое. Почему появилась проверка. В каком изменении добавили поле. Какие файлы менялись вместе. Где проходила граница предыдущей задачи. Документация хранит смысл, который из кода не всегда можно восстановить: принятые решения, ограничения, схемы потоков, договорённости. Тесты показывают ожидаемое поведение в конкретных сценариях. Хороший тест часто объясняет правило быстрее, чем чтение реализации.
Бэклог показывает предполагаемое будущее. Это менее надёжный источник, потому что планы меняются, но иногда он критически важен. Линтеры и CI задают нормативный слой. Они не объясняют, почему правило существует, зато однозначно говорят, что нарушение не допускается. Вместе это уже очень похоже на внешнюю память команды.
Почему доступный контекст ещё не означает использованный контекст
Можно положить в репозиторий папку /docs, написать ADR и README для каждого модуля. Но агент не обязан автоматически найти именно тот документ, который нужен. Информацию надо не только хранить, но и сделать навигационной. Например, корневой AGENTS.md может сказать:
## Architecture
- System overview: `docs/architecture/overview.md`
- Billing rules: `src/Billing/README.md`
- Architecture decisions: `docs/adr/`
- Test conventions: `docs/testing.md`
Do not read all ADRs by default.
Open only ADRs related to the module being changed.
Это намного полезнее, чем вставить содержимое всех ADR прямо в стартовую инструкцию.
Что такое постепенное раскрытие контекста
Мне нравится принцип постепенного раскрытия: на каждом уровне показывать агенту только тот объём информации, который нужен для следующего решения. В корне — карта проекта и основные команды. Внутри ограниченного контекста — локальные правила. В конкретном ADR — причина архитектурного решения. В тесте — поведение сценария. Такой подход решает сразу две проблемы. Во-первых, стартовый контекст остаётся компактным. Во-вторых, знания находятся рядом с областью, к которой относятся. Получается примерно так:
AGENTS.md
↓
docs/architecture/overview.md
↓
src/Billing/AGENTS.md
↓
src/Billing/README.md
↓
docs/adr/0042-retry-policy.md
↓
specific code + tests
Агент углубляется только тогда, когда задача этого требует.
Agent-ready codebase, Context Engineering и Harness Engineering
Как связаны эти три понятия
В 2026 году вокруг AI-разработки появилось много терминов, которые легко смешать. Я бы разделял их по ответственности. Context Engineering отвечает за то, какая информация попадает в рабочий контекст модели в конкретный момент. Agent-ready codebase отвечает за то, можно ли нужную информацию вообще достать из проекта в понятной форме. Harness Engineering отвечает за среду выполнения: инструменты, команды, песочница, полномочия, циклы обратной связи, проверки, наблюдаемость и правила взаимодействия агента с системой. Если провести аналогию с обычным приложением, кодовая база — это данные и доменная структура, инженерия контекста — механизм выборки, обвязка — среда выполнения.
Context Engineering отвечает за отбор информации
Слишком мало контекста — агент начинает додумывать. Слишком много — сигнал тонет в шуме. Плохо подобранный — агент строит правильное решение не для той части системы. Инженерия контекста — это не «написать очень длинный промпт», а управление рабочей памятью: что загрузить сейчас, что оставить снаружи, когда сделать дополнительное извлечение контекста, какую историю сократить, что считать авторитетным источником.
Agent-ready codebase делает информацию доступной
Никакой умный механизм поиска не извлечёт ADR, которого никогда не существовало. Никакое большое контекстное окно не объяснит бизнес-инвариант, который жил только в голове человека, уволившегося два года назад. Никакой агент не запустит стабильные проверки, если у проекта нет воспроизводимого тестового окружения. Подготовка репозитория — фундамент, инженерия контекста работает поверх него.
Harness Engineering превращает правила в управляемый процесс
Можно написать в инструкции: «не нарушай слои архитектуры». Это пожелание. Можно добавить архитектурный тест, который запрещает Domain -> Infrastructure. Это уже ограничение. Можно написать: «после изменений запусти тесты». Это инструкция. Можно дать агенту одну команду make verify, которая запускает юнит-тесты, интеграционные тесты, статический анализ и линтер. Это обвязка. Чем важнее правило, тем меньше мне хочется оставлять его только в естественном языке.
Что такое интеллект репозитория
Ещё один полезный термин — интеллект репозитория. Под ним я понимаю совокупность механизмов, которые позволяют агенту не просто читать файлы, а исследовать систему: текстовый поиск, поиск по символам, семантический поиск, граф зависимостей, историю Git, анализ совместных изменений. Это область, где инструменты в ближайшие годы, думаю, будет развиваться особенно быстро. Пока современные агенты в основном повторяют путь разработчика: grep, дерево файлов, language server, тесты, Git. Но исследования генерации на уровне репозитория уже показывают, что структурное извлечение контекста способно давать сильный прирост.
Важно не спутать качество поиска с качеством исходных данных: умный поиск по хаотичному проекту остаётся поиском по хаосу.
Почему большой контекст не исправляет плохую архитектуру
Большое контекстное окно может временно скрыть архитектурную проблему. Если запихнуть туда двадцать связанных классов, агент, возможно, разберётся. Но это дорогая компенсация. Плохая архитектура увеличивает область рассуждения. Чем больше компонентов нужно одновременно удерживать, тем выше вероятность пропустить неочевидную связь. Для человека это когнитивная нагрузка. Для агента — токены, шаги извлечения контекста и дополнительные точки ошибки. AI не отменяет старую инженерную мысль о локальности, а делает её измеримой в количестве файлов, которые приходится прочитать до одного безопасного изменения.
Почему хорошие инженерные практики особенно важны для AI
Практики, придуманные для людей, становятся интерфейсом для агентов
Большая часть «AI-ready» практик существовала до AI. Принцип единственной ответственности придумали не для LLM. DDD не проектировали под код-агентов. Юнит-тесты появились не для самоисправляющегося цикла генерации. ADR не создавали ради извлечения контекста. Но все они делают инженерное намерение более явным, а именно этого моделям постоянно не хватает. Хорошее имя класса уменьшает неоднозначность. Ограниченный контекст сужает область поиска. Тест превращает требование в исполняемую проверку. Линтер превращает договорённость в детерминированную обратную связь. ADR сохраняет причину решения. То, что помогало людям, стало интерфейсом для AI.
Явность снижает количество догадок модели
Есть принцип, который проходит через всю эту статью: делать скрытое явным. Не string $status, а OrderStatus. Не комментарий в Jira трёхлетней давности, а тест + ADR. Не «у нас принято так делать», а правило линтера. Не «вроде этот сервис нельзя вызывать из домена», а архитектурный тест. Не «прод не трогай», а технически ограниченные полномочия. Каждая такая явность уменьшает пространство, которое модель должна достроить сама.
Локальность уменьшает область потенциального изменения
Если задача умещается в одном модуле, агенту проще понять контекст и проще проверить последствия. Если код сильно связан, рамки быстро разрастаются. Для этого мне нравится смотреть не на длину метода как таковую, а на радиус изменения. Сколько файлов нужно открыть? Сколько концепций понять? Сколько контрактов проверить? Сколько независимых подсистем может случайно затронуть дифф? В этом и состоит реальная сложность задачи для агента.
Детерминированные проверки компенсируют недетерминированность модели
LLM — вероятностная система. Запуск тестов — нет. Статический анализатор — нет. Валидатор схемы — нет. Компилятор — нет. Поэтому автоматические проверки — один из главных элементов agent-ready codebase. Тесты не делают модель умнее, но делают ошибку видимой и дают агенту возможность сделать следующий шаг на основе факта, а не предположения.
В работе Test-Driven Development for Code Generation авторы экспериментально проверяли добавление тестов к исходной постановке задачи и получили более высокую долю успешных решений на бенчмарках генерации кода. Это эксперименты на уровне отдельных функций, их нельзя напрямую переносить на огромный легаси, но сама идея практичная: тест является не только финальной проверкой, но и частью спецификации.
Кодовая база должна не только хранить код, но и объяснять себя
Я бы смотрел на репозиторий как на несколько параллельных представлений одной системы. Код отвечает на вопрос: как работает. Тесты: что обязано работать. Документация: почему устроено так. Git: как мы сюда пришли. Бэклог: куда собираемся двигаться. Линтеры и CI: что менять нельзя. Если эти представления согласованы, агент получает намного более устойчивую модель проекта.
10 практик из моего опыта, которые помогают AI лучше понимать код
Дальше — не академический список лучших практик для LLM, а вещи, к которым я пришёл в обычной разработке и которые стали ещё полезнее с AI-кодингом. Часть из них я использовал задолго до современных агентов; сейчас стало видно, зачем они нужны ещё одному типу читателя.
1. ACDD и атомарная история Git сохраняют ход инженерного мышления
Я уже отдельно писал про ACDD — Atomic Commit Driven Development. Это не ещё одна методология ради аббревиатуры, а ритм работы. Формула простая:
Мысль → фиксация → действие → коммит.
Один смысл — одно действие — один коммит. Когда изменение небольшое и осмысленное, его легче проверить человеку. Но для AI появляется ещё один эффект: Git становится источником исторического контекста. Представьте строку:
if ($payment->isExpired()) {
throw new RetryNotAllowed();
}
По текущему коду можно понять, что происходит. Но почему именно истёкший платёж нельзя повторять? Это бизнес-ограничение? Особенность провайдера? Защита от двойного списания? Временный обходной путь? Если git blame приводит к коммиту:
Prevent retry for expired payments after ProviderX incident
ProviderX can accept delayed retries after the payment session expires,
creating a second charge with a new transaction id.
Refs: INC-2417
контекст меняется полностью. Хорошая история Git — не косметика, а журнал инженерных решений на самом низком уровне.
Почему один коммит должен выражать одно законченное изменение
Атомарность не означает «каждые две строки отдельным коммитом». Я бы определял её через смысл. Хороший коммит можно объяснить одним предложением. У него есть понятная причина. Его можно отдельно просмотреть. В идеале — отдельно откатить. Плохой коммит выглядит так:
Update billing
и внутри:
- новая политика повторов;
- переименование DTO;
- форматирование 80 файлов;
- обновление зависимости;
- исправление старого теста;
- удаление отладочного лога.
Для человека это дорогое ревью. Для агента — плохой исторический контекст: невозможно понять, какие изменения были причинно связаны.
Что агент может узнать из хорошей истории Git
Git даёт несколько полезных типов информации. git log -- path показывает развитие конкретного файла. git blame помогает найти изменение, в котором появилась строка. git show <commit> даёт локальный дифф вместе с сообщением. История связанных коммитов показывает последовательность решения. Иногда это почти готовая трассировка рассуждений команды, только без внутреннего монолога.
Важно другое: Git не попадёт в контекст автоматически только потому, что он хороший. Агент должен понимать, когда обращаться к истории. Я бы явно указывал это в инструкциях: если код содержит неочевидное ограничение, обходной путь, обратную совместимость или странную ветку — перед изменением посмотреть git blame и связанные коммиты.
Почему я не люблю бездумный squash
Squash полезен, когда промежуточная история действительно состоит из шума: wip, fix typo, oops. Но если пять самостоятельных инженерных шагов превращаются в один огромный коммит «Implement feature», мы теряем структуру изменения. Я не считаю, что squash всегда зло. Вопрос в том, что остаётся после него. Если история после merge всё ещё отвечает на «что и почему менялось» — отлично. Если превращается в снимки больших PR, часть внешней памяти проекта исчезает.
2. Документация классов и методов раскрывает скрытый смысл кода
Я не сторонник документировать каждый getter и писать комментарии ради покрытия документации. Комментарий вида:
// Get user by id
public function getUserById(int $id): User
не помогает никому. Полезная документация начинается там, где сигнатура и реализация не передают важный смысл. Например:
/**
* Retries a payment using the original provider session.
*
* Business invariant:
* - allowed only while provider session is active;
* - must never create a new external transaction;
* - duplicate provider response is treated as success.
*
* This method is intentionally not used for manual recovery.
*/
public function retry(Payment $payment): void
Здесь появляются вещи, которые агенту иначе пришлось бы восстанавливать по нескольким файлам.
Что именно стоит документировать
Я бы в первую очередь фиксировал:
- бизнес-инварианты;
- важные побочные эффекты;
- неочевидные ограничения;
- допустимые и недопустимые состояния;
- причины странного поведения;
- требования обратной совместимости;
- связь с внешней системой, если от неё зависит логика.
Документация полезна там, где отвечает на «почему», а не пересказывает «как». При этом есть опасность создать противоположную проблему — информационный шум. Если над каждым методом висит полстраницы очевидного текста, агенту становится только сложнее отделить сигнал от шаблона.
3. Тесты по AAA дают агенту понятную структуру сценария
Я люблю Arrange, Act, Assert не из догматизма: такой тест читается как маленькая история.
public function testExpiredPaymentCannotBeRetried(): void
{
// Arrange
$payment = PaymentFixture::expired();
// Act
$action = fn () => $this->retryPayment->execute($payment);
// Assert
self::assertThrows(RetryNotAllowed::class, $action);
}
Сначала состояние мира. Потом действие. Потом ожидаемый результат. Для человека структура очевидна. Для агента — тоже. Хаотичный тест, в котором вперемешку создаются фикстуры, вызываются три сценария использования, меняется время, делаются шесть несвязанных утверждений и потом ещё проверяется мок, плохо работает как спецификация. Чтобы понять, какое правило он защищает, надо реконструировать сценарий.
Один тест — один логический результат
Здесь важно не впасть в формализм «один тест = один assert». Иногда один логический результат проверяется несколькими техническими утверждениями. Например, «платёж успешно завершён» может означать:
self::assertSame(PaymentStatus::PAID, $payment->status());
self::assertNotNull($payment->paidAt());
self::assertCount(1, $events->ofType(PaymentPaid::class));
Это всё ещё один результат. Критерий проще: можно ли дать тесту одно конкретное название без and, also, then somehow.
4. Документация тестов объясняет бизнес-смысл проверяемого поведения
Эта практика особенно полезна в сложных доменах. Название теста часто говорит, что проверяется, но не говорит, почему это важно. Например:
/**
* ProviderX expires the original payment session after 30 minutes.
* Retrying after expiration may create a second external transaction,
* therefore the system must reject this operation.
*
* Introduced after INC-2417.
*/
public function testExpiredPaymentCannotBeRetried(): void
Теперь тест становится маленьким архивом бизнес-контекста. Мне нравится идея рассматривать код, тест и документацию как три представления одного намерения:
- рабочий код реализует правило;
- тест доказывает наблюдаемое поведение;
- документация сохраняет причину.
Это особенно полезно для AI, потому что причина часто не выводится из поведения однозначно.
Когда документация тестов становится опасной
Когда устаревает. Старый комментарий над новым поведением хуже отсутствующего комментария, потому что создаёт ложную уверенность. Поэтому изменение бизнес-поведения должно включать проверку всей связки: код → тесты → документация. В идеале это входит в критерии готовности и инструкции для агента: если изменилось поведение, проверь связанную документацию и тестовое описание.
5. SOLID и единственная ответственность уменьшают область рассуждения агента
У единственной ответственности много интерпретаций. Для этой статьи мне важен практический эффект: компонент с одной законченной ответственностью создаёт меньшую область рассуждения. Если InvoiceService одновременно создаёт счёт, отправляет письмо, считает НДС, пишет журнал аудита, вызывает ERP и обновляет статистику пользователя, любое изменение тянет за собой широкую область анализа. Если эти ответственности разведены по понятным компонентам, агент может работать локальнее. Это не означает, что надо дробить всё на методы по две строки.
Наоборот, чрезмерная декомпозиция иногда делает понимание хуже. Сценарий, который раньше читался сверху вниз в одном сценарии использования, превращается в прыжки по пятнадцати приватным методам. Граф вызовов становится больше, а локальный смысл — меньше. Я бы формулировал так: метод или класс должен быть достаточно маленьким, чтобы иметь одну ответственность, и достаточно цельным, чтобы эту ответственность можно было прочитать без археологии.
Радиус воздействия важнее количества строк
Качество декомпозиции я бы измерял не количеством строк, а радиусом воздействия. Если изменить правило можно в одном агрегате и трёх тестах — хорошо. Если надо трогать общий базовый класс, хелпер, подписчик событий и четыре несвязанных модуля — границы ответственности, скорее всего, размыты.
6. DDD делает предметную область видимой непосредственно в коде
Чем больше я работаю с AI в разработке, тем сильнее мне снова нравится DDD. Не как набор тяжёлых паттернов, а как способ сделать бизнес-смысл частью кода. LLM прекрасно знает, что такое Manager, Service, Helper, Processor. Проблема в том, что эти слова почти ничего не говорят о вашем бизнесе. А вот CreditLimit, RepaymentSchedule, SubscriptionRenewal, WithdrawalPolicy, InvoiceNumber уже несут смысл.
Единый язык как общий язык бизнеса, разработчика и AI
Если в задаче написано «renew subscription», в документации — renewal, в коде — ProlongationManager, в БД — recurrent, а в UI — «автопродление», даже человек сначала строит словарь переводов. У агента та же проблема. Единый язык уменьшает количество таких преобразований. Одно понятие проходит через задачу, код, тесты и документацию. По сути это семантическое сжатие: меньше терминов — меньше неоднозначности.
Ограниченный контекст как естественная граница агентской задачи
Ограниченный контекст очень удобно использовать как рамки задачи. Задача относится к Billing? Значит, сначала агент читает src/Billing/AGENTS.md, архитектуру Billing и тесты этого модуля. Только если обнаруживается внешний контракт, выходит наружу. Это лучше, чем начинать каждое изменение с исследования всего монолита.
Агрегаты, объекты-значения и доменные события
Агрегат полезен тем, что собирает инварианты в одном месте. Объект-значение превращает ограничение в тип. Вместо «строка, которая на самом деле код валюты по ISO» появляется Currency. Доменное событие делает значимое изменение явным: PaymentPaid, SubscriptionCancelled, LimitExceeded. Для агента это дополнительные опорные точки: он меньше додумывает бизнес из технических деталей.
Почему магия фреймворка мешает
AI особенно плохо чувствует поведение, которое невозможно увидеть из локального кода. Скрытые хуки жизненного цикла. Неявное автосвязывание зависимостей. Глобальное состояние. Конфигурация, которая незаметно подменяет реализацию. Колбэки Active Record. Магические методы. Человек с опытом конкретного фреймворка тоже иногда тратит час на вопрос «кто вообще вызывает этот код?». У агента нет многолетней мышечной памяти вашего проекта. Я не призываю отказаться от магии фреймворка полностью. Но критические связи лучше делать наблюдаемыми: документацией, явными интерфейсами, интеграционными тестами и понятными точками входа.
7. Документация системы внутри репозитория создаёт долговременную память
Я за Documentation as code не потому, что Markdown красивее Confluence, а потому, что документация рядом с кодом:
- версионируется вместе с ним;
- попадает в тот же пул-реквест;
- доступна код-агенту;
- может иметь ссылки на конкретные модули и ADR;
- проще включается в ревью.
Внешняя вики тоже может быть полезна. Но если у агента нет к ней доступа через инструменты, для него этой части памяти просто не существует.
Что документировать на уровне системы
Минимальный набор, который я бы хотел видеть в большом проекте:
docs/
architecture/
overview.md
modules.md
data-flow.md
adr/
integrations/
operations/
testing.md
development.md
Не обязательно именно так. Важнее содержание:
- назначение продукта;
- основные бизнес-процессы;
- архитектурные слои;
- модули и ответственность;
- внешние интеграции;
- потоки данных;
- точки входа;
- известные ограничения;
- технический долг, который влияет на решения.
AGENTS.md должен быть навигатором, а не энциклопедией
Это одна из главных практических идей статьи. Корневой агент-файл должен быстро отвечать:
- Что это за проект?
- Как его запустить?
- Как проверить изменение?
- Где читать архитектуру?
- Какие правила нельзя нарушать?
- Где лежат локальные инструкции?
Всё остальное — по ссылкам. Кстати, такой иерархический подход уже появился и в инструментах. GitHub Copilot coding agent поддерживает корневой и вложенные AGENTS.md, а OpenAI Codex учитывает рамки инструкций по дереву каталогов. Это логично: правила большого монорепозитория редко одинаковы для фронтенда, биллинга и инфраструктуры.
8. TODO-лист и бэклог показывают предполагаемое будущее системы
Это самый спорный пункт списка. Почему вообще давать AI планы, если источник истины — текущий код? Потому что архитектурное решение часто зависит от направления движения. Допустим, агент видит дублирование между двумя модулями и решает вынести общую абстракцию. Локально решение красивое. Но команда уже решила, что через две недели один из модулей будет выделен в отдельный сервис. Новая абстракция только усилит связь, которую планировали разорвать. Бэклог в таком случае даёт стратегический контекст.
Что полезно хранить рядом с кодом
Не вся Jira. Мне полезны вещи, которые меняют сегодняшние инженерные решения:
- текущие крупные изменения;
- запланированные миграции;
- известный технический долг;
- устаревшие части;
- решения «пока не трогаем»;
- отклонённые архитектурные идеи и причина отказа.
При этом надо явно разделять решение, план и гипотезу. Иначе агент может принять сырой мозговой штурм за требование. Например:
## Status
Decision: Orders remain in the monolith in 2026.
Plan: extract Notifications after Q4 load testing.
Hypothesis: Billing may move to a separate service later; no decision yet.
Устаревший бэклог опасен
Старая стратегия иногда хуже отсутствующей. Если документ говорит «в следующем квартале мигрируем на Kafka», а команда три года живёт на RabbitMQ и больше никуда не собирается, агент может начать оптимизировать систему под вымышленное будущее. Стратегический контекст должен иметь владельца, статус и дату пересмотра.
9. Правила линтеров превращают требования в автоматическую обратную связь
Я стараюсь переносить в автоматические проверки всё, что можно проверить автоматически. Не из любви к красному CI, а потому что человеческая договорённость слишком легко забывается, а LLM-договорённость ещё и недетерминирована. Что можно проверять:
- форматирование;
- запрещённые зависимости;
- границы слоёв;
- цикломатическую сложность;
- правила типизации;
- nullable-контракты;
- шаблоны безопасности;
- именование;
- запрещённые API;
- наличие определённых аннотаций;
- совместимость публичного API.
Особенно ценны собственные архитектурные правила. Вместо:
Domain layer must not depend on Infrastructure.
лучше иметь ещё и тест:
Architecture::expect('App\\Domain')
->notToDependOn('App\\Infrastructure');
Теперь агент может ошибиться, но система сразу объяснит ошибку.
Какими должны быть сообщения линтера для AI
Хорошее сообщение должно подсказывать действие. Плохо:
Architecture violation.
Лучше:
Billing\Domain must not depend on Billing\Infrastructure.
Move the interface to Domain or Application and keep the implementation in Infrastructure.
See docs/architecture/dependencies.md.
Это уже почти встроенная подсказка для исправления.
10. Руководство по стилю задаёт единый язык изменений
Последний пункт кажется самым скучным, пока не начинаешь смотреть сотни диффов, сгенерированных AI. Модель легко подстраивается под локальные паттерны, если они действительно едины. Но если половина проекта использует фабрики, половина — конструкторы, ошибки где-то исключения, где-то объекты результата, где-то null, агенту приходится выбирать самому. А значит — добавлять ещё одну вариацию. Руководство по стилю нужно не для войны про количество пробелов. Важны решения, которые влияют на структуру:
- именование классов и методов;
- структура модуля;
- обработка ошибок;
- исключения;
- логирование;
- работа с транзакциями;
- соглашения по тестам;
- документация;
- DTO / объекты-значения;
- правила зависимостей.
И снова: то, что можно проверять, лучше проверять автоматически. Руководство по стилю должно объяснять смысл и исключения, а форматтер/линтеры — механически обеспечивать форму.
Пять слоёв контекста agent-ready кодовой базы
После всех этих практик я стал смотреть на репозиторий как на пять слоёв памяти.
Исторический слой: почему система стала такой
Сюда попадают Git, пул-реквесты, ADR, ссылки на инциденты. Этот слой отвечает на вопрос: почему решение существует. Без него агент особенно легко «исправляет странность», которая на самом деле является защитой от реального случая из продакшена.
Семантический слой: что означает код
DDD, именование, границы модулей, документация, схемы. Он отвечает: что это за сущности и какую роль они играют в бизнесе.
Поведенческий слой: что система обязана делать
Тесты, сценарии приёмки, контракты, примеры. Он отвечает: какое наблюдаемое поведение нельзя случайно сломать.
Стратегический слой: куда система должна двигаться
Бэклог, планы миграций, техническая стратегия, список устаревающих частей. Он отвечает: какие сегодняшние решения совместимы с ближайшим будущим.
Нормативный слой: какие изменения допустимы
Линтеры, статический анализ, CI, полномочия, границы безопасности, инструкции для агента. Он отвечает: что агенту разрешено сделать и какие ограничения должны остаться истинными. Когда все пять слоёв доступны и согласованы, агенту гораздо меньше приходится угадывать.
Чего не хватает даже хорошо написанному коду
Хорошая архитектура, понятные названия и тесты уже дают много. Но для реального агентского рабочего процесса этого недостаточно. Агенту надо не просто читать проект, а практически с ним работать.
AGENTS.md как точка входа для AI-агента
В корневом AGENTS.md я бы держал только действительно общие вещи. Например:
# Project
Payment platform monolith.
PHP 8.2, Symfony, PostgreSQL, RabbitMQ.
## Start here
- Architecture: `docs/architecture/overview.md`
- Module map: `docs/architecture/modules.md`
- Testing: `docs/testing.md`
- ADR: `docs/adr/`
## Commands
- Install: `make install`
- Unit tests: `make test-unit`
- Full verification: `make verify`
## Rules
- Do not change public API contracts without explicit approval.
- Do not modify production infrastructure.
- Do not access real secrets or production data.
- Keep changes within the requested bounded context unless a dependency requires otherwise.
- For non-obvious legacy behavior, inspect Git history before changing it.
## Local instructions
Nested `AGENTS.md` files may define stricter module-specific rules.
Главная задача такого файла — сократить стоимость первого шага. Агент не должен десять минут выяснять, чем запустить тесты и где лежит архитектура.
Что лучше вынести в отдельные документы
Подробное описание домена, список всех интеграционных контрактов, десятки ADR, разбор типичных проблем и соглашения по тестам лучше хранить отдельно. Иначе корневые инструкции быстро разрастутся. Формат AGENTS.md уже используется как минимум в OpenAI Codex и GitHub Copilot coding agent. У других инструментов есть собственные варианты вроде CLAUDE.md, но сама идея важнее имени файла: репозиторий должен иметь компактную машинно-читаемую точку входа.
Архитектурные решения в формате ADR
Код почти всегда показывает выбранное решение. Намного хуже он показывает отвергнутые альтернативы. Допустим, проект использует outbox вместо прямой публикации события. Агент видит дополнительную таблицу, воркер и сложность и может решить «упростить» систему. ADR объяснит, что прямую публикацию уже пробовали, но получили рассинхронизацию между фиксацией транзакции и брокером сообщений. Минимальный формат может быть коротким:
# ADR-0042: Use transactional outbox for payment events
Status: accepted
Date: 2026-02-14
## Context
Payment state and emitted events must not diverge when RabbitMQ is unavailable.
## Decision
Persist events in the same database transaction and publish them asynchronously.
## Alternatives rejected
Direct publish after commit: creates an unrecoverable gap when broker publishing fails.
## Consequences
Additional outbox table and worker are intentional complexity.
Фраза intentional complexity здесь полезнее десяти комментариев в коде. Она сразу защищает архитектуру от «улучшения».
Одна команда для запуска всех проверок
Если агент после изменения должен помнить семь команд, он когда-нибудь забудет восьмую. Я предпочитаю иметь единую точку входа:
make verify
или:
just verify
или любой аналог в экосистеме проекта. Внутри уже могут запускаться:
formatter check
lint
static analysis
unit tests
integration tests
architecture tests
schema validation
contract tests
Не всё обязательно гонять на каждом маленьком изменении. Можно сделать verify-fast и verify-full. Но агент должен понимать разницу, а CI — оставаться финальным авторитетом.
Воспроизводимое локальное окружение
Здесь AI делает старую проблему видимой. Если новый разработчик получает README на пять страниц с фразами «если не поднялось, спроси у Васи», агент тоже не справится стабильно. Воспроизводимость означает, что настройка описана и по возможности автоматизирована:
- зафиксированные версии зависимостей;
- контейнер или dev-окружение;
- настройка миграций;
- тестовая база данных;
- фикстуры;
- предсказуемые зависимости от сервисов;
- документированные переменные окружения;
- отсутствие скрытых ручных шагов.
По этой причине мне нравится, что SWE-bench со временем перешёл на контейнерную обвязку оценки: реальные задачи разработки невозможно честно оценивать, если окружение само по себе невоспроизводимо. В реальных проектах это работает так же.
Явные контракты и схемы данных
Чем больше поведения описано типами и схемами, тем меньше приходится объяснять естественным языком. Полезны:
- типизированные интерфейсы;
- OpenAPI;
- JSON Schema;
- protobuf;
- схема базы данных;
- контракты событий;
- сгенерированные клиенты;
- валидация на границе.
Если API принимает status: string, модель должна искать допустимые значения. Если есть enum или схема:
status:
type: string
enum:
- pending
- paid
- failed
часть контекста становится исполняемой.
Наблюдаемость, доступная агенту
Если задача — исправить баг в рантайме, одних юнит-тестов иногда мало. Агенту полезно уметь:
- запустить приложение локально;
- воспроизвести запрос;
- прочитать структурированные логи;
- увидеть трассировку;
- проверить метрики в тестовом окружении;
- получить детерминированный скрипт воспроизведения.
Я подчёркиваю «тестовое окружение». Давать код-агенту свободный доступ к продакшену ради удобства — плохой компромисс. Наблюдаемость должна помогать проверять результат, а не увеличивать зону риска.
Границы полномочий и безопасность
Чем сильнее агент, тем важнее этот раздел. Нужно определить не только, что он умеет, но и что ему технически разрешено. Я бы разделял действия хотя бы по риску. Низкий риск: чтение репозитория, локальный поиск, запуск юнит-тестов, изменение кода в заданных рамках. Средний риск: обновление зависимостей, миграции, доступ к сети, сгенерированный код, конфигурация CI. Высокий риск: продакшен, секреты, разрушительные команды, реальные данные клиентов, IAM, биллинговая инфраструктура. Для высокорисковых действий запрета на естественном языке недостаточно. Нужна песочница, сетевые политики, ограниченные учётные данные и подтверждение человеком.
В 2026 году это уже не теоретический вопрос. В описании внутренних практик безопасного использования Codex OpenAI отдельно говорит об ограниченном исполнении, сетевых политиках, управляемой конфигурации и телеметрии. Смысл универсален для любого код-агента: полномочия должны соответствовать задаче.
Какая архитектура удобна AI-агентам
Локальность поведения
Это главное свойство. Если открыть сценарий использования и рядом увидеть его доменные объекты, контракты и тесты, задача становится понятной быстрее. Если поведение размазано по глобальным хукам и общим хелперам, рассуждение становится длиннее. Локальность не означает «всё в одном файле». Она означает, что связанные понятия находятся в предсказуемой близости и имеют явные связи.
Высокая связность внутри модуля и низкая между модулями
Старая формула связности и связанности становится практичной метрикой для AI. Высокая связность помогает собрать полноценный контекст внутри ограниченного контекста. Низкая связанность уменьшает количество внешних файлов, которые надо прочитать до изменения. В идеале агент может сказать: «задача относится к Subscription, мне достаточно этого модуля и двух публичных контрактов соседних модулей».
Явные зависимости
Внедрение через конструктор, интерфейсы, импорты и явные контракты сообщений обычно лучше скрытых локаторов сервисов, глобальных переменных и магического разрешения зависимостей. Дело не в том, что агент не понимает DI-контейнер, — понимает. Но явная зависимость видна из кода сразу, а скрытую приходится искать в конфигурации.
Стабильные интерфейсы
Если каждый модуль имеет небольшую публичную поверхность, агенту легче понять, что является контрактом, а что деталью реализации. Это ещё и хорошая защита от расползания рамок. Изменение реализации внутри модуля не должно требовать переписывания половины проекта.
Контролируемый размер области изменения
Я бы ввёл внутреннюю метрику: сколько файлов в среднем приходится открыть агенту до первого корректного плана. Она не идеальна, но заставляет посмотреть на архитектуру с интересной стороны. Если обычное исправление ошибки постоянно требует изучения пятидесяти файлов, это сигнал не только про готовность к AI.
Модульный монолит как удобная стартовая архитектура
Я не считаю микросервисы автоматически более agent-ready. Часто наоборот. Хорошо организованный модульный монолит даёт сильную комбинацию:
- одна кодовая база;
- единая локальная среда;
- простые транзакции;
- быстрый поиск;
- при этом явные доменные границы.
Для код-агента это удобная территория: можно исследовать всю систему без распределённого операционного контекста, но при этом работать локально внутри модуля.
Микросервисы и проблема распределённого контекста
В микросервисах бизнес-сценарий может проходить через пять репозиториев, брокер сообщений, API-шлюз и общий репозиторий схем. Сам по себе каждый сервис маленький. Но сквозной контекст распределён. Тогда agent-ready подход должен существовать уже на уровне экосистемы:
- каталог сервисов;
- контракты;
- владение;
- карта архитектуры;
- версионированные схемы;
- распределённая трассировка;
- ссылки между репозиториями;
- понятный способ локального интеграционного тестирования.
Микросервис размером 2000 строк может быть сложнее для агента, чем монолит на миллион строк, если для понимания одной операции надо собрать пять несвязанных источников.
Почему архитектурная простота не равна примитивности
Простая архитектура — это не «все классы в одной папке». Это архитектура, у которой причинно-следственные связи можно восстановить без большого количества скрытых предположений. Иногда дополнительный объект-значение делает систему проще. Иногда отдельный адаптер делает её проще. Иногда outbox добавляет код, но делает надёжность понятнее. Количество файлов — плохая метрика простоты.
Как проверить, что границы существуют не только на диаграмме
Попробуйте их нарушить. Если Billing\Domain технически может импортировать UserInterface\Controller и никто этого не заметит, граница существует только в презентации. Нужны архитектурные тесты, правила зависимостей, статический анализ, границы пакетов или хотя бы CI-проверки. Диаграмма показывает намерение, а автоматическое правило доказывает существование границы.
Как подготовить легаси-проект к AI-агентам
Самая опасная идея в работе с легаси звучит примерно так: «раз AI теперь умеет много писать, давайте сначала попросим его всё нормально переписать». Я бы делал наоборот. Легаси редко сложен потому, что там старый синтаксис. Он сложен потому, что в коде накопились неявные контракты, исторические исключения, интеграции, странные данные и бизнес-поведение, которое никто полностью не описывал. Большое переписывание уничтожает именно тот контекст, который мы ещё не успели понять. Поэтому сначала я бы делал легаси наблюдаемым и проверяемым, а уже потом увеличивал автономность AI.
Шаг 1. Сделать проект воспроизводимым
Первый шаг не про LLM. Нужно добиться, чтобы новое окружение можно было поднять по документации и автоматизированным командам. Если проект запускается только на ноутбуке двух разработчиков, агенту пока нечего там делать автономно. Проверяем:
- как устанавливаются зависимости;
- как поднимается база данных;
- как применяются миграции;
- как создаются тестовые данные;
- как запускаются сервисы;
- какие переменные окружения обязательны;
- какие версии среды выполнения нужны.
Я бы начал с этого даже в проекте без AI. Agent-ready здесь дополнительная мотивация закрыть старый операционный долг.
Шаг 2. Зафиксировать текущее поведение характеризационными тестами
В легаси часто невозможно сразу сказать, правильный код или нет. Но можно зафиксировать то, что он делает сейчас. Характеризационный тест не утверждает, что поведение идеально. Он говорит: до изменения система в этом сценарии ведёт себя так. Это страховочная сетка перед рефакторингом. Если агенту поручить очистить старый метод на 400 строк без тестов, он может сделать код значительно красивее и одновременно изменить десятилетний пограничный случай. С характеризационными тестами хотя бы появляется сигнал. Важно не обманывать себя покрытием. Лучше десять тестов на ключевые бизнес-сценарии, чем тысяча снапшот-проверок, которые ничего не защищают.
Шаг 3. Найти основные бизнес-инварианты
Следующий шаг — понять, что системе запрещено нарушать. Например:
- суммы в леджере должны сходиться;
- оплаченный счёт нельзя удалить;
- номер заказа уникален в пределах тенанта;
- повторный вебхук должен быть идемпотентным;
- пользователь не может видеть чужой аккаунт;
- выплату после отправки провайдеру нельзя изменить локально.
Именно такие правила стоит поднимать из неявного кода в явные тесты, объекты-значения, доменные методы и документацию. По сути, мы постепенно переводим знания из голов и случайных if в машиночитаемую форму.
Шаг 4. Описать карту модулей и интеграций
Не надо начинать с идеальной C4-модели на сто страниц. Мне хватит одной карты:
HTTP API
↓
Orders ─────→ Billing ─────→ ProviderX
│ │
│ └──────────→ Ledger
↓
Notifications ─────────────→ Email/SMS
И рядом несколько предложений про ответственность каждого блока. Цель — дать агенту возможность быстро ответить: «если меняется выплата, где потенциально лежит связанное поведение?»
Шаг 5. Выделить безопасные области для первых задач
Не начинайте с ядра банковской логики или продакшен-миграций. Первые задачи лучше выбирать там, где:
- рамки малы;
- есть тесты;
- легко проверить результат;
- нет разрушительных побочных эффектов;
- нет чувствительных данных;
- откат простой.
Например: рефакторинг локального парсера, добавление валидации, расширение юнит-тестов, исправление понятного бага в изолированном модуле. Так команда одновременно учится ставить задачи агенту и находит слабые места репозитория.
Шаг 6. Добавить автоматические проверки
Каждая повторяющаяся ошибка AI — кандидат на автоматизацию. Агент постоянно забывает strict_types? Проверка. Создаёт зависимость из Domain в Infrastructure? Архитектурное правило. Пишет небезопасный SQL? Статический анализ или линтер безопасности. Не обновляет OpenAPI после DTO? Проверка контракта. Такой подход мне нравится тем, что плохой результат одной итерации постепенно улучшает саму обвязку.
Шаг 7. Ввести инструкции и границы полномочий
Только после появления базовой проверяемости имеет смысл серьёзно настраивать AGENTS.md, локальные инструкции и полномочия. Инструкция без проверки — просьба. Инструкция плюс тест — процесс. Инструкция плюс технически ограниченное полномочие — граница.
Шаг 8. Постепенно улучшать архитектурную локальность
Не надо устраивать «DDD transformation quarter». Используйте реальные изменения как точки улучшения. Тронули повтор платежа — выделили объект-значение и перенесли инвариант. Работаете с notifications — описали публичный контракт модуля. Меняете отчёты — отделили модель чтения. Так готовность к агентам растёт вместе с обычной разработкой, а не отдельным многомесячным проектом без бизнес-результата.
Шаг 9. Накапливать историю решений
После каждого серьёзного изменения должен оставаться след:
- атомарные коммиты;
- нормальное описание PR;
- обновлённый ADR, если решение архитектурное;
- тест, если появился новый инвариант;
- документация, если поведение неочевидно.
Мы не просто закрываем задачу, а добавляем контекст для следующего разработчика и следующего агента.
Шаг 10. Увеличивать автономность только после появления обратной связи
Сначала агент предлагает план. Потом делает маленький патч. Потом запускает проверки. Потом можно разрешить ему полностью реализовывать ограниченную задачу. Потом — создавать пул-реквест. И только после накопления статистики имеет смысл расширять класс задач. Автономность должна быть следствием проверяемости, а не веры в новую модель.
Как должна выглядеть задача для AI-агента
Хороший репозиторий не отменяет хорошую постановку задачи. Более того: если человек не может коротко объяснить цель изменения, agent-ready codebase не спасёт. Мне нравится шаблон задачи, где явно разделены намерение, рамки и способ проверки.
Цель изменения
Сначала одно предложение о результате:
Allow customers to retry a failed card payment while the original provider session is still active.
Не «рефакторнуть payment service». Не «пофиксить retry». Именно наблюдаемая цель.
Бизнес-контекст
Зачем это нужно и какое правило за этим стоит:
ProviderX keeps a failed payment session active for 30 minutes.
During this period the same transaction may be retried without creating a new external payment.
After expiration retry must be rejected to avoid duplicate charges.
Иногда эти три предложения экономят агенту двадцать поисковых запросов.
Границы задачи
Что относится к рамкам:
Scope:
- Billing/PaymentRetry use case
- ProviderX adapter
- related unit and integration tests
Критерии приёмки
Что должно быть истинно после изменения:
- failed payment can be retried while provider session is active;
- expired session returns RetryNotAllowed;
- retry reuses original provider transaction;
- existing idempotency behavior remains unchanged.
Нефункциональные требования
Если важны производительность, безопасность, обратная совместимость, аудит — пишем явно.
- no public API changes;
- no new database queries in the hot path;
- existing audit event names must remain unchanged.
Что изменять запрещено
Полезный блок.
Do not:
- change Payment status model;
- modify database schema;
- refactor unrelated ProviderX code;
- update dependencies.
Он резко уменьшает творческое расползание рамок.
Связанные модули и документация
Не надо заранее давать агенту двадцать файлов, если он умеет искать. Но полезно обозначить отправные точки:
Start with:
- `src/Billing/PaymentRetry/`
- `src/Billing/README.md`
- `docs/adr/0042-payment-idempotency.md`
Способ проверки результата
Verification:
1. `make test-billing`
2. `make static-analysis`
3. `make architecture-test`
4. `make verify`
Условия остановки и эскалации человеку
Это часть задачи, которую часто забывают.
Stop and ask for review if:
- public API must change;
- current tests contradict the task;
- retry requires a database migration;
- ProviderX behavior cannot be reproduced locally.
Так агент получает право не угадывать.
Почему хорошая постановка задачи важнее длинного промпта
Длинный промпт часто состоит из попыток компенсировать плохую постановку большим количеством слов. Хорошая задача наоборот уменьшает неопределённость. Цель. Контекст. Рамки. Ограничения. Критерии приёмки. Способ проверки. Всё остальное агент способен собрать из agent-ready репозитория.
Полный цикл работы AI-агента с подготовленной кодовой базой
Когда все элементы собраны вместе, мне нравится следующий рабочий процесс.
1. Анализ задачи и поиск связанного контекста
Агент не пишет код сразу. Сначала определяет домен, точки входа и связанные модули.
2. Изучение текущего поведения
Читает продакшен код и тесты. Если поведение непонятно — воспроизводит локально.
3. Обращение к документации и Git-истории
Если видит странное ограничение, ищет ADR, документацию, git blame, прошлые коммиты.
4. Построение плана изменения
План должен быть небольшим и привязанным к конкретным файлам и контрактам. Например:
1. Add active-session invariant to PaymentRetryPolicy.
2. Reuse existing ProviderTransactionId in ProviderX adapter.
3. Add expired-session unit test.
4. Extend ProviderX integration test.
5. Run Billing verification.
5. Проверка плана человеком
Для задач низкого риска этот этап можно пропускать. Для архитектурных и чувствительных изменений я бы пока оставлял.
6. Написание или обновление тестов
Не обязательно догматически тест-first. Важнее, чтобы поведение было зафиксировано независимо от реализации.
7. Реализация минимального изменения
Именно минимального: AI легко генерирует «заодно улучшил». Я обычно хочу противоположного: минимальный целостный дифф.
8. Запуск автоматических проверок
Сначала целевые тесты, затем полную проверку, если стоимость позволяет.
9. Самопроверка полученного диффа
Агент должен посмотреть на собственный дифф как ревьюер:
- всё ли относится к задаче;
- нет ли случайного форматирования;
- не поменялся ли публичный API;
- не появились ли новые зависимости;
- соответствует ли код стилю;
- обновлены ли документация/тесты.
10. Ревью человеком
Человек проверяет уже не каждую скобку, а намерение, архитектуру, безопасность, пограничные случаи и качество доказательства корректности. Чем дешевле становится генерация, тем дороже относительно неё становится ревью.
11. Создание атомарного коммита
Сообщение коммита должно объяснять изменение и причину. Если задача естественно делится на несколько независимых шагов, история сохраняет эту структуру.
12. Обновление документации и бэклога
Если изменилось правило — документация. Если принято решение — ADR. Если закрыт технический долг — бэклог.
13. Превращение повторяющейся ошибки агента в новое правило
Это финальный цикл обратной связи. Если на ревью мы третий раз пишем одно и то же замечание AI, проблема уже не только в AI. Значит, правило недостаточно выражено в репозитории или обвязке. Добавляем линтер, тест, инструкцию или документацию. В итоге кодовая база постепенно становится лучше обучена не в смысле дообучения модели, а в смысле качества среды, в которой модель работает.
Что AI-агент должен проверять самостоятельно
Перед тем как отдать результат человеку, я бы заставлял агента проходить собственный чек-лист.
Соответствие задачи и фактического диффа
Каждый изменённый файл должен иметь отношение к задаче. Если появилась случайная перестановка импортов в ста файлах — убрать. Если агент начал рефакторинг соседнего модуля «для чистоты» — вернуть рамки.
Прохождение тестов
Не просто написать тесты, а запустить их. И отдельно сообщить, что именно запускалось. «Тесты проходят» без команды и результата — слабое доказательство.
Результаты линтеров и статического анализа
Ошибки инструментов — это входные данные для следующей итерации исправления, а не повод закончить задачу со словами «вроде всё должно работать».
Соблюдение архитектурных границ
Проверить правила зависимостей и появление новых межмодульных импортов.
Изменения публичных контрактов
API, события, схемы, публичные интерфейсы, CLI, контракты базы данных. Иногда маленькая правка типа имени поля создаёт гораздо больший радиус поражения, чем 500 строк внутреннего рефакторинга.
Обратная совместимость
Особенно в общих библиотеках, публичных API и распределённых системах.
Безопасность и работа с данными
Права доступа, валидация, секреты, логи с персональными данными, SQL, shell-команды, десериализация, SSRF и всё, что относится к конкретному проекту.
Соответствие документации новому поведению
Если код говорит одно, тест другое, а README третье — задача не закончена.
Отсутствие случайных изменений за пределами задачи
Один из самых полезных финальных вопросов:
Если убрать всё, без чего критерии приёмки всё ещё выполняются, что останется в диффе?
Это дисциплинирует и человека, и AI.
Типичные ошибки при подготовке проекта
Попытка поместить весь контекст в один AGENTS.md
Самая очевидная ошибка. Файл растёт. Каждая команда добавляет туда правила. Через полгода там архитектура, рабочий процесс Git, именование, история инцидентов, список сервисов, способы деплоя и 80 запретов. В результате корневой контекст становится шумом. Лучше маленький указатель и постепенное раскрытие.
Избыточная документация, повторяющая код
Документация ради документации быстро устаревает. Если README перечисляет все методы класса вручную, он почти гарантированно отстанет от реализации. Документируйте намерение, понятия, границы, инварианты, решения и рабочие процессы — то, что невыгодно или невозможно извлекать из кода каждый раз.
Противоречащие друг другу правила
В корневом файле написано «все доменные ошибки — исключения». В README модуля — «возвращаем Result». В старом руководстве по стилю — null. А код использует всё сразу. AI выберет один вариант. Возможно, не тот. Нужна иерархия авторитетности: исполняемые проверки > актуальные локальные инструкции > системная документация > историческая документация. И лучше прямо это описать.
Устаревшие планы и бэклог
План без статуса — потенциальная дезинформация. Добавляйте status, owner, last reviewed.
Тесты, которые проверяют реализацию вместо поведения
Если рефакторинг ломает половину тестов при неизменном наблюдаемом поведении, эти тесты будут мешать и человеку, и агенту. AI начнёт сохранять случайные внутренние детали, потому что набор тестов объявляет их контрактом.
Генерация тестов тем же агентом без независимой проверки
Если агент неправильно понял требование, он может написать реализацию и тест, которые согласованы друг с другом и одновременно оба неверны. Зелёный CI тогда ничего не доказывает про намерение. Поэтому критические приёмочные тесты, бизнес-инварианты и проверки безопасности должны иметь независимый источник: исходное требование, существующий набор тестов, ревью человеком, контракт или внешний источник истины.
Слишком маленькие методы и потеря целостного сценария
Мы уже обсуждали это в SRP. Не превращайте читаемость в квест по графу вызовов. AI хорошо ходит по ссылкам, но каждый новый переход — дополнительный шанс потерять смысл.
Формальное DDD без выраженной доменной модели
Папки Domain/Application/Infrastructure сами по себе ничего не дают. Если в Domain лежат DataManager, CommonService и DTO из фреймворка, агент не получит никакой семантической пользы. DDD работает, когда язык бизнеса действительно выражен в коде.
Архитектурные правила, существующие только в документации
«Не импортировать X из Y» должно по возможности проверяться. Иначе это совет, а не архитектурная граница.
Автоматическое доверие зелёному CI
CI может быть зелёным, потому что нужного теста просто нет. Или потому что утверждение в тесте проверяет не то. Или потому что агент вместе с кодом случайно ослабил тест. Проверки — это доказательство только в пределах того, что они действительно проверяют.
Предоставление агенту избыточных полномочий
Если задача — исправить юнит-тест, доступ к продакшен-кластеру Kubernetes не делает агента умнее. Принцип минимальных привилегий здесь работает буквально.
Попытка компенсировать слабый проект более дорогой моделью
Иногда это помогает: сильная модель лучше разберётся в хаосе. Но экономика странная: мы постоянно платим дополнительными токенами и рассуждениями за архитектурный долг, который можно убрать один раз. Это как нанять очень умного разработчика и каждый день заставлять его заново выяснять, как запустить тесты.
Как понять, что кодовая база стала удобнее для AI
Я бы не измерял успех количеством сгенерированных строк. Чем зрелее агентский рабочий процесс, тем меньше значения имеет сам объём генерации. Полезнее смотреть на путь от задачи до принятого изменения.
Агент быстрее находит место изменения
Можно измерять время или количество вызовов инструментов до корректного плана.
Агент читает меньше нерелевантных файлов
Если раньше для исправления ошибки открывалось 60 файлов, а после описания границ модулей — 15, репозиторий стал навигационно лучше.
Уменьшается количество уточняющих итераций
Не потому, что агенту запрещили задавать вопросы. А потому, что ответы уже лежат в контексте проекта.
Снижается доля изменений за пределами задачи
Соблюдение рамок — очень полезная метрика.
Реже нарушаются архитектурные правила
Особенно если нарушения ловятся до ревью человеком.
Больше ошибок обнаруживается до ревью человеком
Идеальное ревью получает дифф, который уже прошёл компиляцию, тесты, линтер, статический анализ и самопроверку.
Уменьшается время проверки пул-реквеста
Это уже прямой бизнес-эффект. Если агент генерирует в два раза быстрее, а ревью занимает втрое дольше, мы ничего не ускорили.
Снижается количество откатов и регрессий
Финальная метрика всегда продакшен. Быстрое слияние с ростом инцидентов — не прирост производительности.
Почему количество сгенерированных строк не является метрикой успеха
Строки — выход генератора. Ценность — безопасное изменение поведения системы. Иногда лучший результат AI — удалить 300 строк. Иногда — найти существующую функцию и не написать новую. Иногда — остановиться и сказать, что критерии приёмки противоречат текущему контракту. Поэтому я бы измерял принятые изменения относительно затрат на ревью человеком и риска для продакшена, а не объём генерации.
Модель зрелости agent-ready кодовой базы
Чтобы не превращать подготовку проекта в бинарный чекбокс «готов / не готов», мне удобнее думать уровнями. Не обязательно проходить их формально и не обязательно каждому проекту доходить до максимума. Это скорее способ понять, какое следующее улучшение даст наибольший эффект.
Уровень 0. Непрозрачный проект
Проект запускается только у нескольких разработчиков. Значительная часть знаний находится в головах команды. Сборка и тесты зависят от локальной среды. Документация либо отсутствует, либо явно устарела. Архитектурные границы известны «по договорённости». AI в таком проекте можно использовать как автодополнение или локального помощника. Давать ему автономную задачу на уровне репозитория я бы не спешил. Главная цель этого уровня — не добавить AGENTS.md, а убрать магию из базового рабочего процесса разработки.
Уровень 1. Читаемый агентом
Агент способен открыть репозиторий, установить зависимости, найти основные точки входа и прочитать код. Есть:
- рабочий README;
- базовая структура проекта;
- команды настройки;
- хотя бы минимальная документация;
- понятная среда выполнения.
На этом уровне AI уже может отвечать на вопросы по кодовой базе и делать небольшие локальные правки.
Уровень 2. Навигируемый агентом
Проект не только читается, но и помогает понять, куда идти. Есть:
- карта модулей;
- локальные README и инструкции для агента;
- понятное именование;
- указатель документов;
- явные точки входа;
- ссылки на архитектурные решения;
- предсказуемое расположение тестов.
Агент тратит меньше времени на исследование и реже собирает неправильный контекст.
Уровень 3. Проверяемый агентом
Это переломный уровень. Агент может не только написать патч, но и самостоятельно получить качественную обратную связь:
- тесты;
- статический анализ;
- линтер;
- проверки типов;
- воспроизводимое тестовое окружение;
- интеграционные проверки;
- одна понятная команда проверки.
С этого момента можно всерьёз говорить о делегированных задачах, потому что появляется цикл обратной связи.
Уровень 4. Ограниченный для агента
Архитектурные и операционные границы начинают исполняться технически. Например:
- архитектурные тесты запрещают зависимости;
- CI проверяет контракты;
- песочница ограничивает файловую систему и сеть;
- секреты недоступны;
- разрушительные действия требуют подтверждения;
- локальные инструкции применяются к конкретным модулям.
Агент не просто знает правила. Ему становится трудно случайно их нарушить.
Уровень 5. Работоспособный для агента
Агент способен взять хорошо описанную ограниченную задачу, исследовать контекст, предложить план, изменить код, обновить тесты и документацию, выполнить проверку и сформировать пул-реквест. Человек остаётся ревьюером и владельцем решения. Это уже полноценный боевой рабочий процесс, но не «автономный разработчик без людей». Скорее новый исполнитель внутри управляемого инженерного процесса.
Уровень 6. Адаптивный
Самый интересный уровень — когда процесс умеет улучшать собственную среду. Повторяющееся замечание на ревью превращается в правило линтера. Регрессия в продакшене — в характеризационный тест. Странное архитектурное решение — в ADR. Ошибка навигации — в карту модулей. Неоднозначная инструкция — в локальное правило. Опыт работы агента постепенно преобразуется в новую структуру репозитория и обвязки. Здесь находится один из самых сильных эффектов AI в инженерии. Мы перестаём каждый раз чинить конкретный результат и начинаем улучшать систему, которая этот результат производит.
Чек-лист готовности кодовой базы к AI-агентам
Ниже чек-лист, который можно буквально пройти по существующему проекту. Не обязательно закрывать все пункты перед первым использованием AI. Я бы скорее отмечал слабые места и улучшал их в порядке риска и частоты изменений.
История и управление изменениями
- [ ] Коммиты имеют понятные рамки и причину изменения.
- [ ] История Git не состоит преимущественно из
fix,wip,misc. - [ ] По
git blameможно выйти на осмысленный коммит или PR. - [ ] Крупные изменения разбиваются на логические шаги.
- [ ] Неочевидные изменения ссылаются на issue, incident или ADR.
- [ ] Команда понимает, когда squash сохраняет смысл, а когда уничтожает полезную историю.
Архитектура и доменная модель
- [ ] Основные модули явно названы.
- [ ] Ответственность каждого модуля можно объяснить несколькими предложениями.
- [ ] Бизнес-терминология совпадает между задачами, кодом и документацией.
- [ ] Критические инварианты выражены в доменном коде или тестах.
- [ ] Зависимости между слоями понятны.
- [ ] Критические архитектурные границы проверяются автоматически.
- [ ] Публичная поверхность модулей отделена от деталей реализации.
- [ ] Нет большого объёма необъяснимой магии фреймворка на критических путях.
Документация
- [ ] В репозитории есть актуальная точка входа для разработчика.
- [ ] Есть карта архитектуры или модулей.
- [ ] Документация хранится рядом с кодом или доступна агенту через инструменты.
- [ ] Значимые решения фиксируются в ADR или эквивалентном формате.
- [ ] Документация объясняет причины, а не просто повторяет реализацию.
- [ ] У документов есть владелец и статус там, где информация быстро устаревает.
- [ ] Корневые инструкции компактны и ссылаются на более подробные документы.
- [ ] Локальные правила находятся рядом с соответствующим модулем.
Тестирование
- [ ] Ключевые бизнес-сценарии имеют тесты.
- [ ] Поведение легаси зафиксировано характеризационными тестами перед рефакторингом.
- [ ] Тесты читаются как сценарии, а не как набор деталей реализации.
- [ ] Arrange/Act/Assert различимы.
- [ ] Один тест защищает один логический результат.
- [ ] Ключевые критерии приёмки имеют независимую проверку.
- [ ] Тесты можно стабильно запускать локально.
- [ ] Нестабильные тесты не считаются нормой.
- [ ] Падения тестов дают достаточно информации для исправления.
Автоматические проверки
- [ ] Есть форматтер или проверка форматирования.
- [ ] Есть линтер.
- [ ] Есть статический анализ и проверка типов там, где это уместно.
- [ ] Есть архитектурные проверки для важных границ.
- [ ] Проверяются контракты API, событий и схем.
- [ ] Проверки безопасности встроены в CI для критичных классов ошибок.
- [ ] Есть одна команда для основного набора проверок.
- [ ] Ошибки инструментов сформулированы достаточно понятно для действия.
Постановка и хранение задач
- [ ] У задачи есть конкретная цель.
- [ ] Есть бизнес-контекст.
- [ ] Определены рамки.
- [ ] Критерии приёмки проверяемы.
- [ ] Указаны ограничения и то, что не входит в цель.
- [ ] Понятно, какие части системы менять запрещено.
- [ ] Есть отправные точки для сложных задач.
- [ ] Есть условия остановки и эскалации человеку.
- [ ] Бэклог не смешивает решения, планы и гипотезы.
- [ ] Устаревшие планы удаляются или помечаются.
Локальное окружение
- [ ] Настройка воспроизводима с чистого окружения.
- [ ] Версии среды выполнения и зависимостей зафиксированы.
- [ ] Тестовая база данных создаётся автоматически.
- [ ] Фикстуры или стартовые данные доступны без данных из продакшена.
- [ ] Внешние сервисы можно заменить тестовыми дублёрами или локальными аналогами.
- [ ] Нет обязательных скрытых ручных шагов.
- [ ] Агент может запустить нужную часть приложения в песочнице.
Наблюдаемость
- [ ] Логи структурированы и пригодны для локального анализа.
- [ ] Ошибку можно воспроизвести без доступа к продакшену.
- [ ] Для сложных сценариев доступны трассировки или корреляционные идентификаторы.
- [ ] Есть тестовые способы проверить внешние побочные эффекты.
- [ ] Отладка не требует настоящих секретов или данных клиентов.
Безопасность
- [ ] Агент работает по принципу минимальных привилегий.
- [ ] Продакшен учётные данные недоступны по умолчанию.
- [ ] Доступ в сеть ограничен потребностями задачи.
- [ ] Разрушительные команды требуют отдельного подтверждения или технически заблокированы.
- [ ] Чувствительные пути имеют дополнительные правила.
- [ ] Изменения IAM, биллинга, безопасности и продакшен-инфраструктуры требуют ревью человеком.
- [ ] Действия агента можно аудировать.
Ревью человеком и ответственность
- [ ] У каждого влитого изменения всегда есть ответственный человек.
- [ ] Ревьюер видит, какие проверки реально запускал агент.
- [ ] Сгенерированные AI тесты не считаются независимым доказательством сами по себе.
- [ ] В ревью проверяется намерение и рамки, а не только синтаксис.
- [ ] Команда отслеживает регрессии после изменений, сделанных агентом.
- [ ] Повторяющиеся ошибки превращаются в тесты, правила или документацию.
Если по этому списку закрыта примерно половина пунктов, это уже не означает «проект готов на 50%». Разные пункты имеют разный вес. Для финансового ядра отсутствие границ полномочий может быть критичнее идеального руководства по стилю. Для небольшой внутренней утилиты воспроизводимое окружение и тесты дадут почти весь эффект. Поэтому чек-лист — это карта рисков, а не система сертификации.
Частые вопросы
Обязательно ли использовать AGENTS.md
Нет. Название файла — деталь конкретного набора инструментов. Codex и GitHub Copilot coding agent умеют работать с AGENTS.md; другие инструменты используют свои форматы. Важен сам принцип: у агента должна быть компактная на уровне репозитория инструкция с навигацией, командами и границами. Я бы даже не строил архитектуру процесса вокруг одного имени, привязанного к конкретному поставщику. Лучше иметь каноническую документацию и небольшой файл-адаптер, который ссылается на них.
Нужен ли векторный поиск по кодовой базе
Не обязательно. Для маленьких и средних репозиториев хорошего текстового поиска и поиска по символам может быть достаточно. Семантический поиск становится полезнее, когда репозиторий большой, терминология разъезжается или знания разбросаны по множеству файлов. При этом исследования генерации кода на уровне репозитория показывают, что простой поиск по сходству — не предел. Зависимости и структурный контекст могут быть важнее текстовой похожести. Поэтому я бы сначала сделал хорошую структуру и обычную навигацию, а уже потом лечил проблему эмбеддингами.
Может ли AI самостоятельно документировать проект
Может помочь, особенно с первичным черновиком. Но здесь действует та же проблема, что со сгенерированными тестами: AI способен очень убедительно описать то, как он понял систему, а не обязательно то, как система задумана. Полезный рабочий процесс — дать агенту собрать документацию из кода, тестов и Git, затем проверить её владельцем домена и закоммитить как обычное изменение. После этого документ становится частью репозитория и дальше обновляется вместе с кодом.
Какие тесты наиболее полезны код-агентам
Те, которые дают быструю, стабильную и содержательную обратную связь. Для локального доменного изменения это юнит-тесты. Для поведения базы данных и интеграций — интеграционные тесты. Для публичных контрактов — контрактные тесты. Для старого неописанного поведения — характеризационные тесты. Для критичных пользовательских сценариев — небольшое количество сквозных тестов. Не существует одного «удобного для AI вида тестов». Важнее, чтобы тест защищал реальное поведение и его падение объясняло проблему.
Нужно ли документировать каждый класс, метод и тест
Нет. Я бы специально этого не делал. Документировать надо то, где есть информация, неочевидная из кода: бизнес-причина, инвариант, побочный эффект, исключение, историческое ограничение. Если комментарий можно удалить и ничего не потерять — скорее всего, он лишний.
Помогает ли DDD AI-агентам писать код
Я бы не утверждал, что существует универсальное исследование «DDD повышает качество работы код-агента на X процентов». По крайней мере, на этом тезисе я статью не строю. Но инженерная причинность здесь понятна: единый язык уменьшает терминологическую неоднозначность, ограниченные контексты дают рамки, агрегаты локализуют инварианты, объекты-значения делают ограничения явными. Всё это уменьшает объём скрытого контекста. То есть DDD полезен AI по тем же причинам, по которым он полезен людям в сложной предметной области.
Нужно ли менять архитектуру существующего проекта ради AI
Только ради AI — я бы не стал. Если изменение улучшает локальность, тестируемость, явность и онбординг людей, тогда готовность к AI становится дополнительным бонусом. Мне нравится простой фильтр: если практика полезна только агенту и ухудшает проект для человека, надо хорошо подумать, зачем она нужна.
Может ли хорошая документация заменить тесты
Нет. Документация объясняет намерение. Тест даёт исполняемое доказательство конкретного поведения. Можно написать десять раз «повтор запрещён после истечения сессии», но только тест реально поймает случайную правку условия. И наоборот, тест может зафиксировать поведение, но не объяснить, почему именно оно существует. Поэтому эти источники дополняют друг друга.
Может ли AI-агент работать с проектом без чистой Git-истории
Конечно. История Git — дополнительный источник, а не обязательное условие запуска. Но вы теряете исторический слой контекста. Особенно это заметно в легаси с большим количеством странных ограничений. Если история уже плохая, я бы не переписывал прошлое ради AI. Просто начал бы создавать нормальную историю с текущего момента и фиксировать критические старые решения в ADR/тесты по мере касания кода.
Как избежать устаревания документации и бэклог
Привязать обновление к обычному рабочему процессу. Документация меняется в том же PR, что и поведение. ADR получает статус. План имеет дату и владельца. Устаревшая документация удаляется. CI может проверять битые ссылки и схемы. Самое плохое решение — завести большой «AI knowledge base», которую никто из команды не использует. Через полгода это будет качественно оформленная ложь.
Какой объём контекста нужно передавать агенту
Минимальный достаточный: универсального количества токенов нет. Хороший контекст — не самый большой, а тот, после которого агент может принять следующее правильное инженерное решение. Начинаем с задачи и корневых инструкций. Затем документация модуля. Затем код/тесты. Git/ADR — по необходимости. Это и есть постепенное раскрытие.
Когда агенту можно разрешить создавать пул-реквест самостоятельно
Когда класс задач уже многократно проходил стабильный цикл:
- рамки понятны;
- окружение воспроизводимо;
- проверка надёжна;
- полномочия ограничены;
- ревью показывает приемлемое качество;
- регрессии в продакшене не растут.
Сам факт появления новой сильной модели не является причиной расширять полномочия.
Может ли agent-ready проект обходиться без ревью человеком
В отдельных задачах низкого риска — возможно. Например, сгенерированная документация, механическое форматирование или некоторые обновления зависимостей при очень сильной автоматической проверке. Но для изменений бизнес-логики я пока смотрю на ревью человеком как на часть владения результатом. Модель может доказать, что тесты зелёные. Человек должен убедиться, что мы вообще решаем правильную задачу и готовы владеть последствиями.
Agent-ready кодовая база остаётся хорошей кодовой базой для людей
Это главный вывод, к которому я пришёл, пока собирал всё в одну картину. Нам не нужен отдельный «код для AI». Нам нужен проект, в котором смысл меньше зависит от телепатии. Проект, который можно поднять по инструкции. Где названия соответствуют предметной области. Где тесты защищают поведение. Где архитектурные решения имеют причину. Где Git рассказывает историю. Где важное правило либо очевидно из системы типов, либо проверяется автоматически. Где большой план не живёт только в голове одного человека. AI оказался хорошим тестом на качество этой среды.
Человек, пришедший в команду, тоже не знает вашей системы. Ему тоже нужна карта. Ему тоже помогают хорошие имена, тесты, документация и история. Он тоже не хочет три дня выяснять, как локально запустить один воркер. Поэтому подготовка репозитория к агентам одновременно улучшает онбординг, ревью и сопровождение обычной команды.
AI не отменяет инженерные практики, а делает их ценность заметнее
Последние годы иногда создавали впечатление, что сильная модель постепенно отменит часть программной инженерии. Мне пока видится почти противоположное. Чем дешевле становится написать изменение, тем важнее:
- правильно определить границы;
- сохранить намерение;
- проверить результат;
- не допустить случайного расширения рамок;
- понимать последствия.
Код становится дешевле. Инженерное понимание — нет.
Подготовка проекта к агентам одновременно улучшает онбординг команды
Если агент может понять репозиторий за несколько минут благодаря хорошей структуре, новый разработчик тоже быстрее войдёт в систему. Если make verify работает у агента, он работает и у человека. Если ADR объясняет странное решение агенту, он объясняет его ревьюеру через год. Если архитектурный тест не даёт AI нарушить границу, он не даст сделать это и разработчику в пятницу вечером. Agent-ready инженерия не является отдельным направлением рядом с программной инженерией. Это обычная инженерия, к которой добавился очень требовательный новый потребитель контекста.
Автономность начинается не с доверия к модели, а с проверяемости системы
Когда мы говорим «можно ли доверить агенту задачу», вопрос звучит слишком психологически. Доверие плохо масштабируется. Полезнее спросить:
- сможем ли мы ограничить рамки;
- увидим ли неправильное изменение;
- поймают ли тесты нарушение поведения;
- остановит ли архитектурное правило запрещённую зависимость;
- есть ли журнал аудита;
- можно ли безопасно откатить результат.
Чем больше таких механизмов, тем меньше автономность зависит от веры.
Кодовая база должна хранить не только реализацию, но и инженерное намерение
Здесь сходятся почти все части статьи. Реализация без намерения заставляет следующего читателя угадывать. Намерение можно хранить разными способами:
- название доменного объекта;
- тип;
- тест;
- сообщение коммита;
- ADR;
- комментарий;
- правило линтера;
- критерии приёмки задачи.
Ни один формат не решит всё. Но вместе они создают систему, которая способна объяснить не только что написано, но и зачем.
Финальный тезис
Когда появились первые сильные ассистенты для написания кода, основной вопрос был: «насколько хорошо AI умеет писать код?» С код-агентами вопрос постепенно меняется. Насколько хорошо наш проект умеет быть понятым? Можно бесконечно менять модели, увеличивать контекстное окно и покупать больше токенов. Всё это будет работать. Но в какой-то момент ограничением становится не интеллект агента, а энтропия самой системы.
Мой подход консервативный. Я не пытаюсь перепроектировать программную инженерию вокруг AI. Я беру практики, которые и так помогали держать систему под контролем, и делаю их более явными: атомарная история Git, документация классов и тестов, AAA, SRP, DDD, Documentation as code, бэклог, линтеры, руководство по стилю. Затем добавляю то, что нужно уже именно агентскому рабочему процессу: AGENTS.md, постепенное раскрытие, воспроизводимое окружение, единую команду проверки, ограниченные полномочия и условия остановки. Получается не специальная «AI-архитектура», а кодовая база, которую можно безопасно понимать и менять.
Хорошо подготовленная кодовая база становится внешней памятью AI-агента. Git хранит историю решений, DDD раскрывает смысл, документация объясняет причины, тесты фиксируют поведение, бэклог показывает направление, а линтеры и CI задают границы допустимых изменений.
И это лучший критерий agent-ready проекта: если завтра модель станет в два раза сильнее, вам не придётся переделывать всю систему ради неё. Вы просто дадите более сильному агенту тот же хорошо организованный инженерный контекст.
Исследования и материалы
Ниже источники, на которые я опирался в научной и инструментальной части статьи. Я специально не пытался превратить текст в академический обзор: исследования здесь нужны для проверки отдельных тезисов, а не для подмены инженерного опыта.
-
Nelson F. Liu et al. Lost in the Middle: How Language Models Use Long Contexts — исследование использования информации внутри длинного контекста.
https://arxiv.org/abs/2307.03172 -
Fengji Zhang et al. RepoCoder: Repository-Level Code Completion Through Iterative Retrieval and Generation — итеративное извлечение контекста для дополнения кода на уровне репозитория.
https://aclanthology.org/2023.emnlp-main.151/ -
Carlos E. Jimenez et al. SWE-bench: Can Language Models Resolve Real-World GitHub Issues? — бенчмарк реальных инженерных задач, требующих изменений на уровне репозитория.
https://arxiv.org/abs/2310.06770 -
GraphCoder: Enhancing Repository-Level Code Completion via Coarse-to-fine Retrieval Based on Code Context Graph — структурное извлечение контекста через граф кодового контекста, ASE 2024.
https://ieeexplore.ieee.org/document/10765009/ -
Zhongxin Liu et al. Effective and Efficient Context Retrieval via Partial Dependency Graph for Repository-Level Code Generation — извлечение контекста с учётом зависимостей, ASE 2026.
https://arxiv.org/abs/2608.01927 -
Chao Hu et al. In Line with Context: Repository-Level Code Generation via Context Inlining — использование контекста восходящих и нисходящих зависимостей для генерации на уровне репозитория, FSE 2026.
https://arxiv.org/abs/2601.00376 -
Greta Dolcetti et al. Helping LLMs Improve Code Generation Using Feedback from Testing and Static Analysis — применение обратной связи от тестов и статического анализа для исправления сгенерированного кода.
https://arxiv.org/abs/2412.14841 -
Noble Saji Mathews, Meiyappan Nagappan. Test-Driven Development for Code Generation — эксперименты с передачей тестов вместе с постановкой задачи.
https://arxiv.org/abs/2402.13521 -
OpenAI. Introducing Codex — описание инструкций репозитория через
AGENTS.md, настроенного окружения разработки и проверки.
https://openai.com/index/introducing-codex/ -
OpenAI. Running Codex safely at OpenAI — про границы, ограниченное исполнение, сетевые политики и телеметрию при работе код-агентов.
https://openai.com/index/running-codex-safely/ -
GitHub. Copilot coding agent now supports AGENTS.md custom instructions — корневые и вложенные инструкции для код-агента.
https://github.blog/changelog/2025-08-28-copilot-coding-agent-now-supports-agents-md-custom-instructions/