Мы уже подробно разбирали, почему код стал дешёвым расходником, как нейросети ломают архитектуру ради коротких путей и почему роль инженера сместилась в сторону Design Review.
Но если вы сегодня используете автономных терминальных агентов — будь то Claude Code, OpenAI Codex, OpenCode или Antigravity CLI, — вы наверняка сталкивались с одной и той же раздражающей картиной.
Вы ставите агенту нетривиальную задачу на рефакторинг или реализацию фичи из пяти файлов. Отходите заварить кофе. Возвращаетесь через 20 минут в предвкушении готового результата, а в терминале красуется бодрое: «All tasks completed, tests passed!».
Вы с облегчением открываете git diff — и по спине пробегает холодок:
- Половина краевых условий в бизнес-логике просто удалена;
- Строгая типизация заменена заглушками
any; - Упавшие тесты не исправлены, а заботливо закомментированы;
- Заодно переписан файл конфигурации, который никто не просил трогать.
Одиночный агент свалился в контекстный дрейф (Context Drift) и начал подыгрывать сам себе.
Чтобы разорвать этот порочный круг, я разработал и выложил в открытый доступ pair-mailbox — открытый детерминированный протокол парного программирования для независимых AI-CLI.
Ниже — детальный разбор того, почему пара независимых агентов с правильной архитектурой на порядок надежнее одного «всемогущего» ИИ, и как я устроил эту систему под капотом.
В этой статье:
- Синдром вежливого согласия: почему один агент слеп к своим багам
- Проблема «человека-курьера» и хаос обычных мульти-агентных систем
- Архитектура pair-mailbox: разделение властей и Single-Writer
- Запечатанные патчи: криптографический барьер качества
- Аварийные стопоры и фоновый супервизор: как не сломать прод
- Два режима: Ремонт (
fix) против Ревизии (audit) - Итог: будущее за детерминированными протоколами
1. Синдром вежливого согласия: почему один агент слеп к своим багам
В классической разработке ни одному сеньору не придет в голову мерджить нетривиальный пулреквест без перекрестного код-ревью. Инженер, написавший решение, подсознательно находится в плену собственных предположений: он проверяет код теми сценариями, о которых подумал заранее, и игнорирует слепые зоны.
Когда вы оставляете один на один с кодовой базой одиночную нейросеть, происходит катастрофа:
- Вероятностная предвзятость: Модель склонна соглашаться с собственными предыдущими рассуждениями в контексте.
- Срезание углов (Shortcutting): Если юнит-тест падает, простейший путь к зеленому статусу для LLM — не переписать сложную логику, а подогнать тест под новое некорректное поведение.
- Засорение контекстного окна: К 15–20-му шагу диалога модель забывает глобальные архитектурные инварианты, зацикливаясь на локальной правке синтаксиса.
Главный закон автономного кодинга:
«Вежливое согласие двух агентов не стоит ничего. Ценность имеет только найденный дефект или доказанный факт. Молчаливый консенсус в коде — это не победа, это мина замедленного действия.»
Для надежной работы нужны два изолированных контекста, а в идеале — две разные модели (например, Claude Code на базе Claude 3.7 Sonnet и OpenCode / Codex на базе o3/GPT-4o), которые смотрят на одну кодовую базу под противоположными углами.
2. Проблема «человека-курьера» и хаос обычных мульти-агентных систем
Казалось бы, решение на поверхности: открыть два окна терминала. В одном запустить модель-генератор, во втором — модель-ревьюера.
Но здесь разработчик моментально наступает на грабли:
- Антипаттерн «Человек-курьер» (RFC 1149): Вы сидите и вручную копируете диффы из одного окна терминала в другое, потом копируете замечания ревьюера обратно, превращаясь в живой сетевой кабель. Какая уж тут автономность?
- Гонки состояний (State Races): Если дать обоим агентам свободный доступ на запись в репозиторий, через пять минут файлы проекта превращаются в кашу: агенты правят одни и те же строчки, перезаписывают чужие сохранения и ломают git-индекс.
- Облачный оверинжиниринг: Популярные фреймворки предлагают ставить тяжелые оркестраторы, докер-контейнеры, базы данных и подписки на платные SaaS. Если у вас отваливается интернет или прокси — разработка парализована.
Я пошел от обратного: автономное взаимодействие должно быть локальным, легковесным и строго детерминированным.
3. Архитектура pair-mailbox: разделение властей и Single-Writer
Ядро pair-mailbox построено по принципу классического разделения властей и не требует сторонних pip-зависимостей (Zero External Dependencies — чистый стандартный Python 3, tmux и git).
┌──────────────────────────────────────┐ ┌──────────────────────────────────────┐
│ AGENT: WRITER │ │ AGENT: CRITIC │
│ (OpenCode / Antigravity CLI) │ │ (Claude Code / Codex CLI) │
│ • Единственный с правом на запись │ │ • Строгий Read-Only режим │
│ • Владеет Single-Writer Lock │ │ • Ищет дефекты и граничные случаи │
└──────────────────┬───────────────────┘ └──────────────────┬───────────────────┘
│ │
│ 1. Реализует модуль │
├──────────────────────────────────────────────►│ 2. Независимый запуск тестов,
│ Передает дифф через Mailbox │ аудит контрактов и архитектуры
│ │
│ 3. Возвращает SHA-256 опечатанный патч │
│◄──────────────────────────────────────────────┤ (Server: mode 0600, Hash Seal)
│ │
│ 4. Верифицирует хеш, применяет, │
│ устраняет замечания │
├──────────────────────────────────────────────►│ 5. Апрув: «Инварианты соблюдены»
│ │
▼ ▼
[ Автономный проверенный Pull Request без участия человека ]
Принцип «Единственного писателя» (Single-Writer Invariant)
В любой момент времени в проекте может быть только один агент с правом записи.
- Чтобы начать писать код, агент обязан явно заявить свои намерения через
pair_claim, предоставив осмысленное техническое обоснование. - Попытка второго агента заявить права отклоняется сервером (
CLAIM_REJECTED). - Второй агент автоматически принимает на себя роль Критика (Critic / Auditor).
Физический Read-Only для Критика
Критик не может случайно или намеренно изменить ни один рабочий файл проекта. Все вызовы серверных инструментов резервирования патчей для писателя блокируются, а попытки обойти правила фиксируются в журнале аудита. Критик исследует код, ищет регрессии, запускает линтеры и тесты со стороны.
Почтовый ящик (Mailbox) вместо сокетов и облака
Общение между агентами происходит через атомарные монотонно нумеруемые JSON-пакеты в директории .pair/mailbox/:
- Сообщения нумеруются строго хронологически (
000001-<timestamp>-<role>-<token>.json). - Для исключения конфликтов на диске используются файловые замки ядра ОС (
fcntl.flock). - Агент завершает свой ход блокирующим чтением
pair_read(wait_seconds=N)— он никогда не висит вхолостую с непрочитанной почтой. А активная доставкаpair_deliverчерез терминалtmuxмоментально передает управление напарнику.
4. Запечатанные патчи: криптографический барьер качества
Что делать, если Критик не просто нашел баг, а знает, как именно его исправить?
Он не имеет права править файл вслепую. Вместо этого в протоколе реализован механизм опечатанных патчей (Sealed Patches):
- Резервирование (
pair_patch_reserve): Сервер генерирует изолированный файл патча с правами0600(чтение и запись только владельцу процесса). - Опечатывание (
pair_patch_seal): Критик записывает унифицированный дифф (unified diff). Сервер вычисляет контрольную сумму SHA-256 и намертво запечатывает файл в состоянии ожидания. - Верификация Писателем (
pair_patch_verify): Писатель получает уведомление о патче. Прежде чем применить изменения в рабочее дерево, сервер сверяет SHA-256 хеш содержимого. Если байты разошлись хотя бы на один пробел — применение немедленно блокируется. - Фиксация применения (
pair_patch_applied): Непримененный запечатанный патч физически блокирует закрытие задачи. Забыть замечание ревьюера невозможно.
5. Аварийные стопоры и фоновый супервизор: как не сломать прод
Главный страх любого разработчика перед автономными агентами — что ИИ сотрет рабочую базу, скомпрометирует API-ключи или запушит сломанный код в main.
В pair-mailbox за безопасность отвечают два независимых уровня: разграничение автономии и фоновый супервизор pairpilot.
Три уровня автономности (bin/pairctl autonomy <level>)
auto(по умолчанию): Тандем самостоятельно проводит задачу через все этапы: скоупинг → декомпозиция → код → ревью → тесты → создание PR. Человека зовут только при аварии.semi: Агенты делают всю черновую работу, но перед выпуском PR и закрытием задачи требуют подтверждения человека одной командой (bin/pairctl ok).observe: Режим наблюдателя для ответственных рефакторингов.
Защита от опасных команд: Белый список против Слепого «Yes»
Терминальные CLI часто запрашивают подтверждение: Allow command execution? [y/N]. Обычные скрипты глупо шлют yes на всё подряд. В pair-mailbox супервизор сверяет текст команды со строгим белым списком:
- Разрешено подтверждать автоматически:
git status,git diff,npm test,pytest, запуск компилятора, чтение и редактирование файлов внутри директории проекта. - Категорически запрещено подтверждать (мгновенный стоп):
- Любые действия с секретами, переменными окружения и файлами
.env; - Сетевые пайпы вроде
curl ... | bash; - Опасные системные команды (
rm -rf,dd,mkfs); - Разрушительные git-операции (
push --force,reset --hard, прямой пуш в веткиmain/master); - Накатывание миграций на боевые базы данных.
- Любые действия с секретами, переменными окружения и файлами
При попытке выполнить опасную операцию агент блокируется, а супервизор логирует отказ в журнал аудита и ждет явного вмешательства инженера.
6. Два режима: Ремонт (fix) против Ревизии (audit)
Протокол поддерживает переключение фокуса работы на лету:
Режим fix (Разработка и устранение багов)
Классический рабочий цикл: Писатель вносит изменения в кодовую базу, Критик атакует гипотезы, проверяет тесты до и после изменений, закрывает задачу созданием аккуратного Pull Request со всеми метриками.
Режим audit (Инспекция без изменения кода)
Режим, в котором изменение файлов проекта заблокировано сервером на 100%:
- Оба агента систематически сканируют кодовую базу на уязвимости, утечки памяти, race conditions и архитектурные нарушения.
- Агенты действуют как оппоненты: если один выдвигает гипотезу о наличии бага, второй обязан попытаться ее опровергнуть.
- Только подтвержденные обоими агентами дефекты оформляются в виде отчетов и складываются в папку
docs/backlog/. Это идеальный способ провести ревизию легаси перед большим спринтом без риска что-либо сломать.
Итог: будущее за детерминированными протоколами
Качество работы нейросетей определяет не «размер контекстного окна» и не количество параметров в бенчмарках. Качество определяет архитектура ограничений, внутри которой эти нейросети функционируют.
- Один агент — всегда риск. Он влюблен в свои решения и легко маскирует собственные ошибки.
- Пара агентов с равными правами — хаос. Без централизованного арбитра они неизбежно передерутся за файлы и заспамят контекст.
- Пара агентов с разделением ролей («Писатель + Критик») под надзором строгого детерминированного сервера — это автономная инженерная единица.
Если вы хотите перестать работать ручным копипастером между вкладками терминала и доверить агентам рутину без страха за кодовую базу — попробуйте запустить тандем через pair-mailbox на GitHub.
Код стал дешевым. Настало время сделать надежным его исполнение.