# 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 «дай финальный отчёт»`. - **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-fix-handover-2026-07-10.md](codex-sandbox-fix-handover-2026-07-10.md). - **Блок классификатора — решение пользователя.** Если запуск не прошёл 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 \ -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 `); конвейер ходит прямым exec.