- Зачем:
- read-only-конфайн обеднял ревью Codex (без тестов, поиска,
первоисточников), а плотность SKILL.md и дефолты модели/усилия
из config.toml накопили риски по итогам трёх прогонов.
- Что:
- ветка «ревьюер» в codex-exec.md переведена на запись + авто-аппрув,
защита — мандат промптом; в рецепты добавлены --strict-config и
явные -m / model_reasoning_effort.
- SKILL.md: правило «мандат промптом» для обоих ревьюеров, правило
моделей субагентов (Опус/Sonnet, не Fable), /tdd и /research +
Context7 в этапе 1, таймер-подстраховка ScheduleWakeup; уборка
плотности и инлайн-дат.
- handoffs 07-06/07-07/07-09 поглощены запиской 2026-07-10; в lessons.md
добавлены правило дистилляции и блок 2026-07-10; правки прошли слепое
ревью Опусом, все находки закрыты.
- Проверка:
- оверрайды -m/-c проверены живым codex exec --strict-config;
перекрёстные ссылки и команды сверены ревьюером с codex --help.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
118 lines
9.5 KiB
Markdown
118 lines
9.5 KiB
Markdown
# Codex через прямой `codex exec`: рецепты и ловушки
|
||
|
||
Проверено 2026-07-09 (codex-cli 0.142.5, Windows + Git Bash); линукс-эмпирика
|
||
прогонов 07-06/07-07 шла через companion-обёртку и отражена в уроках ниже.
|
||
Прямой CLI надёжнее обёртки: её фоновая машина глючит (молчаливая подмена
|
||
анализа Кодекса своим — issue #158, ломает слепое ревью; зависшие статусы),
|
||
и её `--write`-запуски режет классификатор авторежима. Далее `$SCRATCH` =
|
||
каталог скретчпада сессии из системного промпта (не `/tmp`: под Windows
|
||
`/tmp` Git Bash — ловушка).
|
||
|
||
## Сквозные правила (любая ветка)
|
||
|
||
- **Промпт — файлом, шум — в файлы.** Промпт пиши Write'ом в `$SCRATCH` и
|
||
подавай через stdin (`-`); stdout/stderr — редиректами туда же. В контекст
|
||
оркестратора читается ровно один файл — финальный отчёт из `-o`.
|
||
- **Модель и глубину рассуждения задавай явно** (`-m`,
|
||
`-c 'model_reasoning_effort="..."'`): дефолты берутся из
|
||
`~/.codex/config.toml` и плавают за последней интерактивной сессией
|
||
пользователя. Для реализации и ревью — high; текущую боевую модель сверь
|
||
с конфигом (2026-07-10: `gpt-5.5`). Оверрайды проверены под
|
||
`--strict-config`.
|
||
- **Запуск — собственным фоновым Bash оркестратора** (`run_in_background`):
|
||
фоновый процесс детачится, живёт сквозь ходы и будит оркестратора по
|
||
выходу. Потолок 10 минут — только у фронтграундного Bash; фоновому таймаут
|
||
не нужен, `timeout NNN` вокруг codex не ставь.
|
||
- **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`.
|
||
- **Блок классификатора — решение пользователя.** Если запуск не прошёл
|
||
permission-гейт, дай пользователю готовую команду с префиксом `!` в чат
|
||
или попроси сменить режим разрешений. Сработавший путь — прямой exec;
|
||
companion с `--write` блокируется и напрямую, и через раннера.
|
||
|
||
## Ветка «исполнитель» (пишет код)
|
||
|
||
```bash
|
||
cat "$SCRATCH/task-prompt.md" | codex exec --json --strict-config \
|
||
-s workspace-write -m gpt-5.5 \
|
||
-c 'model_reasoning_effort="high"' \
|
||
-c 'approval_policy="on-request"' -c 'approvals_reviewer="auto_review"' \
|
||
-o "$SCRATCH/task-result.md" - \
|
||
> "$SCRATCH/task-stdout.jsonl" 2> "$SCRATCH/task-stderr.txt"
|
||
```
|
||
|
||
- `--strict-config` — обязателен: опечатка в `-c`-ключе упадёт громко, а не
|
||
проглотится молча (важно для `approvals_reviewer` — в `--help` он не
|
||
документирован, но strict-config его принимает; связка с
|
||
`approval_policy="on-request"` отработала боевой прогон 2026-07-09).
|
||
- Право записи + авто-ревьюер аппрувов. Скоуп ограничивай промптом («коммит
|
||
не делай», границы из файла задачи), не песочницей — жёсткий read-only
|
||
лишает исполнителя тестов и поиска.
|
||
- Промпт: путь к файлу задачи; мандат — в этапе 3 SKILL.md.
|
||
- До старта сними baseline `git status --porcelain`; после — сверь отчёт
|
||
Кодекса с деревом: правок, которых он не называл, быть не должно.
|
||
|
||
## Ветка «ревьюер» (свежий тред, мандат промптом)
|
||
|
||
Тот же вызов, что у исполнителя — запись + авто-аппрув, — но **свежим
|
||
тредом**, не тем, что писал код. Read-only-песочницей ревьюера не режь: она
|
||
отнимает у него руки — тесты, проверку гипотез, поиск, документацию,
|
||
первоисточники. Защита — мандат в промпте: «исходники и окружение не менять,
|
||
правок не вносить — только находки»; Codex держит его надёжно (практика
|
||
пользователя, 2026-07-10). Дешёвая подстраховка: `git status --porcelain`
|
||
до ревью и сверка после — дерево должно остаться нетронутым. Кавеат: сеть
|
||
под workspace-write по умолчанию закрыта; что поиск/документация проходят
|
||
эскалацией через авто-аппрув — рабочая гипотеза, боем не обкатана
|
||
(см. handoff 2026-07-10).
|
||
|
||
В промпте — формат «только индекс находок» (SEVERITY, файл:строка, суть,
|
||
как проверить), явная строка VERDICT и поощрение безопасных эмпирических
|
||
проверок вне репо (воспроизвести краевой случай, свериться с
|
||
первоисточником) — вердикт заметно твёрже (эмпирика 2026-07-09).
|
||
|
||
## Ветка «триаж/починка» (тем же тредом, что писал код)
|
||
|
||
```bash
|
||
cat "$SCRATCH/fix-prompt.md" | codex exec resume --json <thread-id> \
|
||
-o "$SCRATCH/fix-result.md" - \
|
||
> "$SCRATCH/fix-stdout.jsonl" 2> "$SCRATCH/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`) — харнесс переинвоцирует его по выходу процесса.
|
||
«Жду уведомления» без отслеживаемого процесса не будит никогда
|
||
(эмпирика 2026-07-07).
|
||
|
||
Companion-плагин (`codex-companion.mjs` в кэше плагинов) — только для
|
||
ручного интерактива (`status`, `result <job-id>`); конвейер ходит прямым
|
||
exec.
|