Почему модульный монорепозиторий идеален для кодирующих агентов: возможность видеть всё при минимальном вмешательстве.
Агенты Polyrepos без возможности видеть окружение сталкиваются с наводнением неструктурированными монорепозиториями. Открытый контекст, инкапсуляция и настоящая диаграмма зависимостей позволяют модульному монорепозиторию эффективно работать с такими агентами.
Источники: The Shine of the Modular Monorepo in the Agentic Era
Старый спор с новыми последствиями
На протяжении многих лет инженеры делятся на две группы. Одни хранят весь код в одном репозитории, а другие предоставляют каждой части отдельное место хранения, при этом существует множество компромиссов. Никто не прав во всем, и те, кто утверждает обратное, обычно основываются на опыте одного проекта. Если спросить, что лучше — монорепозиторий или полирепозиторий, честный ответ будет «это зависит»: от размера системы, степени взаимосвязи её компонентов, состава команды и частоты выпуска обновлений. Несколько слабо связанных сервисов должны находиться в отдельных репозиториях. Продукт, тесно связанный с общими контрактами, указывает на противоположное решение.
Инструменты кодирования усугубляют эту проблему. Если поручить агенту задачу, требующую работы с фронтендом, общей библиотекой и контрактом бэкенда, структура репозитория уже не будет вопросом вкуса. Последствия этого проявляются в качестве кода, в том, как часто агенту приходится догадываться, и в степени его растерянности. Пример приводится для TypeScript NX, работающего на шести платформах. Это заявленная точка зрения, которая может не соответствовать мнению всех, поэтому рассматривайте её как твёрдое мнение, призванное запустить дискуссию. Четыре слова подводят итог этому утверждению: видеть всё, трогать мало.
Первый барьер: стены, за которыми агент не может видеть
Представьте разделённый мир, в котором работают большинство команд: один репозиторий фронтенда, пара репозиториев сервисов бэкенда, пакет shared-types в частном реестре и репозиторий инфраструктуры. Границы имеют смысл, и у каждой части есть ответственный.
Предположим, агент в репозитории фронтенда получает задание изменить способ вызова эндпоинта, принадлежащего репозиторию сервиса, к которому у него нет доступа. Поскольку нет механизма для чтения данных, агент предполагает, как будет выглядеть ответ. Старый шаблон типа или отдельный пример теста становятся его доказательствами. Результат компилируется на локальной машине, но, скорее всего, окажется неверным при интеграции. Каждая граница репозитория — это стена, за которую агент не может заглянуть, и он заполняет её правдоподобными предположениями. То, что защищает людей, оставляет агентов в поисках информации.
Команды устраняют этот недостаток тремя основными способами, причем некоторые из решений действительно эффективны:
- Git-подмодули размещают репозитории зависимостей внутри основного репозитория, делая структуру файлов единообразной. Агент получает возможность читать всё содержимое, но при этом возникают обычные проблемы: коммиты фиксируются в определенном состоянии, поддержание актуальности данных превращается в рутинную задачу, а рабочий процесс не устраивает никого.
- Рабочие пространства IDE с несколькими корнями позволяют Cursor или VS Code индексировать несколько репозиториев вместе, что удобно, когда цель — просто просматривать содержимое всех из них. Однако такая структура относится к одной машине, а не к проекту, и агент получает огромное количество файлов без графа зависимостей. Он знает о существовании кода, но не понимает, что зависит от чего.
- Синтетические монорепозитории являются более серьезным решением. Например, Polygraph от NX объединяет отдельные репозитории в единый граф зависимостей, оставляя код на прежних местах. Координирующий агент изучает этот граф, чтобы определить, до каких репозиториев дошли изменения, запускает агента в каждом из них и открывает соответствующие запросы на слияние, одновременно отслеживая процессы CI во всех местах. Это решение наиболее близко к поведению монорепозитория при использовании структуры полирепозитория.
Синтетический подход заслуживает уважения, но посмотрите, что он на самом деле делает: он прокладывает туннели сквозь стены, которые остаются неподвижными. Инженеры прилагают огромные усилия для создания инструментов, которые должны воспроизвести ту же видимость, что и монорепозиторий, но без дополнительных затрат. А когда таких инструментов нет, человек выступает в роли туннеля: он читает данные из сервиса B, передает информацию агенту в сервисе A, вставляет определения типов в чат и действует как курьер между изолированными сессиями.
Второй препятствие: бесструктурная куча
Значит, всё перемещается в один репозиторий, и проблема решена? Не совсем. Монорепозиторий без внутренней структуры работает ещё хуже, потому что создаёт соблазн. Всё становится видимым, и это кажется достаточным. На самом деле здесь есть один огромный каталог приложений, библиотеки, которые импортируют друг друга со всех сторон, отсутствуют жёсткие границы, и нет понимания, какая часть принадлежит кому.
Здесь отсутствие чёткого контекста мешает работе. Агент, видящий всё, не получает никаких указаний относительно того, что можно пропустить. Окно заполняется кодом, находящимся рядом на диске и не связанным с задачей; одна правка влияет на импорты, которые никто не отслеживал, а на важный вопрос о том, как это изменение повлияет на всё, приходит ответ «возможно, на всё». Отсутствие структуры при наличии информации приводит к шуму, а не к контексту, и именно поэтому хранение всего кода в одном репозитории — не лучшее решение.
Три основы модульного монорепозитория
Модульный монорепозиторий демонстрирует преимущества, выполняя три задачи одновременно. Нарушение хотя бы одной из них приводит к сбоям.
Открытый контекст. Одно дерево содержит всё необходимое, и агент может просматривать его: фронтенд, бэкенд, общие библиотеки, тесты и типовые контракты, связывающие их вместе, в рамках одной сессии. Никаких барьеров, никаких догадок, никаких посредников. В планах развития NX наибольшее внимание уделяется именно этому аспекту, и это вполне оправдано, поскольку агент, прочитавший производителя контракта и всех его потребителей за один проход, сможет вносить более качественные изменения.
Инкапсуляция. Библиотеки имеют чёткие границы и предоставляют явные публичные интерфейсы, поэтому агенту не нужно помнить всю систему целиком. Он работает с определённой её частью. Именно это позволяет сосуществовать возможности видеть всё и вмешиваться лишь в незначительные аспекты, без чего открытый контекст превращается в ситуацию, описанную в пункте два.
Настоящая диаграмма зависимостей с инструментами для её исследования. Именно этот аспект часто недооценивают. NX рассматривает диаграмму как объект первого класса, с которым можно выполнять запросы. Вместо поиска вручную с надеждой на определение структуры агент может выполнить команду nx show projects, открыть интерфейс nx graph, узнать, какие элементы затронуты изменениями, и получить точный ответ, который может обработать машина. Карта хранится в репозитории, а не в вики или памяти старшего инженера, причём она является исполняемой.
Все это вместе реализует четырёхсловную тезисную структуру: полный обзор — первый принцип, минимальное вмешательство — второй принцип, а знание того, во что именно нужно вмешаться, — третий принцип, который позволяет безопасно сочетать первые два.
Получение и проверка
Агенты работают в цикле: они получают контекст, изменяют код, проверяют эти изменения и снова повторяют процесс. Вся система поддержания порядка в монорепозитории служит одной из двух целей: быстрому получению контекста или быстрой проверке действий.
- Жесткие типы (acquire). Общая библиотека типов предоставляет агенту контракт, который он может читать, а компилятор — соблюдать. Это решает проблему «слепого агента», описанную в первом этапе, поскольку формат ответа не требует догадок, если он зафиксирован и проверен. Типы также служат документацией, которая никогда не устаревает.
- Правила по очистке кода и границам модулей (проверить). Благодаря параметру
@nx/enforce-module-boundariesв NX запрещённые импорты вызывают ошибку вместо того, чтобы проходить незамеченными, причём ошибка поступает во внутренний цикл агента в качестве обратной связи. Если агент подключает библиотеку интерфейса к слою данных, правило отклоняет такое подключение, и архитектура формируется на основе этих сбоев без необходимости явного описания её кем-либо. - TDD и соответствующие тесты (проверить). Команда
nx affectedпозволяет быстро проверять изменения. После редактирования кода агент запускает только те тесты, которые находятся ниже изменённой части, и мгновенно видит результат — красный или зелёный, без необходимости ожидания полного набора тестов или сомнений в корректности изменений. Короткие циклы делают работу агента похожей на процесс разработки, а не на постоянный надзор. - Навыки и файлы AGENTS.md или CLAUDE.md (получение). Выполнение команды
npx nx configure-ai-agentsв рабочем пространстве устанавливает сервер MCP, навыки агента и файлы с правилами работы. Навыки загружаются по мере необходимости, а не все сразу, поэтому способы создания библиотеки осваиваются именно в процессе её создания. Кроме того, это направляет агента на запрос информации из графа вместо поиска по тексту, что связано с третьим принципом. - Атомарные руководства по каждому модулю (получение). Каждая библиотека может содержать краткое описание в файле README или AGENTS.md, которое предоставляет локальный контекст прямо там, где агент только что появился. При загрузке этой библиотеки загружаются её контракт и правила работы, без необходимости подтягивания остальных элементов структуры.
Если просуммировать этот список, получится последовательность «получить», «проверить», «проверить», «получить», «получить», хотя порядок здесь не имеет значения. Каждая возможность соответствует одной из двух задач. Модульный монорепо — это не одна функция для агентов, а множество небольших функций, которые обеспечивают быструю и эффективную работу.
Аргументы против
Никто не получает выгоды от презентаций продукта, поэтому стоит рассмотреть контраргументы. Окна контекста продолжают расширяться, а инструменты многорижковых рабочих пространств и синтетических монорепо сокращают разрыв между подходами. Скептики могут считать преимущество монорепо временным явлением, обусловленным текущими ограничениями, которое исчезнет при наличии достаточно большого окна контекста и хороших инструментов для взаимодействия между репозиториями. Более точная формулировка не связана с окнами контекста. Полиграф показывает, что граф зависимостей можно воссоздать в рамках полирепо, поэтому структура, часто приписываемая монорепо, не может принадлежать только им одним.
Каждая версия ошибается в понимании источника преимущества. Речь никогда не шла о чтении большего количества сырого текста — речь идет о структуре. Более широкое окно позволяет «заблудившемуся агенту» теряться в более тонких деталях, не указывая правильную дверь. Синтетическая схема также является структурой, что объясняет ее эффективность, но эта структура создается и поддерживается на основе разделения данных и не задается самим макетом. Сырой контекст развивается вместе с моделью, структура — благодаря дисциплине, и именно структура превращает возможность видеть все в угрозу в ресурс. По мере увеличения размеров окон монорепозиторий без модулей становится более рискованным, поскольку «шлюз» открывается шире; нагрузку несет прилагательное.
Что раскрыла эра агентов
Графики проектов, границы модулей и общие типы когда-то казались удобством для человеческой команды. Эпоха агентов показала их истинную сущность: интерфейс для нечеловеческих партнеров по сотрудничеству. Архитектура, разработанная с учётом человеческого мышления, оказалась на самом деле инструментом создания контекста на уровне репозитория, за много лет до появления этого термина. Это объясняет, почему вновь становятся популярными решения, отличные от монорепозиториев. Модульный монорепозиторий тихо дал ответ на вопрос, который ещё никто не задавал: видеть всё, вмешиваться минимум, а агенты лишь сделали это более очевидным.