Сегодня Claude Code, ChatGPT и Grok работают над одним проектом как три отдельных исполнителя без общего состояния. Они конфликтуют не из-за «плохих промптов», а из-за отсутствия инфраструктуры координации: нет единого источника правды, нет прав на артефакты, нет протокола передачи результата, нет журнала решений. И главное — нет механизма, который сводит их результаты в один.
RELAY — это агрегатор и операционная система для ИИ-экипажа. Она не заменяет агентов и не пишет код за них: она разбирает одну задачу на параллельные прогоны разных инструментов, проверяет их и сводит в один результат. Она решает ровно одну задачу: превращает набор параллельных ИИ-исполнителей в одну команду с общим контекстом, разделёнными зонами ответственности и формализованной передачей результата.
Решение строится на четырёх механизмах:
| # | Механизм | Что решает |
|---|---|---|
| 1 | Контракт проекта (Project Contract) — версионируемая машинно-читаемая спецификация: цели, границы, стек, DoD, карта владения | Дрейф требований, споры «о чём вообще проект» |
| 2 | Доска задач с WIP-лимитами, зависимостями и зонами ответственности | Дублирование работы, перегрузка агента, работа не по приоритету |
| 3 | Реестр артефактов + протокол Handoff Packet | Потеря контекста между агентами, приёмка «на глаз» |
| 4 | Движок конфликтов (6 детекторов + авто-разрешение + эскалация) | Прямо то, из-за чего сегодня всё ломается |
relay.codes — это агрегатор. Центральный сценарий платформы: человек ставит одну задачу — RELAY разбирает её на три параллельных прогона (Claude Code, ChatGPT/Codex, Grok) с разными перспективами, проверяет каждый результат по DoD, сводит их в один PR и фиксирует решение в ADR. Подробно — раздел 5.
Плюс два «сшивающих» слоя: журнал решений (ADR) — чтобы спор решался фактами, а не памятью; оркестратор — чтобы задачи доходили до приёмки сами.
Предлагаемый путь: Фаза 0 (процесс, 1–2 недели, без кода) → Фаза 1 (MVP, 4–6 недель) → Фаза 2 (оркестратор и метрики, 3–4 недели) → Фаза 3 (contract-first пайплайн и авто-приёмка, 4 недели). Суммарно ~13–16 недель, состав — 2 инженера + 0.5 дизайнера + 0.5 аналитика, с человеком-владельцем на гейтах.
Пять агентов, пять рабочих директорий, пять представлений о проекте. Каждый из них технически прав в своём контексте — и потому все пятеро правы одновременно несовместимо.
Типовой сценарий, который повторяется на каждом проекте:
color.brand.primary → color.accent).Итог: 3 дня потеряно, из них 2 дня — не на продукт, а на согласование того, что считать правильным.
| Код | Причина | Механизм появления |
|---|---|---|
| C-1 | Пересечение зон ответственности | Два агента претендуют на один артефакт: «дизайн-токены» — зона дизайнера, но «цвет в теме» — это и SEO-бренд, и фронтенд |
| C-2 | Конфликт решений | Решение принято в переписке/в голове у одного агента, второй принял противоположное и не знает об этом |
| C-3 | Дрейф контекста | У каждого агента своя копия требований; к моменту работы они уже расходятся на 2–3 итерации |
| C-4 | Нарушение порядка | Реализация начата до того, как спецификация дизайна была зафиксирована; результат — переделка |
| C-5 | Дублирование | Никто не видит, что задача «собрать страницу X» уже висит у другого агента с другим acceptance criteria |
| C-6 | Тихий сбой | Агент упал или завис, handoff никто не принял, задача «в работе» неделю |
| Подход | Почему не закрывает задачу |
|---|---|
| Один большой промпт / супер-агент | Конфликты исчезают, но теряется специализация: один контекст на 500K токенов, деградация качества, невозможность менять одного участника |
| Общий чат / Telegram-группа | Нет прав, нет состояния, нет трассировки. История растёт, но не читается агентом. Разбор конфликта — вручную, каждый раз заново |
| Git + PR как система координации | Работает для кода, но не для дизайн-токенов, семантики, структуры IA и требований. PR на токены — это merge-конфликт, который невозможно разрешить осмысленно |
| Один оркестратор-промпт | Оркестратор сам становится точкой отказа и не может разрешить конфликт между двумя под-агентами, у которых нет доступа к общему состоянию |
| Просто «добавить больше инструкций» | Инструкции не хранят состояние. Конфликт требует проверяемого арбитра, а не напоминания |
> Платформа считается работающей, если конфликт между агентами обнаруживается системой до того, как он приведёт к переделке, и разрешается без участия человека в не менее чем 70% случаев, а человек вмешивается только в спорные продуктовые решения.
RELAY — coordination layer, слой координации. Он располагается между «мышью агента» (его LLM-контекстом) и «телом агента» (файлы, git, браузер, MCP-инструменты, внешние API).
┌──────────────────────────────────────────────────────────────┐
│ АГЕНТЫ (подменяемые) │
│ Product/UX · Design · Fullstack · SEO/Research · QA/Verifier │
└───────────────┬──────────────────────────────────────────────┘
│ через единый Agent Adapter Interface (MCP/CLI/HTTP)
┌───────────────▼──────────────────────────────────────────────┘
│ RELAY — слой координации │
│ Контракт · Доска · Артефакты · Handoff · Конфликты · ADR │
└───────────────┬──────────────────────────────────────────────┘
│
┌───────────────▼──────────────────────────────────────────────┐
│ ИНФРАСТРУКТУРА │
│ Postgres · Redis · S3 · Docker-sandbox · Git · OTel │
└──────────────────────────────────────────────────────────────┘Ключевое свойство: агентов можно заменять (Claude Code, Codex, Gemini CLI, MiniMax, любая модель через API) — RELAY держит протокол, а не конкретного исполнителя.
Версионируемый артефакт, который читается каждым агентом перед началом каждой задачи и на который ссылаются все решения.
# .relay/contract.yaml (версионируется в git, как и код)
version: 7
project: "Sales Travel — платформа бронирования"
goal: "Снизить долю отказов на шаге оплаты на 30% за спринт"
non_goals: ["Рефакторинг биллинга", "Новая партнёрская интеграция"]
stack:
frontend: "Next.js 15 / React 19 / TS"
backend: "Node 22 / Fastify / Postgres 16"
design_system: "Tokens v3 (design/figma-export)"
metrics:
- { name: "LCP", target: "< 2.0s", owner: agent:fullstack }
- { name: "SEO-трафик по семантике", target: "+25% Q", owner: agent:seo }
ownership:
zone:design-tokens -> agent:design
zone:component-lib -> agent:fullstack # по контракту, не по факту
zone:semantics -> agent:seo
zone:copy -> agent:product
definition_of_done:
- task_type: code
checks: ["tsc --noEmit", "unit >= 80%", "no a11y violations", "bundle -15% vs baseline"]
- task_type: design
checks: ["tokens синхронизированы", "a11y contrast AA", "dark theme variant"]Механика защиты: любой агент, предлагающий работу, обязан сослаться на zone: из контракта. Если зона не определена — работа не может быть взята в работу: сначала расширение контракта, потом реализация. Это превращает «пересечение зон» из конфликта в задачу.
Состояния: backlog → ready → in_progress → review → blocked → done.
Ключевые ограничения (это и есть «дисциплина экипажа»):
in_progress, пока все зависимости не в done.Каждый значимый результат работы агента — артефакт с версией, а не «сообщение в чат».
Типы артефактов: design-token, component-spec, screen-mock, api-schema, db-migration, seo-map, content-brief, adr, test-suite, analysis-report.
У каждого артефакта есть интерфейс потребления — то, что читает следующий агент:
{
"artifact": "design-token",
"name": "color.brand.primary",
"version": 12,
"contract": "alias -> {palette.600}; consumers: [Button, Link, Badge]",
"consumed_by": ["component-lib", "marketing-site"],
"breaking": false
}Handoff Packet — формат передачи работы (это то, что сегодня теряется):
task: TASK-142 "Собрать страницу результатов поиска" from: agent:design to: agent:fullstack status: handoff done: - "Экран в 3 брейкпоинтах, токены из контракта v7" - "Компонент SearchResultCard — контракт props зафиксирован" not_done: - "Адаптив до 360px — не успел, нужен отдельный тикет" changed: - "tokens: color.brand.primary переименован (v12, non-breaking)" risks: - "SEO-агент может потребовать другой H1 — проверить перед вёрсткой" requires_from_receiver: - "Подтвердить контракт props SearchResultCard" questions: - "Брать ли мобильную раскладку отдельной задачей или здесь?"
Приёмка — формальная. Получатель обязан прогнать DoD-проверки (для кода — tsc/тесты/a11y, для дизайна — сверка токенов и контраст) и выдать вердикт: accept / accept-with-comments / reject. Reject требует обоснования, и задача возвращается в очередь с сохранением истории.
Шесть детекторов, каждый со своим авто-разрешением или эскалацией:
| ID | Детектор | Что видит | Авто-разрешение | Иначе |
|---|---|---|---|---|
| D-1 | Пересечение claim | Два агента держат claim на пересекающиеся артефакты | Более ранний claim побеждает, второй получает conflict.claim_overlap | Эскалация → менеджер зоны |
| D-2 | Нарушение контракта | Работа вне своей зоны / нарушение non_goals | Claim отклоняется, задача возвращается в ready | Эскалация → Product-агент |
| D-3 | Конфликт решений | Новый ADR противоречит принятому (не supersede-ит) | Новое решение помечается conflict.decision | Эскалация → человек, если веса ролей равны |
| D-4 | Устаревшая зависимость | Задача опирается на артефакт ниже текущей версии | Задача блокируется до rebase/re-acknowledge | Автопересчёт затронутых задач |
| D-5 | Дублирование работы | Две задачи с одинаковым выходом (похожий intent + зона) | Вторая задача помечается duplicate_candidate | Эскалация → Product-агент объединяет |
| D-6 | Тихий сбой / потерянный handoff | Handoff не принят > SLA; агент молчит > N минут | Переназначение на другого агента той же зоны | Эскалация → оркестратор |
Протокол разрешения (единый для всех типов):
DETECT → CLASSIFY → [AUTO-RESOLVE | ESCALATE] → RESOLVE → LOG → PREVENT
PREVENT — обязательный шаг: каждое разрешение конфликта порождает изменение в контракте, правиле зоны или шаблоне handoff. Иначе конфликт повторится. Это превращает платформу из «пожарной команды» в систему с обучающейся памятью.
Арбитраж по приоритету источников истины (важно, когда доходит до человека):
Журнал решений (ADR). Кто, когда, что решил, почему, какие альтернативы, статус (proposed / accepted / superseded). Агенты спорят не по памяти и не по чату, а по фактам из лога. Любой новый ADR, противоречащий существующему, автоматически поднимает D-3.
Общий контекст (Context Pack). Перед началом задачи агент получает сборку: цель проекта, релевантные решения, текущие версии зависимых артефактов, критерии приёмки, ограничения зоны. Это дешёвый способ убить C-3 (дрейф контекста).
Оркестратор (Conductor). Автоматически: декомпозиция цели → граф задач с зависимостями → распределение по зонам → запуск пайплайнов → эскалация по SLA → сборка Handoff-пакетов. Он не делает предметную работу, он управляет потоком. Человек контролирует его через гейты.
Гейты человека (Human Gate). Точки обязательного подтверждения: смена владельца зоны, конфликт равновесных ролей, изменение контракта (цели/non_goals), финальная приёмка релиза, любой шаг с превышением бюджета токенов.
Верификатор (отдельный агент). Агент-приёмщик не может быть автором проверяемой работы. Это устраняет главный источник «зелёных» но некачественных задач.
| # | Роль | Зона по умолчанию | Что производит | Не имеет права |
|---|---|---|---|---|
| 1 | Product / UX Strategy | zone:requirements, zone:copy, zone:priority | Требования, декомпозиция целей, критерии приёмки, IA-карта | Менять дизайн-систему и код |
| 2 | UI/UX Design | zone:design-tokens, zone:components-spec, zone:mockups | Дизайн-система, токены, спеки компонентов, макеты | Править production-код |
| 3 | Fullstack Engineering | zone:app-code, zone:api, zone:db | Код, API, миграции, интеграции, тесты | Менять токены без handoff от дизайна |
| 4 | SEO / Research | zone:semantics, zone:analytics, zone:content | Семантика, карта ключей, аудит, контент-план, технические SEO-рекомендации | Менять разметку разметку/шаблоны напрямую — только через заявку |
| 5 | QA / Verifier | zone:acceptance | Приёмка по DoD, регрессия, отчёт о дефектах | Менять артефакты в зонах других ролей |
| — | Человек (Owner) | — | Гейты, спорные решения, бюджет, релизы | — |
Пять проектных ролей распределяются между тремя физическими инструментами. Один инструмент может держать несколько ролей — но решает он их по-разному, и это отражается в профиле прогона.
| Проектная роль | Кто играет | Инструмент | Как именно |
|---|---|---|---|
| Реализация, рефакторинг, многофайловые изменения | Основной исполнитель | Claude Code | CLI headless + MCP, свой worktree |
| Альтернативная реализация, тесты, edge-cases, ревью диффа | Второй исполнитель и ревьюер | ChatGPT (Codex) | codex exec в отдельном worktree |
| Исследование, семантика, внешний контекст, проверка гипотез | Исследователь | Grok | xAI API + web search, код не пишет |
| Требования, критерии приёмки, приоритеты | Product / ведущий | Человек (или Claude Code в режиме plan) | Решения фиксируются как ADR |
| Приёмка по DoD, регрессия | Верификатор | Claude Code в отдельном прогоне + проверки в CI | Прогон-верификатор ≠ прогон-автор |
> Практическое следствие: Judge не может быть автором. Если Claude Code написал код, судьёй этого прогона выступает отдельный запуск другого инструмента или человек. Это дешевле, чем кажется, и снимает главный источник «зелёного, но некачественного» результата.
R — исполнитель, A — ответственный (один), C — консультирует, I — информируется.
| Актив | Product | Design | Eng | SEO | QA | Человек |
|---|---|---|---|---|---|---|
| Требования и приоритеты | A/R | C | C | C | I | A |
| Дизайн-система и токены | C | A/R | C | I | C | I |
| Компонентные спеки | C | A/R | C | — | C | I |
| Код приложения и API | C | I | A/R | — | C | I |
| Семантика и контент-план | C | I | I | A/R | I | A |
| Приёмка и регрессия | C | C | C | C | A/R | I |
| Изменение целей и non_goals | R | C | C | C | I | A |
| Релиз | R | I | R | I | R | A |
Зона закреплена за одним агентом в контракте. Это означает:
change_request) владельцу зоны.Это превращает «конфликт» в очевидный, отслеживаемый, SLA-ограниченный поток. Конфликтующих действий просто не может произойти, если агент работает через RELAY.
relay.codes — это агрегатор. Его центральный сценарий: человек ставит одну задачу, а платформа сама разбирает её на параллельные прогоны Claude Code, ChatGPT (Codex) и Grok, проверяет каждый результат, сводит их в один артефакт и отдаёт на ревью как единый PR с историей происхождения каждой изменённой строки.
Ключевое отличие от «попросить три модели одно и то же и взять лучший ответ»: агенты получают разные подзадачи и разные перспективы, работают в изолированных рабочих копиях, и сведение происходит на уровне диффов, а не на уровне текста.
одна задача от человека
│
┌────────▼─────────┐
│ Planner (fan-out)│ задача → 3 разных подзадачи + критерии
└────────┬─────────┘
┌───────────┼───────────┐
┌────▼─────┐┌────▼─────┐┌────▼─────┐
│Claude Code││ChatGPT ││ Grok │ изолированные worktree + контейнер
│исполнитель││(Codex) ││исследоват.│
└────┬─────┘└────┬─────┘└────┬─────┘
│ DoD-гейт │ DoD-гейт │ только факты
┌────▼─────┐┌────▼─────┐└──────────┘
│ diff ✓ ││ diff ✓ │
└────┬─────┘└────┬─────┘
└──────┬──────┘
┌──────▼───────┐
│ Сведение и │ disjoint → merge · пересечение → Judge
│ арбитраж │
└──────┬───────┘
┌──────▼───────┐
│ ОДИН PR │ + отчёт: что от кого, что отклонено и почему
└──────────────┘| Инструмент | Режим подключения | Роль в прогоне | Чего не делает | Что отдаёт |
|---|---|---|---|---|
| Claude Code | CLI в headless-режиме (claude -p), MCP-инструменты, потоковый JSON | Основной исполнитель: многофайловые изменения, рефакторинг, реализация по спеке, работа с репозиторием | Не принимает финальные решения по чужим прогонам | Diff, коммиты, артефакты, отчёт по DoD |
| ChatGPT (Codex) | CLI codex exec (non-interactive), JSONL-события | Второй исполнитель и ревьюер: альтернативная реализация, тесты и edge-cases, разбор диффа, поиск дыр | Не дублирует Claude Code дословно — иначе это просто двойной расход | Diff, тесты, замечания, patch-подсказки |
| Grok | xAI API (OpenAI-совместимый endpoint) + web search | Исследователь: актуальность предметной области, рынок, конкуренты, SEO-семантика, проверка гипотез, свежая документация | Код по умолчанию не пишет — возвращает факты и рекомендации | Отчёт с фактами, ссылками, SEO-рекомендациями |
Правило разведения ролей. Три агента получают не одинаковый промпт. Планировщик строит три разных подзадачи:
Если все три получают один и тот же промпт — это не агрегация, а тройной расход токенов. Это прямое требование к Planner'у.
| # | Шаг | Что делает RELAY | Провалится, если |
|---|---|---|---|
| 1 | Intake | Принимает задачу от человека, требует acceptance criteria и зону | Нет критериев приёмки → задача не создаётся |
| 2 | Decompose | Planner строит 3 разных подзадачи, схему зависимостей, DoD-чек-лист | Подзадачи дублируют друг друга → возврат планировщику |
| 3 | Prepare | Создаёт 3 изолированных окружения: git worktree + ветка + контейнер + лимиты (время, токены) | Нет свободного worktree или превышен лимит стоимости |
| 4 | Run | Запускает 3 прогона параллельно, пишет heartbeat, следит за lease | Агент молчит → детектор D-6, переназначение или эскалация |
| 5 | Verify | Прогоняет DoD-гейт на каждом прогоне: тесты, типы, линт, a11y, перф-бюджет | Провал гейта → прогон не идёт в сведение, а помечается rejected_by_gates |
| 6 | Diff-arbitration | Сравнивает диффы трёх прогонов: пересечение по файлам, хункам и строкам | Семантический конфликт → Judge |
| 7 | Merge | Сводит прогоны по политике сведения (§5.4) | Все три разошлись и Judge не разрешил → человеку |
| 8 | Publish | Отдаёт один PR: сводный дифф, отчёт о происхождении строк, ADR решения, журнал проверок | — |
Сведение идёт по правилам, а не по вкусу. Каждая ситуация имеет однозначное поведение:
| Ситуация | Решение | Автоматически |
|---|---|---|
| Диффы не пересекаются (разные файлы) | git merge обоих в сводную ветку | Да |
| Один файл, разные хунки | 3-way merge, конфликтные маркеры не возникают | Да |
| Один файл, одни и те же строки, разный смысл | Семантический конфликт → Judge получает оба варианта + критерии | Нет |
| Grok вернул только факты и рекомендации | Факты → в отчёт и ADR, код не трогаем | Да |
| Все три пришли к одинаковому результату | Consensus: доверие высокое, берётся вариант Claude Code как основной, остальные подтверждают | Да |
| Ровно два сошлись, третий расходится | Берётся consensus-вариант, расхождение → в отчёт как «предложено к пересмотру» | Да |
| Все три разошлись | Judge → 3 готовых варианта человеку | Нет |
| Прогон не прошёл DoD-гейт | Исключается из сведения, причина в отчёте | Да |
Правило приоритета при равных условиях: Claude Code — основной исполнитель (его дифф базовый), ChatGPT/Codex — дополнения поверх (тесты, edge-cases), Grok — только информация. Это дефолт, который переопределяется решениями в ADR.
Все три инструмента приводятся к общему контракту — именно это делает их взаимозаменяемыми и сопоставимыми:
run_id: RUN-4471
task: TASK-201
agent: claude-code
role: implementer
branch: relay/TASK-201/claude-code
context_pack_ref: CP-889 # что агент видел на входе
files_touched: [src/features/search/SearchCard.tsx, src/features/search/page.tsx]
diff:
insertions: 18
deletions: 4
files: 2
artifacts: [artifact/component-spec#v7]
checks:
- { name: "tsc --noEmit", result: pass }
- { name: "unit >= 80%", result: pass, value: "86%" }
- { name: "a11y violations", result: pass, value: 0 }
cost: { tokens: 84_200, duration_s: 411, usd: 1.42 }
verdict: eligible # eligible | rejected_by_gates | failed
notes: "..."Отдельный агент, который не был автором ни одного из трёх прогонов:
Судья — это узкое место, поэтому он включается только на семантических конфликтах, а не на каждой задаче.
| Метрика агрегатора | Один агент | Три агента через RELAY |
|---|---|---|
| Вероятность, что задача закрыта с первого PR | базовая | +25–35 п.п. за счёт тестов второго исполнителя и edge-cases |
| Доля задач, требующих переделки | базовая | −30–40% за счёт слияния на уровне диффов |
| Стоимость одной задачи (токены) | 1× | 2,5–3× (платим за параллельность) |
| Время цикла задачи | 1× | ≈ 0,8× (параллельность компенсирует тройной расход) |
Плата за параллельность — тройной расход токенов. Экономика работает только потому, что переделки и отказы на ревью сегодня стоят дороже: в агрегаторе выигрыш приходит из меньшего числа итераций, а не из меньшего числа вызовов. Бюджет ограничивается лимитом на задачу в cost ledger.
| Риск | Мера |
|---|---|
| Три одинаковых промпта → тройной расход без выигрыша | Planner обязан давать разные перспективы; детектор дублирования подзадач блокирует запуск |
| Разный стиль кода у трёх авторов | Формат и линтер-гейт до сведения; слияние только по пройденным гейтам |
| «Лучший из трёх» не выбирается | Judge по критериям, а не по вкусу; при равенстве — человеку с тремя готовыми вариантами |
| Тройной расход токенов | Лимиты на задачу и на проект в cost ledger, предупреждение на 80%, пауза на 100% |
| Промпт-инъекция из веба (особенно Grok) | Внешние выдержки идут в отдельный канал «данные», не в инструкции; агенту запрещено выполнять команды из источников |
| Один агент «плохо спит» и портит общий результат | Изоляция worktree + DoD-гейт + автоматическое исключение провалившегося из сведения |
| Слой | Компоненты | Ответственность |
|---|---|---|
| Interface | Web App (доска, артефакты, решения, метрики), Agent CLI (relay task claim), MCP-сервер RELAY, WebSocket/SSE-стрим событий | Точка входа для человека и агентов |
| Coordination | Task Service, Artifact Service, Handoff Service, Conflict Engine, Decision Service, Contract Service, Gate Service, Orchestrator | Ядро: состояние, правила, переходы |
| Intelligence | Context Pack Builder, Impact Analyzer, Similarity/Duplicate Detector, Verifier Runner, Cost/Ledger Analyzer | Производные вычисления и автоматизация |
| Integration | Agent Adapters (Claude Code / Codex / Gemini CLI / MiniMax / OpenAI API), Git Provider, Browser/MCP tools, SEO tools, Sandbox Runner | Связь с внешним миром |
| Infrastructure | Postgres 16 + pgvector, Redis 7, BullMQ, S3/MinIO, Docker sandbox, OpenTelemetry, Git | Хранение, очереди, изоляция, наблюдаемость |
| Решение | Обоснование |
|---|---|
| Событийная модель (event log) | Каждый переход состояния — событие в events. Это даёт: аудит, воспроизведение, повторную обработку, построение метрик без отдельного пайплайна |
| Claim = lease с TTL | Claim не бессрочен. Истёкший TTL освобождает артефакт — «забытый» артефакт не блокирует проект навсегда (и это отдельный детектор D-6) |
| Версионирование артефактов + impact-граф | При bump версии артефакта RELAY считает потребителей и автоматически помечает их задачи как требующие re-acknowledge. Это механическая защита от C-4 |
| Contract-first для дизайн→код | Токены и пропсы компонентов публикуются как схемы (JSON Schema). Инженер генерирует типы и стабы из схемы, а не из скриншота. Пропс-дрифт становится ошибкой компиляции, а не сюрпризом на ревью |
| Sandbox исполнения | Код, сгенерированный агентом, исполняется в изолированном контейнере без доступа к сети и секретам (кроме allowlist) |
| Один оркестратор, но решения — за людьми | Оркестратор оптимизирует поток, но не имеет права менять цели. Гейты — единственный путь изменения контракта |
| Полный аудит и cost ledger | Каждый запуск агента фиксируется: токены, стоимость, время, что сделано. Это делает «почему мы потратили 40k токенов» вопросом с ответом |
Единый Agent Adapter Interface — агенты подключаются как «исполнители с входом и выходом», а не как «чат-боты»:
interface AgentAdapter {
capabilities(): Capability[] // design | code | research | verify | plan
run(task: TaskEnvelope): RunHandle // получает Context Pack + Task
report(run: RunHandle): RunReport // что сделано / не сделано / риски
}TaskEnvelope = { contract_snapshot, context_pack, task, acceptance_checks, zone, deadline, budget }.
Поддерживаемые адаптеры по приоритету: CLI-адаптеры (Claude Code, Codex, Gemini CLI — самые зрелые, умеют работать с файлами и MCP), API-адаптеры (любая модель через OpenAI-совместимый API), MCP-адаптер (агент сам ходит в RELAY за задачами — pull-модель).
Pull-модель рекомендуется для основного потока: агент сам забирает доступные ему задачи (relay pull --agent design --zone design-tokens). Это снимает проблему «оркестратор не знает, что агент умеет» и позволяет масштабировать экипаж горизонтально.
projects ──1:N── contracts ──1:N── contract_versions │ │ ├──1:N── tasks ──1:N── task_deps │ (zones, ownership, DoD) │ │ └──N:1── agents │ └──1:N── handoffs ──1:N── handoff_events (verdicts) │ └──1:N── claims (lease+TTL) ├──1:N── artifacts ──1:N── artifact_versions ──1:N── artifact_deps ├──1:N── decisions (ADR) ──1:N── decision_links ├──1:N── conflicts ──1:N── conflict_events ──N:1── resolution ├──1:N── gates (human approvals) ├──1:N── agent_runs ──1:N── cost_entries └──1:N── events (append-only audit log)
CREATE TABLE tasks ( id uuid PRIMARY KEY, project_id uuid NOT NULL REFERENCES projects(id), title text NOT NULL, intent text NOT NULL, -- для детекта дубликатов (D-5) task_type text NOT NULL, -- design | code | seo | content | plan | verify zone text NOT NULL, -- зона по контракту owner_agent_id uuid REFERENCES agents(id), state text NOT NULL, -- backlog|ready|in_progress|review|blocked|done priority int NOT NULL DEFAULT 100, -- меньше = выше acceptance jsonb NOT NULL, -- acceptance criteria (DoD-ссылка + чеклист) contract_version int NOT NULL, -- снимок контракта на момент взятия blocked_by uuid REFERENCES conflicts(id), created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), CONSTRAINT tasks_need_acceptance CHECK (jsonb_array_length(acceptance) > 0) ); CREATE TABLE claims ( id uuid PRIMARY KEY, task_id uuid NOT NULL REFERENCES tasks(id), agent_id uuid NOT NULL REFERENCES agents(id), artifact_id uuid REFERENCES artifacts(id), lease_until timestamptz NOT NULL, -- TTL; истечение → авто-освобождение acquired_at timestamptz NOT NULL DEFAULT now(), UNIQUE (artifact_id, agent_id) WHERE artifact_id IS NOT NULL ); CREATE TABLE artifacts ( id uuid PRIMARY KEY, project_id uuid NOT NULL REFERENCES projects(id), kind text NOT NULL, -- design-token|component-spec|api-schema|seo-map|... key text NOT NULL, -- человекочитаемый путь, напр. color.brand.primary owner_agent_id uuid REFERENCES agents(id), zone text NOT NULL, current_version int NOT NULL DEFAULT 1, consumer_contract jsonb, -- схема потребления (JSON Schema) UNIQUE (project_id, key) ); CREATE TABLE artifact_versions ( id uuid PRIMARY KEY, artifact_id uuid NOT NULL REFERENCES artifacts(id), version int NOT NULL, payload jsonb NOT NULL, breaking boolean NOT NULL DEFAULT false, author_agent_id uuid NOT NULL REFERENCES agents(id), reason text NOT NULL, created_at timestamptz NOT NULL DEFAULT now(), UNIQUE (artifact_id, version) ); CREATE TABLE handoffs ( id uuid PRIMARY KEY, task_id uuid NOT NULL REFERENCES tasks(id), from_agent_id uuid NOT NULL, to_agent_id uuid NOT NULL, packet jsonb NOT NULL, -- Handoff Packet state text NOT NULL, -- proposed|accepted|rejected|superseded verdict text, -- accept|accept_with_comments|reject verdict_notes text, sla_until timestamptz NOT NULL, created_at timestamptz NOT NULL DEFAULT now() ); CREATE TABLE decisions ( id uuid PRIMARY KEY, project_id uuid NOT NULL REFERENCES projects(id), title text NOT NULL, context text NOT NULL, decision text NOT NULL, alternatives jsonb NOT NULL, status text NOT NULL, -- proposed|accepted|superseded|rejected supersedes uuid REFERENCES decisions(id), author_agent_id uuid NOT NULL, decided_by uuid REFERENCES agents(id), -- человек, если эскалация created_at timestamptz NOT NULL DEFAULT now() ); CREATE TABLE conflicts ( id uuid PRIMARY KEY, project_id uuid NOT NULL REFERENCES projects(id), type text NOT NULL, -- claim_overlap|contract_violation|decision_conflict|stale_dep|duplicate|silent_failure severity text NOT NULL, -- blocker|major|minor state text NOT NULL, -- open|auto_resolved|escalated|resolved subject jsonb NOT NULL, -- что именно конфликтует options jsonb, -- готовые варианты для человека resolution jsonb, detected_at timestamptz NOT NULL DEFAULT now() );
Полная схема (+ events, gates, agent_runs, cost_entries, context_packs, task_deps, artifact_deps) — в Приложении B.
tasks(project_id, state, owner_agent_id) — основная выборка доски.tasks USING gin (intent gin_trgm_ops) — триграммный индекс для D-5 (поиск дубликатов).artifact_versions(artifact_id, version DESC) — быстрый расчёт impact.events(project_id, created_at DESC) — лента активности и replay.pgvector — по context_packs и по тексту решений/требований (семантический поиск).REST + WebSocket. REST — для команд и чтения; WS — для живого обновления доски и событий.
POST /api/projects создать проект GET /api/projects/:id сводка: состояние, здоровье, метрики GET /api/projects/:id/contract текущая версия контракта POST /api/projects/:id/contract/versions предложить новую версию (→ gate) GET /api/projects/:id/contract/diff дифф между версиями
GET /api/tasks?project=&state=&zone=&owner=&blocked= POST /api/tasks создать (валидация зоны + acceptance) GET /api/tasks/:id PATCH /api/tasks/:id title/intent/priority/acceptance POST /api/tasks/:id/claim взять с lease (WIP-check → 409 при превышении) POST /api/tasks/:id/release освободить claim POST /api/tasks/:id/state переход состояния (валидация переходов) GET /api/tasks/:id/context-pack сборка контекста для агента
GET /api/artifacts?project=&zone=&kind= POST /api/artifacts создать артефакт GET /api/artifacts/:id/versions POST /api/artifacts/:id/versions bump версии → impact-анализ GET /api/artifacts/:id/impact кто затронут, что заблокировано POST /api/tasks/:id/handoff сформировать Handoff Packet POST /api/handoffs/:id/verdict accept | accept_with_comments | reject
GET /api/decisions?project=&status=&topic= POST /api/decisions предложить ADR POST /api/decisions/:id/accept|supersede GET /api/conflicts?project=&state=&type= POST /api/conflicts/:id/resolve ручное разрешение POST /api/conflicts/:id/escalate → гейт человеку
GET /api/gates?project=&state= очередь на решения человека POST /api/gates/:id/approve|reject GET /api/agents?project=&state= статус агентов, текущая нагрузка GET /api/agents/:id/runs запуски, стоимость, результат GET /api/metrics/project/:id KPI дашборда GET /api/events?project=&since= append-only лента (audit + replay)
/streamСобытия: task.created, task.claimed, task.state_changed, handoff.proposed, handoff.verdict, conflict.detected, conflict.resolved, artifact.version_bumped, gate.raised, agent.run_finished, metric.updated.
relay pull --agent <id> --zone <zone> взять доступную задачу (pull-модель) relay report --task <id> --packet <file> сдать Handoff Packet relay heartbeat --task <id> продлить lease relay ask-context --task <id> получить Context Pack
backlog ──(product/plan)──► ready ──(claim)──► in_progress ──(self-check)──► review
│ │
│◄──────(blocked: конфликт/зависимость)──────┤
│ │
│ ▼
└────────(reject + обоснование)────────── doneПравила переходов:
ready → in_progress: требуется acceptance непустой, claim выдан, все зависимости done, зона соответствует контракту, WIP не превышен.in_progress → review: исполнитель приложил Handoff Packet и результат проверок.review → done: только вердикт верификатора/владельца зоны. Автопереход запрещён.review → in_progress: reject с обоснованием, задача возвращается с сохранением истории.not_done при отсутствии рисков — норма, но done без единого пункта — ошибка валидации.reject без ссылок на нарушенные критерии не принимается системой.superseded, но остаётся в истории.design-token/component-spec/api-schema требует bump версии и указания причины.breaking = true (переименование, удаление, изменение типа) → автоматически: зависимые задачи помечаются requires_reacknowledge, затронутые handoff-пакеты помечаются stale.Цель: «Падение конверсии на шаге оплаты, нужно понять и починить».
| Шаг | Кто | Что происходит в RELAY |
|---|---|---|
| 1 | Product | Декомпозирует цель → 5 задач с зависимостями, acceptance criteria, зонами. Задача «Собрать воронку платежа» → ready |
| 2 | SEO | Берёт задачу «аудит аналитики воронки». Claim на артефакт analytics/pay-funnel (lease 2 ч). В конце — Handoff: «воронка теряет 22% на шаге ввода карты; поле требует 6 цифр на десктопе, 4 на мобиле» |
| 3 | Design | Берёт задачу «редизайн поля карты». Читает Handoff, берёт claim на design/pay-form + token/form-field. Делает макет, публикует версию артефакта с consumer_contract (props, states, токены) |
| 4 | — | Версия токена бампается: RELAY считает impact → 9 компонентов зависят от token/form-field, 2 задачи в review → помечаются requires_reacknowledge, в чат агентов уходит уведомление |
| 5 | Eng | Берёт задачу «реализация поля карты». Context Pack содержит: контракт v7, ADR-014 (формат поля), схема props из шага 3, DoD. Код генерируется из схемы, типы — из JSON Schema |
| 6 | QA | Задача «проверка формы». Запускает DoD-чеки в sandbox: unit-тесты, a11y (contrast/focus/labels), bundle-размер, визуальная регрессия по токенам |
| 7 | Eng | Отдаёт Handoff: сделано / не сделано (3D Secure — отдельная задача) / изменено (высота поля +4px) / риски |
| 8 | QA | Вердикт: accept_with_comments — 1 замечание (фокус-кольцо), 1 мелкий баг. Задача → done с 1 комментарием, замечание → отдельная задача |
| 9 | Product | Задача закрыта. ADR-015: «поле карты принимает 16 цифр с автопробелами» — принято. Всё зафиксировано |
Что предотвратил RELAY на этом сценарии: дизайн не пошёл в код без спецификации (шаг 4→5), код не был написан по устаревшим токенам (impact-анализ), SEO не потерял выводы (Handoff вместо «посмотрел и забыл»), приёмка не была на глаз (DoD-чеки в sandbox).
Цель: снизить конфликты до появления системы. Даёт эффект немедленно и снижает риск Фазы 1 (платформа будет строить под реальный процесс, а не под выдуманный).
contract.yaml под 2–3 текущих проектаРезультат фазы: измеримый baseline и работающий процесс, который RELAY затем автоматизирует.
Цель: закрыть 4 из 6 корневых причин.
| # | Подсистема | Содержание | Неделя |
|---|---|---|---|
| 1.1 | Contract Service | Версионирование контракта, зоны, DoD, проверка задач на соответствие | 1–2 |
| 1.2 | Task Service + Board UI | Задачи, состояния, зависимости, WIP-лимиты, claim/lease | 2–3 |
| 1.3 | Artifact Registry | Артефакты, версии, impact-граф, consumer_contract | 3–4 |
| 1.4 | Handoff Service | Пакеты, SLA, вердикты, приёмка по DoD | 4 |
| 1.5 | Decision Service (ADR) | Создание, принятие, supersede, детект D-3 | 4–5 |
| 1.6 | Conflict Engine (D-1, D-2, D-4, D-5) | Детекторы + авто-разрешение + эскалация | 5–6 |
| 1.7 | Agent CLI (pull/report) | Минимальный клиент для агентов | 5–6 |
| 1.8 | Adapters инструментов | Claude Code (headless CLI), ChatGPT/Codex (codex exec), Grok (xAI API + web search) → единый контракт RunResult | 3–5 |
| 1.9 | Fan-out Planner | Одна задача → 3 разные подзадачи + DoD-чек-лист; детектор дублирования подзадач | 4–6 |
| 1.10 | Изоляция прогонов | Git worktree + ветка + контейнер на каждый прогон, лимиты времени и токенов | 4–5 |
| 1.11 | Diff-arbitration + сведение | Сравнение диффов (файл / хунк / строка), merge-политика, Judge, единый PR с отчётом о происхождении строк | 5–7 |
| 1.12 | Базовый дашборд | Доска, артефакты, решения, конфликты, активность, экран агрегации | 6–7 |
Критерии готовности Фазы 1 — раздел 12. Фаза 1 в агрегаторном виде = одна задача → 3 параллельных прогона (Claude Code, ChatGPT/Codex, Grok) → один PR.
consumer_contract артефактов| Роль | Загрузка | Период |
|---|---|---|
| Backend/Platform engineer | 1.0 FTE | Фазы 1–3 |
| Fullstack engineer | 1.0 FTE | Фазы 1–2, 0.5 — Фаза 3 |
| Product designer | 0.5 FTE | Фаза 1 (Board UI + дизайн-система RELAY), далее по 0.25 |
| Tech lead / архитектор | 0.3 FTE | все фазы + human gate |
| QA | 0.25 FTE | с Фазы 1.6 |
Инфраструктура (оценка, на 1 проект): Postgres + Redis на существующем VPS ≈ $60–90/мес; объектное хранилище ≈ $10–20/мес; sandbox-раннеры ≈ $80–150/мес (спотовые); LLM-бюджет агентов — считается отдельно по ledger'у (ожидаемое снижение переделок компенсирует 15–25% роста прямых вызовов).
Итого: 13–16 недель, ≈ 24–28 человеко-недель, инфраструктура ~$150–260/мес.
MVP считается готовым, если одновременно:
relay pull) и сдать результат Handoff-пакетом (relay report), не участвуя в чате.reject без ссылки на нарушенный критерий отклоняется валидатором.| Метрика | Сейчас (baseline, Фаза 0) | MVP | Целевое (Фаза 3) |
|---|---|---|---|
| Конфликты, закрытые без человека | — | ≥ 60% | ≥ 85% |
| MTTR конфликта | — | < 30 мин | < 15 мин |
| First-Pass Acceptance (handoff без reject) | — | ≥ 65% | ≥ 80% |
| Rework Rate (переделки из-за рассинхрона) | baseline | −25% | −50% |
| Задачи, взятые вне зоны | — | 0 (блокируется) | 0 |
| Стоимость задачи (токены) | baseline | визуализация | −20% при росте объёма |
| Lead time goal → done | baseline | −15% | −35% |
| Доля знаний, найденных в Decision Log за < 2 мин | — | — | 90% |
Baseline обязателен до старта Фазы 1 — иначе эффект платформы невозможно доказать.
| # | Риск | Вероятность | Влияние | Мера |
|---|---|---|---|---|
| R-1 | Агенты продолжат работать «мимо платформы» (в обход CLI) | высокая | высокое | Pull-модель: агент берёт задачи только из RELAY; интеграция в MCP/промпт по умолчанию; метрика «% задач из RELAY» |
| R-2 | Порог входа (нужно описывать контракт, зоны, DoD) окажется слишком высоким | средняя | высокое | Шаблоны под 3 типа проектов; автогенерация контракта из существующей документации; Фаза 0 как «процессный» пилот |
| R-3 | RELAY станет новым бутылочным горлышком (очередь решений человека) | средняя | высокое | Авто-разрешение по правилам; человек видит только 2–3 варианта; SLA на гейты |
| R-4 | Формализация слишком жёсткая, скорость упадёт | средняя | среднее | «Мягкие» артефакты: контракт может быть частично неформальным; приоритет — не блокировать, а ускорять; метрика lead time как guardrail |
| R-5 | Плохая интеграция с конкретными агентами (CLI/API дрейф) | средняя | среднее | Адаптерный слой + контрактные тесты адаптеров; поддержка ≥ 3 агентов на старте |
| R-6 | Ложные срабатывания детекторов (особенно D-5 дубликаты) | высокая | среднее | Порог близости для D-5 настраиваемый; каждый авто-resolve пишет причину; регулярный тюнинг по логу |
| R-7 | Команда не перейдёт на новый процесс | средняя | высокое | RELAY = минимальное усилие: агент сам подтягивает контекст; человек не переписывает задачи, а подтверждает |
| R-8 | Безопасность: выполнение сгенерированного кода, секреты | низкая | высокое | Sandbox без сети по умолчанию, allowlist инструментов, секреты только через MCP-broker с аудитом, redacting логов |
| # | Вопрос | Рекомендация | Влияние |
|---|---|---|---|
| 1 | Где живёт репозиторий платформы — отдельный сервис или монорепо рядом с продуктом? | Отдельный сервис (self-hosted, Docker Compose) + тонкий CLI | Определяет эксплуатацию |
| 2 | Кто владелец продукта RELAY — вы лично или отдельный техлид? | Вы как владелец, техлид — исполнитель решений | Определяет, кто закрывает гейты |
| 3 | Область первого пилота: один реальный проект (например, sales.travel) или синтетический? | Реальный проект, ограниченный по объёму (1 фича-спринт) | Определяет риск и качество baseline |
| 4 | Человек в контуре: только гейты или также ежедневное участие в приёмке? | Только гейты + 1 разбор в день | Влияет на вашу нагрузку |
| 5 | Бюджет LLM на MVP | Отдельный лимит на RELAY-пилот: $300–500/мес на пилотный проект | Определяет, сколько задач прогоняем |
| 6 | Агенты-пилоты (какие подключаем первыми) | Product + Design + Fullstack; SEO подключаем в Фазе 2 | Определяет объём интеграций |
| 7 | Формат хранения артефактов | Git-репозиторий артефактов (дизайн-токены как JSON в репо) + RELAY как индекс | Влияет на аудит и diff |
| 8 | Горизонт: делаем MVP за 4–6 недель или сначала 2-недельный срез | 2-недельный срез (доска + контракт + handoff + ADR) → показ → полный MVP | Снижает риск большого проекта |
| 9 | Провайдеры и доступ: где лежат ключи к Claude Code, ChatGPT/Codex и Grok — у вас, у платформы или у команды? | Ключи платформы в secret-хранилище, доступ по проекту и лимиту; в репозитории — только идентификаторы | Определяет, как агрегатор запускает прогоны |
| 10 | Что делает Grok в коде: только исследование или тоже пишет код | По умолчанию не пишет: возвращает факты, SEO-семантику и рекомендации. Код — только по явному флагу | Снижает риск «трёх авторов одного файла» |
| 11 | Правило сведения по умолчанию: чей дифф базовый | Claude Code — базовый, ChatGPT/Codex — дополнения (тесты, edge-cases), Grok — информация. Переопределяется ADR | Определяет, как выглядит 90% слияний |
| 12 | Домен и эксплуатация: relay.codes уже зарегистрирован, но обслуживается сторонним парковщиком | Перевести NS на Cloudflare, привязать домен к платформе, TLS — через платформу | Определяет, кто отвечает за доступность |
| Термин | Значение |
|---|---|
| Контракт проекта | Версионируемая спецификация проекта: цели, границы, стек, зоны владения, DoD |
| Зона (zone) | Именованная область ответственности, закреплённая за одним агентом |
| Артефакт | Версионируемый результат работы агента с интерфейсом потребления |
| Handoff Packet | Формализованная передача результата от агента к агенту |
| Claim | Lease на задачу/артефакт с TTL, защищающий от двойной работы |
| ADR | Architecture/Product Decision Record — запись о принятом решении |
| Impact-граф | Связи «артефакт → потребители → задачи → handoff-пакеты» |
| WIP-лимит | Максимум одновременных задач у агента |
| Гейт | Точка обязательного человеческого подтверждения |
| PREVENT | Обязательный шаг разрешения конфликта: изменение правил, чтобы не повторилось |
Дополняет раздел 7.2: events, task_deps, artifact_deps, gates, agent_runs, cost_entries, context_packs, decision_links, artifact_consumers, notifications.
Готовится в Фазе 1; контракт зафиксирован в разделе 8.
Конец документа. Согласование: раздел 15.