Files
dotfiles/agents/.agents/skills/claude-subagent-playbook/references/codex-exec.md
T
Dmitry DementievandClaude Fable 5 ef09a7832b docs(skills): плейбук — уроки боевого прогона тикета #12 по песочнице Codex
- Зачем:
  - боевой прогон 2026-07-30 (тикет #12 v2) закрыл открытый вопрос: расширенный доступ Codex не нужен, штатной связки достаточно.
- Что:
  - codex-exec.md: пункт про блок классификатора начинается с проверки песочницы; в рецепт исполнителя добавлено «шире не бери»; снят кавеат «боем не обкатано» — сеть и docker-сокет работают при штатной связке on-request + auto_review.
  - lessons.md: датированный урок 2026-07-30 с дополнением по итогам прогона.
- Проверка:
  - чтение обновлённых разделов; факты — из JSONL-логов прогона тикета #12 (docker manifest inspect и make up завершились completed под workspace-write).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 20:54:36 +03:00

16 KiB
Raw Blame History

Codex через прямой codex exec: рецепты и ловушки

Проверено 2026-07-09 (codex-cli 0.142.5, Windows + Git Bash) и 2026-07-12 (0.144.1, WSL2 Ubuntu: exec/resume/-o/фоновый Bash — весь конвейер); линукс-эмпирика 07-06/07-07 шла через companion-обёртку и отражена в уроках ниже. Прямой CLI надёжнее обёртки: её фоновая машина глючит (молчаливая подмена анализа Кодекса своим — issue #158, ломает слепое ревью; зависшие статусы), и её --write-запуски режет классификатор авторежима. Далее $D = подпапка задачи в обменном каталоге прогона (определение и конвенция — prompt-templates.md).

Сквозные правила (любая ветка)

  • Промпт — файлом, шум — в файлы. Промпт подавай через stdin (-); stdout/stderr — редиректами в $SCRATCH. В контекст оркестратора читается ровно один файл — финальный отчёт из -o. Промпт собирай конкатенацией, а не переписывай: скелеты — в prompt-templates.md, Write'ом пиши только параметрический блок задачи; чужой контент (вердикты ревью, отчёты) в промпт попадает через cat a.md b.md > prompt.md — дословно и без повторного прохода через твой контекст (ретро 2026-07-10: переписывание гоняло находки через оркестратора до шести раз).
  • Модель и глубину рассуждения задавай явно (-m, -c 'model_reasoning_effort="..."'): дефолты берутся из ~/.codex/config.toml и плавают за последней интерактивной сессией пользователя — из конфига не наследовать, при расхождении с правилом — спроси пользователя. Боевая модель — gpt-5.6-sol (решение пользователя 2026-07-12), она хороша и для анализа/ревью, не только для кода. Эффорт по сложности (решение пользователя 2026-07-19): medium — дефолт для обычных задач (типовая реализация, механика, узкие починки по готовому диагнозу); high — для более сложных: нетривиальная или рискованная реализация, ревью кода, диагноз; xhigh — не дефолтить: расход удваивается, а выигрыш мал — только по явному запросу пользователя. Оверрайды проверены под --strict-config. Уточнение по эксперименту xray-proxy 03/04 (решение пользователя 2026-07-21): реализация по отревьюированному самодостаточному тикету на medium допустима и для нетривиальных задач — конвейер (саморевью + два слепых ревью + триаж) ловит просадку (03: 4 MAJOR-гонки найдены и починены; 04: 1 «чистый» MAJOR — на уровне high-baseline 06). Но экономию считай по всему конвейеру, не по этапу: в 04 medium вышел дороже high-baseline (~822k+135k против ~735k+97k свежих) — сэкономленное на реализации съел триаж находок. Критерий выбора — цена тихой ошибки этапа: ревью/постановка/диагноз остаются high (там модель — последняя линия обороны). И предел: high на ревью постановки не страхует от уверенной выдумки внешних фактов (04: несуществующий однострочный формат .dgst) — форматы артефактов и версии проверяй реальным запросом или фикстурой из первоисточника. Попутная эмпирика: смена model_reasoning_effort при resume кэш треда НЕ сбрасывает (доля кэша держалась ~93–94% при high→medium в 06/03/04) — дорогое ревью на high и дешёвая перепроверка на medium в одном треде работают как задумано.
  • Запуск — собственным фоновым Bash оркестратора (run_in_background): фоновый процесс детачится, живёт сквозь ходы и будит оркестратора по выходу. Потолок 10 минут — только у фронтграундного Bash; фоновому таймаут не нужен, timeout NNN вокруг codex не ставь. & внутрь команды не добавляй — фон даёт харнесс; с & уведомление придёт от обёртки при живом codex (эмпирика 2026-07-12). Спасение осиротевшего процесса: ожидатель while kill -0 <pid>; do sleep 10; done под run_in_background будит по его реальному выходу.
  • thread_id — в первой строке stdout-JSONL ({"type":"thread.started",...}). Забирай сразу после старта: это страховка — если процесс умер или его прибил хост, тред жив: codex exec resume <id> «дай финальный отчёт».
  • resume — только по явному id. Безадресный resume цепляет последний тред сессии — при параллельных тредах подхватит чужой (например, ревью-тред вместо треда реализации).
  • Вердикт без находок — проверь лог: работа или отписка. Дёшево: grep -c '"command_execution"' stdout.jsonl (счётчик выполненных команд) или промежуточные сообщения — jq -r 'select(.item.type=="agent_message") | .item.text' stdout.jsonl. Одна строка APPROVED при пустом счётчике — отписка, перезапускай.
  • Кросс-платформенно. Рецепты — POSIX под Git Bash (эмпирика 2026-07-09: codex, jq, редиректы под Windows работают). $SCRATCH задавай forward-slash-путём (/c/Users/...), не C:\...; пути в аргументах кавычь; в выводах под Windows возможны \r.
  • Linux: sandbox может молча сломаться обновлением Codex. CLI 0.144.1 сменил backend на bwrap+userns; Ubuntu 24.04 с apparmor_restrict_unprivileged_userns=1 глушит любые команды до запуска (bwrap: loopback: Failed RTM_NEWADDR). Сигнатура: web_search работает, а pwd в sandbox — нет. Обход без sudo use_legacy_landlock=true чинит только read-only (write-режим с ним паникует); полный фикс — AppArmor- профиль. Диагностика и рецепты — codex-sandbox-apparmor.md. Фикс целиком под sudo — сам не применяй: дай пользователю готовые команды из файла рецептов (!-префикс в чат), после применения профиля напомни убрать use_legacy_landlock. Перед первым прогоном конвейера на новой Linux-машине прогони диагностику из файла рецептов превентивно.
  • Блок классификатора — сначала сузь песочницу, потом зови пользователя. Первая проверка: нет ли в команде -s danger-full-access — классификатор его блокирует, и он не нужен: docker и сеть проходят эскалацией под штатной связкой из рецепта ниже (боевой прогон 2026-07-30, тикет #12 v2). Если блок не из-за песочницы — дай пользователю готовую команду с префиксом ! в чат или попроси сменить режим разрешений. Сработавший путь — прямой exec; companion с --write блокируется и напрямую, и через раннера.

Ветка «исполнитель» (пишет код)

cat "$D/task-prompt.md" | codex exec --json --strict-config \
  -s workspace-write -m gpt-5.6-sol \
  -c 'model_reasoning_effort="high"' \
  -c 'approval_policy="on-request"' -c 'approvals_reviewer="auto_review"' \
  -o "$D/task-result.md" - \
  > "$D/task-stdout.jsonl" 2> "$D/task-stderr.txt"
  • Эффорт в примере — high (сложная задача); обычной задаче ставь medium по сквозному правилу выше.
  • --strict-config — обязателен: опечатка в -c-ключе упадёт громко, а не проглотится молча (важно для approvals_reviewer — в --help он не документирован, но strict-config его принимает; связка с approval_policy="on-request" отработала боевой прогон 2026-07-09).
  • Право записи + авто-ревьюер аппрувов. Скоуп ограничивай промптом («коммит не делай», границы из файла задачи), не песочницей — жёсткий read-only лишает исполнителя тестов и поиска. Шире тоже не бери: -s danger-full-access блокируется классификатором авторежима и не нужен — docker-сокет (make up) и сеть (docker manifest inspect) прошли эскалацией в боевом прогоне 2026-07-30 (тикет #12 v2).
  • Промпт: путь к файлу задачи; мандат — в этапе 3 SKILL.md.
  • До старта сними baseline git status --porcelain; после — сверь отчёт Кодекса с деревом: правок, которых он не называл, быть не должно.

Ветка «ревьюер» (свежий тред, мандат промптом)

Тот же вызов, что у исполнителя — запись + авто-аппрув, — но свежим тредом, не тем, что писал код. Read-only-песочницей ревьюера не режь: она отнимает у него руки — тесты, проверку гипотез, поиск, документацию, первоисточники. Защита — мандат в промпте, готовым файлом prompts/review-boilerplate.md (сборка — prompt-templates.md); Codex держит его надёжно (практика пользователя, 2026-07-10). Дешёвая подстраховка: git status --porcelain до ревью и сверка после — дерево должно остаться нетронутым. Кавеат снят 2026-07-30: сеть под workspace-write по умолчанию закрыта, но эскалация через авто-аппрув её проходит — в боевом прогоне тикета #12 (v2) у исполнителя прошли и сеть (docker manifest inspect), и docker-сокет (make up, docker compose down). Отдельных событий эскалации в --json-логе при этом нет — успешные команды выглядят обычными completed (история вопроса — ../handoffs/20260710-codex-revyuer-write-i-sliyanie-handoffov.md).

-o-файл вердикта — и есть обменный артефакт: на триаже он уходит в fix-промпт конкатенацией, читай его один раз для синтеза и не пересказывай.

Ветка «триаж/починка» (тем же тредом, что писал код)

cat "$D/fix-prompt.md" | codex exec resume --json <thread-id> \
  -o "$D/fix-result.md" - \
  > "$D/fix-stdout.jsonl" 2> "$D/fix-stderr.txt"
  • resume не принимает -s/-C — песочница и CWD наследуются от исходного треда (write-тред остаётся write); модель наследуется, но переопределяется -m при нужде.
  • Промпт — индекс находок дословно + «закрой перечисленное, больше ничего не меняй; отклонение — только аргументированно».

Раннер-субагент: когда результат надо переварить

Для запуска раннер не нужен (см. сквозные правила) — он нужен, когда сырой результат шумный и его стоит провалидировать или сжать до индекса, прежде чем показывать оркестратору. Тогда раннеру (fast-worker; нет в репозитории — general-purpose) отдай готовую команду и правила разбора — не постановку задачи: тонкий агент, получив постановку, реализует её сам (казус форвардера, lessons 2026-07-06). Свой 10-минутный потолок на синхронный Bash раннер обходит отслеживаемым ожиданием: команда запускается его собственным фоновым Bash, а ждёт он процессом-ожидателем (until grep -q '<маркер>' лог; do sleep 30; done под run_in_background) — харнесс переинвоцирует его по выходу процесса. «Жду уведомления» без отслеживаемого процесса не будит никогда, а голый поллер вне run_in_background умирает при смене хода (эмпирика 2026-07-07) — живучесть даёт именно фоновый запуск.

Companion-плагин (codex-companion.mjs в кэше плагинов) — только для ручного интерактива (status, result <job-id>); конвейер ходит прямым exec.