Модуль 1 · Codex без человека в цикле · урок 4 из 14
Продолжение и ветвление сессий в скриптах
Одна задача — один вызов codex exec: так работает большинство автоматизаций. Но иногда шаги связаны: сначала разобрать проблему, потом исправить, потом проверить. Повторять анализ в каждом вызове дорого, а терять контекст — обидно. Для этого у codex exec есть resume и fork. Разберём, как ими пользоваться в скриптах и где они вредят.
Сессия и её идентификатор
Каждый запуск codex exec создаёт сессию (в событиях и SDK она называется thread). Если вы не указали --ephemeral, сессия сохраняется на диск, и к ней можно вернуться. Идентификатор приходит первым событием потока --json:
codex exec --json "найди причину падения теста OrderTest::testRefund" > step1.jsonl
THREAD_ID=$(jq -r 'select(.type=="thread.started") | .thread_id' step1.jsonl | head -n1)
echo "$THREAD_ID"Для интерактивных сессий то же самое делается командами /resume и /fork — см. урок «Сессии». В скриптах работают подкоманды codex exec.
resume: продолжить с того же места
codex exec resume "$THREAD_ID" "исправь причину, которую ты нашёл; тесты в tests/ не меняй"Агент получает всю историю первого шага: какие файлы читал, что запускал, к какому выводу пришёл. Повторно разбираться ему не нужно.
Есть и короткая форма codex exec resume --last: продолжить самую свежую сессию из текущего каталога. Флаг --all расширяет поиск на сессии из любых каталогов. В скриптах --last удобен, но опасен: если на машине параллельно идут два запуска в одном каталоге, «последней» может оказаться чужая сессия. В CI и в любых конкурентных сценариях передавайте идентификатор явно. Вместо UUID подкоманды принимают и имя сессии.
Пример двухшагового сценария из документации — ревью, затем исправление найденного:
codex exec "проверь изменения на гонки данных"
codex exec resume --last "исправь гонки, которые ты нашёл"fork: ответвить и попробовать иначе
codex exec fork копирует сохранённую сессию в новую. Исходная остаётся нетронутой, а копия продолжает работу с другим промптом:
codex exec fork "$THREAD_ID" "попробуй исправить через изменение запроса, а не через кэш"Если промпт не указан, fork просто создаёт копию без нового хода. Промпт обязателен, если вы передаёте картинки, --output-schema, --output-last-message или --ephemeral.
Локально fork хорошо сочетается с флагом --worktree: Codex создаст отдельный управляемый Git worktree, и альтернативное решение не смешается с первым.
codex exec fork "$THREAD_ID" --worktree "попробуй альтернативный подход"--worktree работает только при локальном запуске и не совмещается с resume, review, --ephemeral и --ignore-user-config. О работе с worktree в целом — урок «Несколько задач параллельно».
Когда продолжать, а когда начинать заново
Продолжение сессии экономит работу, но тащит за собой весь контекст — включая ошибки и неудачные гипотезы. Практическое правило:
| Ситуация | Что делать |
|---|---|
| Анализ, затем исправление того же | resume: агенту нужны выводы анализа |
| Два альтернативных решения одной проблемы | fork от общего анализа |
| Ревью того, что сделал агент | новая сессия: ревьюер не должен видеть рассуждения автора |
| Предыдущий шаг ушёл в тупик | новая сессия с уточнённым промптом |
| Независимые задачи в одном пайплайне | новые сессии, лучше с --ephemeral |
Третий пункт важен. Если тот же агент, который писал исправление, его же и проверяет, он склонен соглашаться со своими решениями. Для проверки запускайте отдельную сессию, например codex review --uncommitted — неинтерактивное ревью незакоммиченных изменений.
Сценарий целиком
Скрипт для разбора упавшего теста: анализ с ответом по схеме, исправление в той же сессии, независимая проверка.
#!/usr/bin/env bash
set -euo pipefail
# 1. Анализ: только чтение, ответ по схеме
codex exec --json \
--output-schema .codex/schemas/diagnosis.json -o diagnosis.json \
"Тест $1 падает. Найди причину, ничего не меняй." > step1.jsonl
THREAD_ID=$(jq -r 'select(.type=="thread.started") | .thread_id' step1.jsonl | head -n1)
if [ "$(jq -r .confidence diagnosis.json)" = "low" ]; then
echo "Причина не ясна, нужен человек"; exit 1
fi
# 2. Исправление в той же сессии, с правом записи
codex exec --sandbox workspace-write resume "$THREAD_ID" \
"Исправь найденную причину минимальным изменением. Тесты не меняй. Запусти тест снова." \
> fix-report.md
# 3. Независимое ревью — новая сессия
codex review --uncommitted > review.mdСхема diagnosis.json здесь — объект с полями cause, files и confidence (enum: low, medium, high). Как её составить — в предыдущем уроке.
Обратите внимание на права и порядок флагов. Первый шаг идёт в read-only по умолчанию. Второму нужна запись, поэтому --sandbox workspace-write стоит перед подкомандой resume: это флаг самой codex exec. Флаги вывода — --json, -o, --output-schema, --ephemeral — в исходниках CLI объявлены глобальными и работают и с подкомандами. Проверьте, как ваша версия применяет права к продолженной сессии: codex exec resume --help и пробный запуск на тестовой ветке.
Где хранятся сессии и почему это важно в CI
Сессии лежат внутри CODEX_HOME (по умолчанию ~/.codex; в README TypeScript SDK указан каталог ~/.codex/sessions). Отсюда два следствия для CI.
Между job сессия не переживёт. Каждый job GitLab CI стартует в чистом контейнере. Многошаговый сценарий проще всего держать внутри одного job. Переносить CODEX_HOME артефактом между job технически можно, но это хрупко и проверяется только экспериментом на вашей версии.
В CODEX_HOME может лежать авторизация. При входе через ChatGPT там хранится auth.json с токенами. Никогда не сохраняйте CODEX_HOME целиком в артефакты или кэш пайплайна: артефакты скачивает любой, у кого есть доступ к проекту.
Если сессия не нужна после запуска, ставьте --ephemeral: файлы не пишутся на диск, а значит, нечему утечь. Но помните, что продолжить такую сессию уже нельзя.
Попробуйте сами
10–15 мин на рабочем месте- Запустите анализ с
--json, достаньтеthread_idи продолжите сессию черезcodex exec resume <id>вопросом «какие файлы ты читал на прошлом шаге?». Убедитесь, что контекст сохранился. - Сделайте
codex exec forkот той же сессии с другим промптом и сравните ответы. - Проверьте
codex exec resume --helpв своей версии CLI и выпишите, какие флаги доступны при продолжении.
Коротко
- Идентификатор сессии приходит в событии
thread.startedпотока--json. codex exec resume <id>продолжает сессию,codex exec fork <id>копирует её в новую.- В скриптах передавайте идентификатор явно:
--lastможет подхватить чужую сессию. - Ревью сделанного агентом — всегда в новой сессии.
CODEX_HOMEне кладите в артефакты: там могут быть токены.