Один агент упёрся в лимит, второй потерял контекст: как собрать команду Claude Code + Codex без ручных перезапусков
Я Denis Shokhirev, Agentic AI Systems Architect из Freiburg im Breisgau, Germany, и в DennisCraft AI Studio я собираю production-grade AI-системы для DACH B2B на стеке Claude, Supabase, n8n, Doppler и self-hosted Postgres. Самый неприятный сбой в агентной разработке выглядит не как падение сервера, а как тихий разрыв между двумя сильными моделями: Claude Code упёрся в лимит, Codex подхватил задачу, но уже без нужного контекста, и через 20 минут у вас конфликтующий patch, потерянный ход рассужден
Я Denis Shokhirev, Agentic AI Systems Architect из Freiburg im Breisgau, Germany, и в DennisCraft AI Studio я собираю production-grade AI-системы для DACH B2B на стеке Claude, Supabase, n8n, Doppler и self-hosted Postgres. Самый неприятный сбой в агентной разработке выглядит не как падение сервера, а как тихий разрыв между двумя сильными моделями: Claude Code упёрся в лимит, Codex подхватил задачу, но уже без нужного контекста, и через 20 минут у вас конфликтующий patch, потерянный ход рассуждений и ручной restart прямо посреди рабочего дня.
Эта проблема возникает не потому, что модели слабые. Наоборот: обе полезны, но у них разные режимы отказа. Если относиться к ним как к двум независимым помощникам в одном терминале, вы получаете хаос. Если относиться к ним как к команде с журналом состояния, контрактами на вход и выход и автоматическим оркестратором, ручные handoff почти исчезают.
Где ломается связка Claude Code + Codex
В production я вижу 3 повторяющихся сбоя. Первый: квоты и rate limits приходят в самый неподходящий момент, обычно на длинной задаче с несколькими файлами. Второй: агент продолжает работу после обрезки контекста и начинает уверенно переписывать уже принятые решения. Третий: новый агент получает только prompt, но не получает фактическое состояние проекта — какие файлы уже тронуты, какие тесты упали, какой security gate не пройден.
Почему простое "передай prompt дальше" не работает
Prompt не равен состоянию. Состояние — это commit SHA, список изменённых файлов, результаты semgrep, bandit и gitleaks, открытые TODO, текущая ветка, статус миграций Postgres и последнее решение по архитектуре. Пока это не записано явно, второй агент не продолжает работу, а реконструирует её наугад.
Anthropic в документации по tool use и structured outputs в 2024 году прямо показывает ценность структурированных ответов для автоматических workflows, а не только для диалога: docs.anthropic.com. В похожем ключе OpenAI Cookbook в 2024 году показывает паттерны orchestration и state passing между шагами, а не надежду на длинный chat history: cookbook.openai.com. Это ровно тот случай.
Правильная модель: не чат, а журнал состояния
Я не связываю Claude Code и Codex через "общую память" в абстрактном смысле. Я связываю их через внешний state store. На моём стеке это обычно Postgres или Supabase Postgres, а n8n исполняет простую логику оркестрации: создать задачу, назначить агента, получить артефакты, прогнать проверки, при сбое передать следующему агенту уже не prompt, а карточку состояния.
| Слой | Что хранить | Зачем это второму агенту |
|---|---|---|
| Task state | task_id, branch, commit_sha, goal, owner_agent | Понять, что именно продолжается |
| Execution log | команды, stderr/stdout, коды возврата | Не повторять уже провалившиеся шаги |
| Code artifacts | diff summary, changed_files, test results | Войти в задачу без сканирования всего репозитория |
| Risk gates | semgrep, bandit, gitleaks, manual review flag | Не протащить уязвимость при handoff |
Минимальный контракт handoff
У каждого агента должен быть фиксированный выходной формат. Не "опиши, что ты сделал", а JSON с обязательными полями. Если агент не может вернуть этот контракт, задача не передаётся дальше автоматически.
from pydantic import BaseModel
from typing import List, Literal
class HandoffState(BaseModel):
task_id: str
agent: Literal["claude_code", "codex"]
branch: str
commit_sha: str
changed_files: List[str]
test_status: Literal["passed", "failed", "not_run"]
security_status: Literal["passed", "failed", "not_run"]
next_action: str
blocker: str | None = None
Этот контракт кажется скучным, пока не случится первый аварийный переход между агентами в пятницу вечером. После этого скука становится достоинством.
Как убрать ручные restart через n8n и Postgres
Механика простая. Claude Code получает задачу на реализацию. Если он доходит до лимита, timeout или не проходит gate, n8n не шлёт человеку сообщение "перезапусти". Вместо этого workflow сохраняет handoff state в Postgres, переключает owner_agent на Codex и передаёт только task_id. Codex сначала читает состояние, а уже потом открывает репозиторий и продолжает с нужной точки.
version: "3"
steps:
- name: run_claude_code
on_error: persist_state
- name: persist_state
action: write_postgres
- name: run_checks
action: bash
- name: route_next_agent
when: "quota_hit || context_loss || timeout"
action: assign_codex
- name: require_review
when: "security_failed"
action: notify_human
Да, это упрощённое представление. Но принцип важнее деталей: handoff должен запускаться событием, а не человеком. И переключение не должно зависеть от того, сохранил ли кто-то "тот самый последний prompt" в заметках.
Какие события реально стоит ловить
Я обычно использую 5 триггеров: quota hit, context truncation, command timeout, failed tests и failed security scan. Первые 3 ведут к автоматическому handoff. Последние 2 чаще ведут либо к возврату задачи тому же агенту с узким remediation prompt, либо к human review, если код касается auth, SQL или работы с секретами.
Безопасность: не доверяйте второму агенту больше, чем первому
Одна частая ошибка — считать handoff просто операционной проблемой. На деле это ещё и security-проблема. Второй агент склонен "чинить" не понимая, почему первое решение было ограничено. Именно на handoff у меня чаще всего всплывают лишние расширения прав, сырые SQL-запросы или случайная запись секретов в лог.
OWASP в 2021 году в Top 10 закрепил injection как один из базовых классов риска: owasp.org/Top10. Поэтому я не пропускаю handoff без статических проверок. Для Python это может быть bandit, для общего паттерн-матчинга — semgrep, для секретов — gitleaks.
#!/usr/bin/env bash
set -euo pipefail
pytest -q
semgrep --config auto .
bandit -r app -q
gitleaks detect --no-banner --redact
echo "checks_passed=true"
На 3 недавних agent deployment я ловил один и тот же паттерн: первый агент аккуратно использовал параметризованные запросы, второй при срочном исправлении регрессии вставлял сырой SQL в helper-слой. Не потому что модель "плохая", а потому что handoff был бедным по контексту и богатым по давлению на скорость.
Практическая схема для regulated Europe
Для клиентов из логистики, fintech и industrial automation в DACH я стараюсь держать архитектуру скучной и проверяемой. Исходники в Git, состояние задач в Postgres, секреты в Doppler, оркестрация в n8n, артефакты проверок рядом с task_id. Это важно не только для удобства, но и для аудита: кто менял код, какой агент это делал, какие проверки были пройдены, где потребовался человек.
Если у вас есть Supabase, не превращайте его только в backend для приложения. Это хороший слой для журналирования agent runs, особенно если нужно быстро поднять таблицы состояния, webhooks и простые административные представления. Главное — не хранить "память" агента в одном текстовом blob. Храните нормализованные поля, по которым можно строить маршрутизацию и контроль.
FAQ
Можно ли обойтись без n8n?
Да. Логику handoff можно собрать и на чистом Python с очередью задач. Но n8n удобен там, где нужны быстрые изменения маршрутов, уведомления и работа с webhooks без отдельного сервиса оркестрации.
Нужно ли давать Claude Code и Codex доступ к одной ветке?
Обычно да, но только при жёстком контракте состояния и фиксации commit SHA. Если риск высокий, лучше делать handoff через новую ветку от последнего подтверждённого коммита и автоматически собирать diff.
Что важнее: длинный prompt или внешний state store?
Внешний state store. Длинный prompt полезен как краткое резюме, но он не заменяет результаты тестов, историю команд и статусы проверок в структурированном виде.
Когда обязательно нужен human review?
Когда задача затрагивает auth, права доступа, SQL, секреты, платёжную логику или персональные данные. Чем ближе код к границе риска, тем меньше смысла надеяться на автоматический handoff без человека.
Как понять, что handoff у вас уже сломан?
Если агенты часто перечитывают весь репозиторий, повторяют одинаковые команды, спорят с уже принятыми решениями или производят конфликтующие изменения, значит состояние не передаётся явно. Это не проблема модели, это проблема операционного слоя.
Где в вашем LLM pipeline чаще всего рвётся работа в проде — на квотах, на потере контекста, на security gate или уже на человеческом ревью? Мне правда интересно сравнить это с тем, что я вижу в DACH-проектах.
I run a free 30-min stack audit for DACH founders building AI in regulated markets. DM me on LinkedIn or write to @ger_dennis_ai.
Превратить процесс в систему, которая работает
Продакшн-качество, а не демо.