aitherlab
ru / en

Team of Faggots

[КОМАНДА ПЕДИКОВ] Как я заставил четырёх агентов разговаривать между собой через MCP, перестал быть посредником и обнаружил что городу нужно ограждение.

Я полгода запускаю агентов по одному и копипащу результаты из одного окна в другое, и в какой-то момент до меня наконец доходит абсурдность ситуации, ведь у меня десктопное приложение которое управляет CLI-процессами, у каждого процесса есть stdin и stdout, и я сижу как обезьяна посередине и перекладываю текст между ними руками.

Утренний план

Идея простая, до боли: пусть агенты разговаривают между собой напрямую, без моего участия. Один пишет код, второй проверяет, третий координирует. Я подключаюсь когда нужно принять решение, а не когда нужно скопировать промт из окна А в окно Б.

Начинаю с того что лезу в старую ветку exp, где когда-то жила арена, два агента спорили друг с другом в одном чате. Там был memory-mcp, отдельный бинарник на SQLite, который автоматически подключался к каждой CLI-сессии. Звучит красиво, но ветка морально сгнила, мы оттуда давно всё выпилили, и пересобирать этот крейт ради одной фичи бессмысленно.

Почтовый ящик

Первое что я делаю, ну, точнее что делает кодер в ветке branches, потому что я решил сразу работать в формате «кодер пишет, ревьюер проверяет, я дирижирую» — это mailbox. Обычные JSONL-файлы на диске, append-only, каждый агент имеет свой inbox. Рядом — система задач, тоже файлы, с блокировками и владельцами. Ревьюер тут же находит что любой агент может завершить чужую задачу. Починили. Ревьюер находит что при инжекции сообщений в stdin агента есть гонка с пользовательским вводом — оба могут одновременно писать в трубу. Починили, сделали единый замок AgentWriter который атомарно проверяет состояние и пишет.

Я сижу в отдельном чате, формулирую промты кодеру и ревьюеру, получаю отчёты, скидываю фиксы. По сути именно то, что хочу автоматизировать, но пока делаю руками. Ирония.

HTTP-сервер внутри коробки

Дальше самое вкусное. Агентам надо как-то разговаривать между собой не через файлы которые кто-то должен проверять раз в три секунды, а через нормальный протокол. MCP, Model Context Protocol, вот он для этого и нужен. Варианты: отдельный бинарник как в exp, парсинг stdout, или HTTP-сервер прямо в приложении.

Выбираю третий. Axum на 127.0.0.1, рандомный порт, MCP Streamable HTTP транспорт. Семь инструментов: send_message, broadcast, read_inbox, list_tasks, create_task, claim_task, complete_task. При запуске агента команды в --mcp-config подсовывается URL с его agent_id, и всё, он видит инструменты и может ими пользоваться. Идентификация через URL, подделать from нельзя — ревьюер специально это проверил и нашёл дыру которую мы тут же залатали.

Потом навешиваем инструменты управления для роли architect: start_agent, stop_agent, restart_agent, send_prompt. Architect может запускать других агентов и отправлять им задачи прямо через MCP. Coder и reviewer видят только коммуникационные инструменты, управляющие скрыты и заблокированы на уровне execute_tool.

Момент истины

Собираю билд из ветки branches, открываю, создаю команду. Называю «PEDIKI», потому что у меня такой юмор. Добавляю кодера, ревьюера, архитектора. Жму Play.

Архитектор запускается, сам лезет в mcp_teamwork_read_inbox, проверяет почту, пишет «Жду входящих сообщений. Готов к работе». Я даже ничего не просил. Он увидел инструменты и сам решил проверить ящик.

Отправляю broadcast через панель команды: «Привет, тестируем фичу, ответьте получили ли мое сообщение». Переключаюсь на чаты. Кодер ответил. Ревьюер ответил. Architect ответил. Все трое просят разрешение на MCP-инструменты — ага, забыл добавить mcp__teamwork__* в allowedTools. Агенты висят, приложение выглядит зависшим, кодер в ветке тоже завис на этом же. Перезапускаю, добавляю wildcard, пересобираю.

Второй заход. Пишу архитектору: «отправь сообщение кодеру через MCP: привет от архитектора». Architect вызывает mcp__teamwork__list_agents, находит кодера, вызывает mcp__teamwork__send_message. Переключаюсь на чат кодера. «Жду задачу от архитектора.» Кодер сам ответил архитектору через MCP. Переключаюсь обратно на архитектора: «Кодер ответил — на связи, ждёт задач.»

Полная цепочка. Без моего участия. Два агента нашли друг друга и поговорили.

Неудобная правда

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

И ещё я замечаю что MCP-сервер-то встроен в приложение. Он не привязан к командам. Любой агент, которому подсунуть конфиг, может писать любому другому. Вся эта конструкция с team_create, team_add_agent, ролями — это обвязка поверх того что по сути уже работает. Один HTTP-эндпоинт решает задачу коммуникации, а мы вокруг него настроили целый город.

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

Что дальше

Нужен нормальный групповой чат, как в мессенджере. Одно окно, все сообщения от всех агентов, с подписями кто кому. Не прыгать по табам. Индивидуальные чаты оставить для тех кто хочет посмотреть полный лог с инструментами и размышлениями, а координация — в одном месте.

За день с нуля собрали: mailbox, задачи, команды, роли, инжекцию в stdin, защиту от гонок, UI-панель, HTTP MCP-сервер с 12 инструментами, привязку к чатам. Ревьюер нашёл штук восемь багов которые починили до того как они стали проблемой. Вся архитектура работает, агенты реально общаются, и мне это стоило ноль строк кода написанных лично — я только формулировал промты и принимал решения. Что, собственно, и является целью всей этой затеи.