# codex-crew Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Плагин Claude Code, делающий Codex CLI полноценным сабагентом (исполнение / ревью / консультации) с resumable-сессиями и детерминированной детекцией зависаний. **Architecture:** Тонкий сабагент-транспорт (`agents/codex.md`, sonnet) запускает `scripts/codex-run.sh` в фоне; скрипт гонит `codex exec --json`, следит за стагнацией потока событий (watchdog → kill), пишет `status`/`thread_id`/`last.md` в job_dir. Follow-up оркестратора = SendMessage → `codex exec resume `. Три скилла учат оркестратора формировать задания. **Tech Stack:** bash, Claude Code plugin (agents + skills), codex CLI ≥0.142. Спека: `docs/design.md`. При реализации Task 1/6/7 сверяйся со скиллами plugin-dev (`plugin-dev:plugin-structure`, `plugin-dev:agent-development`, `plugin-dev:skill-development`) — валидация форматов manifest/frontmatter. Факты, проверенные заранее: `--json` и `-o` поддерживаются всеми тремя режимами (`exec`, `exec resume`, `exec review`); `thread_id` приходит в событии `thread.started`; у `review` нет `-C` — рабочая директория задаётся через cwd запуска; без ` exec [codex-flags...] [prompt] # codex-run.sh resume [codex-flags...] [prompt] # codex-run.sh review [--base X|--commit Y|--uncommitted] [codex-flags...] [prompt] # # If /prompt.md exists and no positional prompt given, it is fed via stdin. # Review runs against the git repo at the CURRENT WORKING DIRECTORY (no -C support). # # Files written to : events.jsonl last.md err.log thread_id status # status: ok | stalled | error: . Exit code 0 only on ok. # # Env knobs: # CODEX_STALL_TIMEOUT seconds of event silence before kill (default 600) # CODEX_WATCH_INTERVAL watchdog poll interval seconds (default 15) # CODEX_BIN codex binary (default codex; tests use a stub) set -u JOB_DIR=$1; MODE=$2; shift 2 mkdir -p "$JOB_DIR" JOB_DIR=$(cd "$JOB_DIR" && pwd) EV=$JOB_DIR/events.jsonl LAST=$JOB_DIR/last.md ERR=$JOB_DIR/err.log STALL=${CODEX_STALL_TIMEOUT:-600} TICK=${CODEX_WATCH_INTERVAL:-15} BIN=${CODEX_BIN:-codex} case $MODE in exec) CMD=("$BIN" exec --json --skip-git-repo-check -o "$LAST") ;; resume) TID=$1; shift; printf '%s\n' "$TID" > "$JOB_DIR/thread_id" CMD=("$BIN" exec resume "$TID" --json --skip-git-repo-check -o "$LAST") ;; review) CMD=("$BIN" exec review --json -o "$LAST") ;; *) echo "usage: codex-run.sh exec|resume|review ..." >&2; exit 2 ;; esac rm -f "$JOB_DIR/status"; : > "$EV"; : > "$ERR"; rm -f "$LAST" if [[ $# -eq 0 && -s $JOB_DIR/prompt.md ]]; then "${CMD[@]}" - < "$JOB_DIR/prompt.md" > "$EV" 2> "$ERR" & else "${CMD[@]}" "$@" < /dev/null > "$EV" 2> "$ERR" & fi PID=$! ( while kill -0 "$PID" 2>/dev/null; do sleep "$TICK" now=$(date +%s); mt=$(stat -c %Y "$EV" 2>/dev/null || echo "$now") if (( now - mt > STALL )); then echo stalled > "$JOB_DIR/status" kill "$PID" 2>/dev/null; sleep 3; kill -9 "$PID" 2>/dev/null break fi done ) & WATCH=$! wait "$PID"; RC=$? kill "$WATCH" 2>/dev/null; wait "$WATCH" 2>/dev/null TID_FOUND=$(grep -m1 -o '"thread_id":"[^"]*"' "$EV" | cut -d'"' -f4) [[ -n $TID_FOUND ]] && printf '%s\n' "$TID_FOUND" > "$JOB_DIR/thread_id" if [[ -s $JOB_DIR/status ]]; then : # stalled, written by watchdog elif [[ $RC -eq 0 && -s $LAST ]]; then echo ok > "$JOB_DIR/status" else echo "error: exit=$RC $(tail -c 300 "$ERR" | tr '\n' ' ')" > "$JOB_DIR/status" fi ST=$(head -n1 "$JOB_DIR/status") echo "status: $ST" echo "thread_id: $(cat "$JOB_DIR/thread_id" 2>/dev/null || echo none)" [[ $ST == ok ]] ``` - [ ] **Step 2: chmod и commit** ```bash chmod +x ~/Projects/codex-crew/scripts/codex-run.sh cd ~/Projects/codex-crew && git add -A && git commit -m "feat: codex-run.sh watchdog wrapper" ``` --- ### Task 3: Тест скрипта на стабах (happy path + stall) **Files:** - Create: `~/Projects/codex-crew/tests/test-run.sh` (chmod +x) - Create: `~/Projects/codex-crew/tests/stub-ok/codex` (chmod +x) - Create: `~/Projects/codex-crew/tests/stub-hang/codex` (chmod +x) - [ ] **Step 1: Стаб happy path** — `tests/stub-ok/codex`: ```bash #!/usr/bin/env bash # fake codex: emits thread.started, writes last message file, exits 0 out="" prev="" for a in "$@"; do [[ $prev == "-o" ]] && out=$a; prev=$a; done echo '{"type":"thread.started","thread_id":"test-thread-123"}' echo '{"type":"turn.completed"}' echo "stub answer" > "$out" exit 0 ``` - [ ] **Step 2: Стаб зависания** — `tests/stub-hang/codex`: ```bash #!/usr/bin/env bash # fake codex: emits one event then hangs silently echo '{"type":"thread.started","thread_id":"hang-thread-456"}' sleep 300 ``` - [ ] **Step 3: Тест** — `tests/test-run.sh`: ```bash #!/usr/bin/env bash set -eu HERE=$(cd "$(dirname "$0")" && pwd) RUN=$HERE/../scripts/codex-run.sh TMP=$(mktemp -d) trap 'rm -rf "$TMP"' EXIT # 1. happy path -> status ok, thread_id captured, exit 0 CODEX_BIN=$HERE/stub-ok/codex "$RUN" "$TMP/ok" exec "hello" [[ $(cat "$TMP/ok/status") == ok ]] [[ $(cat "$TMP/ok/thread_id") == test-thread-123 ]] [[ $(cat "$TMP/ok/last.md") == "stub answer" ]] # 2. stall -> watchdog kills, status stalled, exit nonzero if CODEX_BIN=$HERE/stub-hang/codex CODEX_STALL_TIMEOUT=4 CODEX_WATCH_INTERVAL=2 \ "$RUN" "$TMP/hang" exec "hello"; then echo "FAIL: stall run must exit nonzero"; exit 1 fi [[ $(cat "$TMP/hang/status") == stalled ]] [[ $(cat "$TMP/hang/thread_id") == hang-thread-456 ]] # 3. prompt.md via stdin path mkdir -p "$TMP/stdin"; echo "prompt from file" > "$TMP/stdin/prompt.md" CODEX_BIN=$HERE/stub-ok/codex "$RUN" "$TMP/stdin" exec [[ $(cat "$TMP/stdin/status") == ok ]] echo "ALL PASS" ``` - [ ] **Step 4: Запустить, убедиться в провале/успехе честно** ```bash chmod +x ~/Projects/codex-crew/tests/*.sh ~/Projects/codex-crew/tests/stub-*/codex ~/Projects/codex-crew/tests/test-run.sh ``` Expected: `ALL PASS` (stall-кейс занимает ~6-10 с). Если FAIL — чинить скрипт, не тест. - [ ] **Step 5: Commit** ```bash cd ~/Projects/codex-crew && git add -A && git commit -m "test: stub-based watchdog tests" ``` --- ### Task 4: Живой smoke: exec + resume Ничего не коммитим — проверка против реального codex. - [ ] **Step 1: exec** ```bash J=$(mktemp -d) ~/Projects/codex-crew/scripts/codex-run.sh "$J" exec "Ответь одним словом: пинг" cat "$J/last.md" ``` Expected: `status: ok`, `thread_id: `, last.md содержит «понг» (или похожее). - [ ] **Step 2: resume той же сессии** ```bash ~/Projects/codex-crew/scripts/codex-run.sh "$J" resume "$(cat $J/thread_id)" "Процитируй моё прошлое сообщение" cat "$J/last.md" ``` Expected: `status: ok`, цитата «пинг» — сессия непрерывна. --- ### Task 5: Живой smoke: review - [ ] **Step 1: review --uncommitted на тестовом репо** ```bash R=$(mktemp -d) && cd "$R" && git init -q printf 'def div(a, b):\n return a / b\n' > calc.py git add -A && git commit -qm init printf 'def div(a, b):\n return a / b # may divide by zero\n\ndef unused():\n pass\n' > calc.py J=$(mktemp -d) ~/Projects/codex-crew/scripts/codex-run.sh "$J" review --uncommitted cat "$J/last.md"; cat "$J/thread_id" ``` Expected: `status: ok`, last.md с находками, thread_id записан. Если `thread.started` у review отсутствует — зафиксировать в agents/codex.md, что ревью-итерации идут новым exec-заданием (спека это допускает). --- ### Task 6: agents/codex.md **Files:** - Create: `~/Projects/codex-crew/agents/codex.md` - [ ] **Step 1: Написать агента целиком** ````markdown --- name: codex description: Codex (GPT) как полноценный сабагент — исполнение задач, ревью кода, второе мнение. Держит живую codex-сессию, follow-up через SendMessage продолжает тот же диалог. Промпт = задание; опционально строки `cwd: <абсолютный путь>`, `codex options: <флаги>`, `review scope: --base X|--commit Y|--uncommitted`. model: sonnet tools: Bash, Read, Write --- Ты — транспорт между оркестратором и Codex CLI. Задачу сам НЕ решаешь, ответы codex не редактируешь и не дополняешь. Запустил → дождался → вернул как есть. Скрипт: `${CLAUDE_PLUGIN_ROOT}/scripts/codex-run.sh` (дальше — codex-run.sh). Он пишет в job_dir: `status` (ok|stalled|error), `thread_id`, `last.md` (финальный ответ codex), `events.jsonl` (живой прогресс), `err.log`. ## Первое задание 1. `JOB=$(mktemp -d /tmp/codex-job-XXXXXX)` — запомни путь. 2. Write в `$JOB/prompt.md`: транспортная преамбула (ниже) + задание оркестратора ДОСЛОВНО (не пересказывай). 3. Собери команду: - обычное задание: `codex-run.sh $JOB exec ` - ревью с `review scope:`: `codex-run.sh $JOB review ` - если оркестратор дал `cwd:` — префикс `cd && `. 4. Запусти через Bash с `run_in_background: true`. 5. Заверши ход коротко: «codex запущен, job_dir: $JOB». Когда фоновая команда завершится — тебя разбудят. ## Пробуждение (фоновая команда завершилась) Прочитай `$JOB/status`: - **ok** → верни содержимое `$JOB/last.md` ЦЕЛИКОМ, без пересказа, плюс финальную строку `thread_id: $(cat $JOB/thread_id)`. - **stalled / error** → ретрай, суммарно не больше 3 попыток: 1. Write в `$JOB/prompt.md`: `You were interrupted mid-task. Continue where you left off. If you had already finished, reply with your final report.` 2. `codex-run.sh $JOB resume $(cat $JOB/thread_id)` в фоне. 3. Нет `thread_id` (упал до старта) → один повтор `exec` с исходным промптом. После 3 неудач верни честный отчёт: status, `thread_id`, последние 30 строк `err.log`. Не выдумывай результат. ## SendMessage от оркестратора - **Codex ещё работает** → не прерывай. Ответь статусом: `tail -5 $JOB/events.jsonl` — что codex делает сейчас. - **Codex свободен** → это новая реплика (ответ на вопрос codex, доработка, следующая итерация консультации): Write текст в `$JOB/prompt.md` (дословно), запусти `codex-run.sh $JOB resume $(cat $JOB/thread_id)` в фоне, по завершении верни ответ по правилам «Пробуждения». ## Транспортная преамбула (вставляй перед первым заданием) ``` You are operating non-interactively as an executor for an orchestrating agent. If you hit a blocker or need a decision, end your turn with a clear question — the dialogue continues (your session will be resumed with the answer). Your final message is your report: what was done, which files were touched, how it was verified. ``` К follow-up-репликам (resume) преамбулу НЕ добавляй. ## Переопределения (строка `codex options:` от оркестратора) Пробрасывай флаги в codex-run.sh как есть, после режима. Сам ничего не добавляй. Частые: | Что | Флаг | |---|---| | Модель | `-m ` | | Reasoning effort | `-c model_reasoning_effort="minimal|low|medium|high|xhigh"` | | Права | `-s read-only` / `-s workspace-write` (default: полный доступ из конфига юзера) | | Доп. write-директории | `--add-dir ` | | Картинки | `-i ` | | Структурированный ответ | `--output-schema ` | | Любой конфиг-ключ | `-c key=value` | Никогда: `--ephemeral` (ломает resume). Долгая задача ожидается — `CODEX_STALL_TIMEOUT=<сек>` перед командой (default 600 — стагнация вывода, не общее время; трогать редко). ```` - [ ] **Step 2: Commit** ```bash cd ~/Projects/codex-crew && git add -A && git commit -m "feat: codex transport subagent" ``` --- ### Task 7: Три скилла **Files:** - Create: `~/Projects/codex-crew/skills/codex-agent/SKILL.md` - Create: `~/Projects/codex-crew/skills/codex-review/SKILL.md` - Create: `~/Projects/codex-crew/skills/codex-consult/SKILL.md` - [ ] **Step 1: codex-agent/SKILL.md** ````markdown --- name: codex-agent description: Делегировать Codex'у исполнение — написать код, починить баг, исследовать. Use when user says «отдай кодексу», «пусть codex сделает/напишет/починит», «делегируй в codex», or when a plan step is assigned to Codex as the implementer. --- # Делегация задачи Codex Спавни сабагента `codex` (Agent tool). Он держит живую codex-сессию: доработки и ответы на его вопросы — SendMessage тому же агенту, НЕ новый спавн. ## Промпт сабагенту — обязательные части - `cwd: <абсолютный путь проекта>` - Задание: что сделать. Конкретно, с релевантными файлами/путями. - Критерии приёмки: что должно работать, какие тесты/команды пройти. - Что вернуть: отчёт, список тронутых файлов, как проверено. - Опционально: `codex options: -m o3 -s read-only ...` ## Пример ``` cwd: /home/smartass/Projects/nomcrm-api Задание: почини N+1 в эндпоинте GET /orders — queries лог показывает по запросу на каждую позицию заказа. Смотри app/controllers/OrdersController.php. Критерии: существующие тесты проходят (composer test), запросов к БД ≤ 3 на запрос. Верни: список изменённых файлов, суть фикса, вывод composer test. ``` ## После завершения - Ответ codex = отчёт + `thread_id: ...`. Не верь на слово: проверь diff, прогони тесты сам. - Замечания → SendMessage тому же сабагенту (та же codex-сессия, контекст цел). - Codex закончил вопросом (блокер) → ответь через SendMessage, он продолжит. - Пока работает, можно спросить статус SendMessage'ем — не прерывает. ```` - [ ] **Step 2: codex-review/SKILL.md** ````markdown --- name: codex-review description: Ревью кода силами Codex — ветка, коммит, uncommitted-изменения или произвольные файлы. Use when user says «ревью у кодекса», «пусть codex посмотрит ветку/коммит/файл», «codex review», «второй ревьюер». --- # Ревью через Codex Спавни сабагента `codex`. Скоуп задаёт режим: - ветка против базы: `review scope: --base main` - один коммит: `review scope: --commit ` - незакоммиченное: `review scope: --uncommitted` - произвольные файлы / абстрактный скоуп: БЕЗ `review scope:` — обычное задание «сделай ревью файлов X, Y и их производных». ## Промпт сабагенту — обязательные части - `cwd: <абсолютный путь репозитория>` (review работает от cwd) - `review scope: ...` (если применимо) - Фокус, если есть: безопасность / перфоманс / корректность / всё. - Формат находок: `file:line — 🔴|🟡|🔵 — проблема — предлагаемый фикс`, без похвал и пересказа кода. ## Пример ``` cwd: /home/smartass/Projects/proxy-gate review scope: --base main Фокус: корректность и безопасность. Формат находок: file:line — 🔴|🟡|🔵 — проблема — фикс. Без похвал. ``` ## После - Находки отдай юзеру / обработай по задаче. - Спорная находка → SendMessage в ту же сессию: попроси обосновать или показать репро. Не принимай и не отвергай молча. ```` - [ ] **Step 3: codex-consult/SKILL.md** ````markdown --- name: codex-consult description: Второе мнение Codex по артефакту — спека, план, дизайн, документ, идея. Итерации до консенсуса. Use when user says «проверь у кодекса», «спроси codex», «второе мнение», «пусть codex ревьюнет спеку/план», or when validating a spec/plan before execution. --- # Консультация с Codex Спавни сабагента `codex`, итерируй SendMessage'ами. Жёсткий лимит: 5 итераций. ## Первый промпт — обязательные части - Роль: «Ты — второе мнение, НЕ исполнитель. Артефакт не переписывай. Верни находки с severity и отдельно вопросы.» - Требования юзера — дословно (что артефакт должен удовлетворять). - Сам артефакт: текст целиком или `cwd:` + путь к файлу. ## Цикл итераций 1. Получил находки → оцени критически сам (используй superpowers:receiving-code-review, не соглашайся слепо). 2. Внёс правки в артефакт → SendMessage: что принял, что отклонил и ПОЧЕМУ, плюс обновлённый артефакт или diff. 3. Повторяй до «существенных замечаний нет» или лимита 5. ## Финал — резюме юзеру - Что согласовано и внесено. - Что отклонено и почему. - Нерешённые расхождения, если упёрлись (решает юзер). ```` - [ ] **Step 4: Commit** ```bash cd ~/Projects/codex-crew && git add -A && git commit -m "feat: codex-agent, codex-review, codex-consult skills" ``` --- ### Task 8: Установка плагина - [ ] **Step 1: Подключить marketplace и плагин** ```bash claude plugin marketplace add ~/Projects/codex-crew claude plugin install codex-crew@codex-crew ``` (Если CLI-команды нет в этой версии — интерактивно: `/plugin marketplace add ~/Projects/codex-crew`, затем `/plugin install codex-crew@codex-crew`.) - [ ] **Step 2: Выключить старый плагин** ```bash claude plugin disable codex@openai-codex ``` - [ ] **Step 3: Проверить** ```bash claude plugin list 2>/dev/null | grep -iE 'codex' ``` Expected: `codex-crew` enabled, `codex@openai-codex` disabled. --- ### Task 9: Интеграционный тест (новая сессия) Проверяет открытый вопрос спеки: доставку результата при re-invoke фоновой таской. - [ ] **Step 1: Тестовый проект** ```bash T=$(mktemp -d) && cd "$T" && git init -q && echo "# demo" > README.md && git add -A && git commit -qm init ``` - [ ] **Step 2: В НОВОЙ сессии Claude Code (перезапуск — плагин подхватился) спавнить сабагента** Промпт оркестратору: «Через сабагента codex: cwd: . Задание: создай файл hello.py, печатающий "hi", запусти его, верни вывод.» Expected: сабагент запускает фон, возвращает результат codex с `thread_id`. Файл `hello.py` существует, работает. - [ ] **Step 3: Follow-up через SendMessage** «Спроси у того же сабагента: добавь в hello.py вторую строку "bye" — тем же thread'ом.» Expected: сабагент делает resume (не новый exec), codex помнит контекст, файл обновлён. - [ ] **Step 4: Если результат при re-invoke НЕ дошёл до оркестратора сам** Добавить в конец `agents/codex.md` и в секцию «После завершения» всех трёх скиллов fallback-абзац: оркестратор пингует SendMessage'ем «статус?», сабагент отвечает по `$JOB/status` + `last.md`. Commit: `fix: polling fallback`. --- ### Task 10: Финал - [ ] **Step 1: Удалить одноразовые доки** ```bash cd ~/Projects/codex-crew && git rm -q docs/design.md docs/plan.md && rmdir docs 2>/dev/null; git commit -m "chore: drop one-off spec and plan" ``` - [ ] **Step 2: Memory-заметка** — записать в память факт: плагин codex-crew в `~/Projects/codex-crew` (сабагент codex + 3 скилла), старый openai-codex отключён.