Как я отдал агенту четыре репозитория и увидел то, что в коде не видно в принципе.

Хайп AI-кодинга не обошёл никого. Если ты не используешь AI-инструменты в работе и в жизни — твои навыки устаревают с каждой неделей и с каждым выходом новой модели. А заодно этот хайп заполонил интернет толпами SaaS-решений, под капот которых страшно заглядывать.

И дело тут не в низкой квалификации тех, кто эти проекты делает — технический бэкграунд у ребят часто более чем приличный. Дело в скорости: темп релизов и решений тянет за собой тонны недодуманного, потому что в этой гонке надо успеть откусить свой кусок пирога.

Концепция при этом не меняется: сначала по-быстрому слепить MVP из того, что есть, зарелизить, получить обратную связь. Пройти самый важный этап — от пустоты до чего-то осязаемого — как можно быстрее. А вот если проект заработает, тогда уже и переписывать под все потребности: на нужные технологии, с нужными подходами и паттернами.

Да закидают меня палками солюшн-архитекторы :)

И кто же будет всё это переписывать? У кого будет контекст огромного навайбкоженного проекта? Люди, конечно. Которые тоже будут использовать AI — но уже с пониманием контекста и существующих проблем.

Начнётся реверс-инжиниринг всего навайбкоженного: документирование, описание потоков данных, куча разных диаграмм — чтобы спроектировать всё так, как нужно.

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

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

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

И контекста всей системы не хватает ни агентам, ни нам — техническим специалистам, которые этими агентами управляют.

Дальше я проверил это на живом проекте: собрал такой SaaS из четырёх репозиториев, отдал агенту восстановить архитектуру, а потом переписал ядро с Node на Java по всем правилам — со слоями, типами, JPA и DTO. Спойлер: кода стало в разы больше и он стал объективно лучше, а все пять архитектурных проблем остались на месте. Одна из них при переписывании даже закрепилась в коде явно. Увидеть это получилось только на диаграмме.

Подопытный: ClipCast

Чтобы не махать руками в воздухе, я собрал такой проект по-настоящему. Знакомьтесь — ClipCast: SaaS, который принимает подкаст или видео и нарезает из него клипы для соцсетей.

Четыре отдельных репозитория, ровно так, как это обычно и выглядит:

  • clipcast-web - Веб-студия: логин, воркспейсы, проекты, клипы, комментарии. React + TypeScript (Vite)

  • clipcast-api - Ядро: авторизация, воркспейсы, проекты, загрузка медиа, API-токены. Java 21 + Spring Boot

  • clipcast-transcriber - Воркер: медиа → транскрипт. Python

  • clipcast-clipper - Воркер: транскрипт → клипы, вызов внешнего AI. Node.js

Плюс Postgres и Redis, всё поднимается одной командой:

docker compose up --build
Дерево проекта: четыре папки-репозитория + docker-compose.yml.
Дерево проекта: четыре папки-репозитория + docker-compose.yml.

Открой любой из четырёх репозиториев по отдельности — и всё выглядит нормально.

  • Открываешь clipcast-api — отличный Spring Boot, всё по канону.

  • Открываешь clipcast-transcriber — маленький аккуратный Python-воркер на 50 строк.

  • Открываешь clipcast-clipper — такой же маленький Node-воркер.

  • Открываешь clipcast-web — типизированный React.

А вот вопросы, на которые ни один из этих репозиториев не отвечает:

  • Кто вообще пишет в таблицу clips? (Спойлер: не то, что вы думаете.)

  • Сколько сервисов держат подключение к одной и той же базе?

  • Что произойдёт, если поменять схему transcripts?

  • Какие эндпоинты api не защищены авторизацией?

  • Какие эндпоинты вообще никто не вызывает?

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

Дальше — ровно тот эксперимент, ради которого всё затевалось.

Шаг 1. Получаем токен в Viaduct

Viaduct — это полностью бесплатный инструмент, в котором я держу архитектуру: C4-модель (системы → контейнеры → компоненты), HTTP-контракты, брокерские каналы, ER-схемы, PlantUML-последовательности и Magic flows (проигрываемые потоки данных через всю систему).

Ключевое для этой статьи: у него есть MCP-сервер. То есть агент может не просто «посмотреть картинку», а читать и писать модель инструментами.

Создаём API-токен:

Путь: шестеренка и MCP Access
Путь: шестеренка и MCP Access

Создаем токен и далее копируем конфиг для агента с ним и просим агента настроить себе MCP коннект.

Шаг 2. Подключаем MCP-сервер к агенту

Я работаю в Claude Code, поэтому команда такая:

claude mcp add --transport http viaduct https://c4.quietgridlabs.com/api/mcp \
--header "Authorization: Bearer $VIADUCT_TOKEN"

Проверяем, что агент действительно достучался — самый простой вызов:

c4_whoami

Если в ответ приходит твой пользователь — всё, агент подключён к архитектуре.

Агент вызовет tool c4_whoami или любой другой и Viaduct Увидит что все успешно подключилось.
Агент вызовет tool c4_whoami или любой другой и Viaduct Увидит что все успешно подключилось.
Агент успешно подключился
Агент успешно подключился

Далее выполняем:

claude mcp list
Чтобы убедиться, что MCP сервер успешно подключен
Чтобы убедиться, что MCP сервер успешно подключен
Экран успешного подключения  MCP Viaduct
Экран успешного подключения MCP Viaduct

Полный набор инструментов, который получает агент, — это примерно то, чем пользуется живой архитектор:

  • чтение: c4_project_context, c4_search, c4_get_element, c4_list_docs, c4_list_technologies

  • запись модели: c4_create_element, c4_update_element, c4_upsert_connection

  • документация и потоки: c4_upsert_doc, c4_upsert_sequence, c4_upsert_data_flow

Отдельно отмечу мелочь, которая оказалась важной: у Viaduct есть скилл (viaduct-architect) — набор правил, как именно моделировать. Что эндпоинт — это kind=endpoint с методом и контрактом, а топик — это kind=channel под брокером, а не «ещё один эндпоинт». Что связи бывают только между элементами одного уровня C4. Что technology — это id из каталога, а не «Redis» строкой.

Без этих правил агент рисует кашу из «Сервис А общается с Сервисом Б». С ними — получается модель, которую не стыдно показать команде.

Шаг 3. Просим агента задокументировать проект

Дальше самое интересное. Промпт, по сути, один:

Просканируй код в ~/clipcast-demo (4 репозитория: clipcast-web, clipcast-api,
clipcast-transcriber, clipcast-clipper) и задокументируй архитектуру в Viaduct:
создай системы под каждый сервис, эндпоинты, брокерские каналы, связи между сервисами — включая скрытые.
Отметь скрытую связность отдельно, она должна быть заметна на диаграмме.

И агент уходит работать: читает pom.xml и контроллеры, worker.py и worker.js, schema.sql, docker-compose.yml, package.json — и параллельно выкладывает это в модель.

Начало работы агента по документированию
Начало работы агента по документированию


Агент собирает модель
Агент собирает модель

Ждем пока агент все создаст в проекте.

Спустя 12 минут агент полностью задокументировал все репозитории.

Успешное завершение и краткое Итого от Агента
Успешное завершение и краткое Итого от Агента

Что получилось

В Viaduct появилось:

  • 1 Актор - Пользователь студии

  • 5 Систем, 1 из которых внешняя OpenAI API

  • 16 эндпоинтов на api — с методами, путями, телами запросов и всеми статусами ответов, а не только счастливым

  • 2 брокерских канала под Redis: media.uploaded и transcript.ready — со схемами сообщений

  • 9 таблиц в Postgres с колонками и типами

  • документация на систему и на каждый значимый контейнер

  • PlantUML-диаграмма последовательности для основного сценария

  • Magic flow «Upload → Clips pipeline» из 9 шагов — весь путь файла от загрузки до готового клипа

Самый верхний уровень, как и просили, чтобы агент выделил их в системы
Самый верхний уровень, как и просили, чтобы агент выделил их в системы
Толпа несвязанных друг с другом таблиц в Postgres
Толпа несвязанных друг с другом таблиц в Postgres
Поток данных по загрузке клипов
Поток данных по загрузке клипов
Каталог с документацией и эндпоинтами
Каталог с документацией и эндпоинтами

А теперь то, ради чего всё затевалось

Когда модель собралась, на диаграмме стало видно то, что в коде размазано по четырём репозиториям.

1. В базу пишут три сервиса, а не один

clipcast-api — вроде бы единственная точка входа к данным. Но clipcast-transcriber держит свой psycopg2-коннект к той же базе и делает INSERT INTO transcripts. А clipcast-clipper держит свой pg-пул и делает INSERT INTO clips.

В коде это два неприметных файла db.py и db.js по пять строк каждый. На диаграмме — три стрелки, сходящиеся в одну Postgres, и две из них подписаны «напрямую, в обход api».

Последствие, которое из кода не видно вообще: любая миграция схемы в Java-сервисе тихо ломает два других сервиса на других языках. Hibernate с ddl-auto: update при этом радостно поменяет схему сам.

2. Пайплайн наполовину на событиях, наполовину на HTTP

Вся цепочка построена на Redis pub/sub: media.uploaded → транскрипт → transcript.ready → клипы. А вот финализацию clipper отправляет прямым HTTP-вызовом POST /internal/clips/ready.

Когда-то это был быстрый фикс. В коде clipper'а это одна строчка fetch. На диаграмме это отдельная стрелка, которая ломает симметрию всего остального потока, — и её сразу хочется убрать.

3. Внутренний вебхук без авторизации

/internal/clips/ready не проверяет вообще ничего: ни авторизацию, ни то, что projectId принадлежит вызывающему. Любой, кто дотянется до порта, может пометить чужой проект как готовый.

4. Мёртвый код, который никто не решается удалить

GET /api/legacy/ping — старый health-check. Вызывающего кода нет ни в одном из четырёх репозиториев. Агент это пометил тегом dead-code.

5. Захардкоженный адрес API во фронте

const API_BASE = 'http://localhost:4000' — без переменных окружения.

Главная мысль

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

Что это даёт на практике

Теперь у меня есть карта системы, и она не в голове у одного человека.

  • Для меня как для технического специалиста: я вижу, за какие ниточки дёргать. Не «надо бы отрефакторить», а конкретно: убрать два прямых коннекта к базе, закрыть /internal/*, заменить HTTP-уведомление на событие. Приоритеты стали видны.

  • Для агентов: это тот самый недостающий контекст. Когда я даю агенту задачу «добавь эндпоинт для скачивания клипа», он может сначала прочитать модель и узнать, что таблицу clips пишет вообще другой сервис на другом языке. Без этого он бы просто дописал INSERT в Java-сервис и создал третьего писателя в ту же таблицу.

- Для новых людей в проекте: онбординг — это открыть диаграмму и проиграть Magic flow, а не читать четыре репозитория подряд.

___

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

___

Экстраординарные времена требуют экстраординарных решений. Вайбкодить дальше мы не перестанем — и не надо. Но если генерировать код в десять раз быстрее, чем раньше, то и карту этого кода придётся обновлять в десять раз быстрее. Руками так уже не получится.

Ссылки: