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

177 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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](prompt-templates.md)).
## Сквозные правила (любая ветка)
- **Промпт — файлом, шум — в файлы.** Промпт подавай через stdin (`-`);
stdout/stderr — редиректами в `$SCRATCH`. В контекст оркестратора
читается ровно один файл — финальный отчёт из `-o`. Промпт **собирай
конкатенацией, а не переписывай**: скелеты — в
[prompt-templates.md](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](codex-sandbox-apparmor.md).
Фикс целиком под sudo — сам не применяй: дай пользователю готовые команды
из файла рецептов (`!`-префикс в чат), после применения профиля напомни
убрать `use_legacy_landlock`. Перед первым прогоном конвейера на новой
Linux-машине прогони диагностику из файла рецептов превентивно.
- **Блок классификатора — сначала сузь песочницу, потом зови
пользователя.** Первая проверка: нет ли в команде `-s
danger-full-access` — классификатор его блокирует, и он не нужен:
docker и сеть проходят эскалацией под штатной связкой из рецепта ниже
(боевой прогон 2026-07-30, тикет #12 v2). Если блок не из-за
песочницы — дай пользователю готовую команду с префиксом `!` в чат или
попроси сменить режим разрешений. Сработавший путь — прямой exec;
companion с `--write` блокируется и напрямую, и через раннера.
## Ветка «исполнитель» (пишет код)
```bash
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](prompts/review-boilerplate.md) (сборка —
[prompt-templates.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](../handoffs/20260710-codex-revyuer-write-i-sliyanie-handoffov.md)).
`-o`-файл вердикта — и есть обменный артефакт: на триаже он уходит в
fix-промпт конкатенацией, читай его один раз для синтеза и не пересказывай.
## Ветка «триаж/починка» (тем же тредом, что писал код)
```bash
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.