Codex exec в CI: машиночитаемый вывод, коды возврата и цена прогона

37 мин. чтения
BYBIT · СПОТ И ФЬЮЧЕРСЫ
Крипта с нуля
Комиссия 0,1%, торги 24/7, старт с $10
Открыть счёт

Коротко (TL;DR)

  • codex exec — это тот же агент Codex, только без интерфейса: задача приходит аргументом или через stdin, прогресс уходит в stderr, а в stdout остаётся финальный ответ. Официальное описание режима — на странице неинтерактивного режима Codex.
  • Конвейеру нужны две вещи: --json и код возврата. По замеру на версии 0.147.0 (13 августа 2026) провал хода даёт код 1 и событие turn.failed в потоке, а ошибка в флагах — код 2 ещё до обращения к сети.
  • Первая ловушка не в правах, а в stdin. Если поток ввода открыт, codex exec "задача" пишет «Reading additional input from stdin…» и ждёт бесконечно. Лечится добавлением < /dev/null.
  • В CI ключ передают на одну команду, а не на весь job — переменной CODEX_API_KEY. Для GitHub есть официальный экшен, который прячет ключ за прокси и снимает sudo с раннера.
  • Один прогон стоит центы, и это считается точно. Сверка тарифной сетки кредитов с ценами API даёт курс 1 кредит = $0,04, а типовой ночной прогон на GPT-5.6 Terra выходит около $0,18.
  • Данные актуальны на 13 августа 2026 и проверены на Codex CLI 0.147.0 (релиз 7 августа 2026). Версии здесь стареют быстро: три официальных рецепта уже разошлись с бинарником — разбор в конце.

Что делает codex exec и чем отличается от Codex в терминале

codex exec — это запуск Codex без текстового интерфейса: команда получает задачу, выполняет её до конца и завершается, возвращая процессу код выхода. В справке версии 0.147.0 она описана буквально как «Run Codex non-interactively» и имеет короткий алиас codex e.

Разница с интерактивным циклом в терминале не в силе агента, а в том, кто принимает решения. В интерактиве вы видите план, подтверждаете команды и правите курс. В exec подтверждать некому: агент отработает ровно с теми правами и по тем правилам, которые вы задали до запуска.

Задачу можно передать тремя способами, и они не взаимозаменяемы:

# 1. Промпт аргументом — обычный случай для CI
codex exec "проверь миграции на обратную совместимость"

# 2. Промпт из stdin: сентинел «-» говорит «читай задачу целиком отсюда»
cat prompt.txt | codex exec -

# 3. Промпт аргументом + данные через трубу: stdin приедет как блок <stdin>
npm test 2>&1 | codex exec "суммируй упавшие тесты и предложи минимальную правку"

Третий способ — самый недооценённый. Он превращает агента в обычный элемент конвейера: слева команда, которая производит данные, справа — инструмент, который их разбирает. Именно так пишут сводки по логам, разборы упавших сборок и черновики комментариев к pull request.

SpaceX · xStockSpaceX — частная компания. Торгуй её токеном на Bybit за крипту.Торговать SpaceX →

Потоки разведены намеренно: прогресс печатается в stderr, а в stdout попадает только финальное сообщение. Поэтому codex exec "..." > result.md даёт чистый файл без служебного шума, а не перемешанный лог.

Три пути запустить Codex без человека: exec, SDK и GitHub Action

Поверхностей три, и выбирать между ними нужно осознанно. Неочевидное здесь то, что все три ведут в один и тот же бинарник: TypeScript SDK, по его собственному README, запускает процесс codex и обменивается с ним событиями JSONL через stdin и stdout, а официальный экшен просто ставит CLI и вызывает codex exec. Меняется обвязка, а не движок.

ПоверхностьЧто этоКогда братьЧем платит
codex execкоманда CLIjob уже живёт в shell-скрипте; нужен минимум зависимостейсами разбираете JSONL и коды возврата
Codex SDKбиблиотека для TypeScript или PythonCodex — движок внутри вашего продукта или сложного оркестраторанужен рантайм Node 18+ или Python 3.10+
openai/codex-actionготовый экшен GitHubконвейер живёт в GitHub Actionsменьше контроля, зато ключ защищён из коробки
codex cloud execотправка задачи в облакоработа долгая, раннер держать не хочетсяпомечена экспериментальной, нужен ID окружения

Четвёртая строка часто выпадает из обзоров. Команда codex cloud exec --env <ENV_ID> "задача" отправляет работу в облачные задачи Codex прямо из скрипта, поддерживает --branch и --attempts (несколько попыток с выбором лучшей). По справке 0.147.0 вся ветка codex cloud помечена как экспериментальная — в критичный конвейер её ставить рано, но для фоновых задач она снимает вопрос «где держать раннер».

Флаги codex exec, от которых зависит судьба прогона в CI

Справка codex exec --help на версии 0.147.0 длинная, но для автоматизации значение имеет короткий список. Ниже — то, что реально меняет поведение прогона.

ФлагЧто делаетПочему важно в CI
--jsonпереводит stdout в поток JSON Linesединственный способ читать ход работы программно
-o, --output-last-message <файл>пишет финальный ответ в файлфайл остаётся артефактом job; в stdout ответ тоже придёт
--output-schema <файл>заставляет финальный ответ соответствовать JSON Schemaследующий шаг конвейера получает стабильные поля, а не прозу
--sandbox <режим>read-only, workspace-write, danger-full-accessпо умолчанию агент не может писать на диск
--ephemeralне сохранять файлы сессии на дискна общем раннере не оставляет следов работы
--ignore-user-configне читать config.toml из CODEX_HOMEпрогон перестаёт зависеть от настроек чужой машины
--ignore-rulesпропустить файлы .rules пользователя и проектато же самое для правил запуска команд
--skip-git-repo-checkразрешить запуск вне git-репозиториянужен редко и осознанно, см. ниже
-C, --cd <каталог>рабочий корень агентав монорепозитории ограничивает область работы
--add-dir <каталог>дополнительный каталог на записькогда правки нужны вне основного рабочего каталога

Отдельно стоит -c (или --config): он переопределяет любое значение конфигурации по точечному пути, например -c model="gpt-5.6-terra". Именно через него официальный cookbook выдаёт агенту право на запись, не трогая --sandbox.

Машиночитаемый вывод: поток JSONL, схема ответа и коды возврата

Без --json конвейер видит только финальный текст. С ним stdout превращается в поток событий, где каждая строка — самостоятельный объект JSON. Типы событий: thread.started, turn.started, turn.completed, turn.failed, семейство item.* и error. Внутри item приезжают сообщения агента, рассуждения, запуски команд, правки файлов, вызовы инструментов и обновления плана.

Практическая ценность в том, что расход токенов приходит прямо в потоке: событие turn.completed несёт поле usage со счётчиками input_tokens, cached_input_tokens, output_tokens и reasoning_output_tokens. Это готовый вход для учёта стоимости, о котором ниже.

BYBIT EARNЗаставь крипту работатьПроценты на USDT и BTC без блокировки — деньги остаются под рукой.Разместить

Что происходит при провале, обзоры обычно не показывают — а для CI это важнее успешного случая. Вот реальный хвост потока из прогона без действительных учётных данных (13 августа 2026, версия 0.147.0):

{"type":"thread.started","thread_id":"019ffaa2-1de8-76d3-896a-5352ae4e9447"}
{"type":"turn.started"}
{"type":"error","message":"Reconnecting... 2/5 (unexpected status 401 Unauthorized...)"}
{"type":"item.completed","item":{"id":"item_0","type":"error","message":"Falling back from WebSockets to HTTPS transport..."}}
{"type":"turn.failed","error":{"message":"unexpected status 401 Unauthorized: Missing bearer or basic authentication in header..."}}

Отсюда два вывода. Первый: события error идут в stdout вперемешку с полезными, поэтому «взять последнюю строку» — рабочая стратегия только если вы действительно ждёте turn.failed или turn.completed. Второй: причина отказа лежит в потоке текстом, и её не нужно выковыривать из логов.

Коды возврата в документации не описаны, поэтому я измерил их на версии 0.147.0:

КодЧто случилосьЧто делать конвейеру
0ход завершёнчитать финальное сообщение или файл -o
1агент дошёл до модели, но ход провалился; в потоке turn.failedпоказать причину из потока, решить — повторять или падать
2Codex до работы не дошёл: неизвестный флаг, ошибка командной строкичинить сам вызов, повтор бесполезен

Двойка проверена контрольным опытом: заведомо несуществующий флаг --no-such-flag-xyz даёт ровно тот же код и ту же форму сообщения, что и устаревший флаг. То есть 2 означает «неверная команда», а не «конкретно эта опция устарела».

Если следующему шагу нужны поля, а не текст, задайте схему. Файл schema.json описывает форму ответа, а прогон выглядит так:

codex exec "собери метаданные проекта" \
  --output-schema ./schema.json \
  -o ./project-metadata.json < /dev/null

Почему codex exec зависает в раннере и лечится одним /dev/null

Это самая дорогая ловушка неинтерактивного запуска, и в материалах топа её нет. Симптом: job висит до таймаута, в логе одна строка — «Reading additional input from stdin…». Задача при этом передана аргументом, и логически читать больше нечего.

Механика простая. Codex поддерживает передачу данных через трубу: если stdin запайплен, его содержимое добавляется к промпту как блок <stdin>. Отличить «труба пустая» от «данные ещё не пришли» невозможно, пока труба не закрыта. В интерактивном терминале это незаметно, а в раннере, cron-задаче или при запуске из родительского процесса поток ввода часто остаётся открытым — и агент ждёт данные, которых не будет.

Замер 13 августа 2026 на версии 0.147.0, два прогона с одинаковой задачей:

Условие запускаПоведениеИтог
stdin открыт (держим трубу)печатает «Reading additional input from stdin…»висит бесконечно, снят сторожем через 30 с
stdin закрыт: < /dev/nullработает штатнозавершился за 22 с с кодом 1 (нет учётных данных)

Лечение — одна конструкция в конце команды:

codex exec --json "прогони тесты и почини падение" < /dev/null

Официальный cookbook по GitLab обходит ту же проблему иначе — заворачивает вызов в script -q -c, то есть выдаёт процессу псевдотерминал. Способ рабочий, но < /dev/null проще и не тянет за собой лишнюю утилиту.

Рядом живёт вторая причина мгновенной остановки: Codex отказывается работать вне git-репозитория. Сообщение при этом говорит не про git, а про доверие — «Not inside a trusted directory and —skip-git-repo-check was not specified», код возврата 1. По тексту ошибки в документации искать бесполезно, поэтому запомните формулировку: она означает «положи задачу в репозиторий или осознанно добавь --skip-git-repo-check».

Аутентификация автоматического прогона: ключ, а не аккаунт

Развилка «аккаунт ChatGPT или API-ключ» в автоматическом прогоне решается иначе, чем на своей машине. Рекомендованный путь — ключ: его проще выдать, отозвать и ротировать.

Переменная называется CODEX_API_KEY, и у неё есть особенность, которую легко пропустить: она поддерживается только в codex exec. Ставить её положено на одну команду, а не на весь job:

CODEX_API_KEY=$MY_KEY codex exec --json "разбери упавшие тесты" < /dev/null

Требование не косметическое. Документация прямо запрещает объявлять OPENAI_API_KEY или CODEX_API_KEY переменной уровня job в конвейере, который выкачивает или запускает код из репозитория: скрипты сборки, тесты, хуки установки зависимостей и скомпрометированный сторонний экшен в том же job прочитают эту переменную без всякого взлома.

Гонять CI под аккаунтом ChatGPT тоже можно, но путь ровно один и он неудобен по устройству, а не по недосмотру. Нужно создать auth.json командой codex login на доверенной машине, положить файл на раннер и позволить Codex обновлять его самому: клиент освежает пачку токенов, если последнее обновление старше примерно 8 суток, и записывает новые значения обратно в тот же файл. Отсюда три правила, которые ломают наивную схему:

  • Не перезаписывайте файл исходным секретом на каждом рейсе — затрёте токены, которые Codex только что обновил.
  • Один auth.json на один раннер или на строго последовательный поток задач; два параллельных job рассинхронизируют сессию.
  • Для публичных и open-source репозиториев этот путь запрещён прямо в документации: файл содержит действующие токены доступа.

Из остальных переменных в автоматическом прогоне пригодятся CODEX_HOME (корень состояния, каталог обязан существовать заранее), RUST_LOG для подробных логов при разборе инцидента и CODEX_NON_INTERACTIVE=1 для тихой установки через официальный скрипт.

Codex GitHub Action: прокси для ключа и снятие sudo с раннера

Для GitHub Actions есть официальный экшен openai/codex-action@v1. Он ставит CLI, поднимает прокси Responses API, если вы передали ключ, и запускает codex exec с заданными правами. Финальное сообщение агента отдаётся выходом final-message — его можно передать в следующий job.

- name: Run Codex
  id: run_codex
  uses: openai/codex-action@v1
  with:
    openai-api-key: ${{ secrets.OPENAI_API_KEY }}
    prompt-file: .github/codex/prompts/review.md
    output-file: codex-output.md

Самое интересное в экшене — не входы, а то, как он обращается с ключом. Разбор его action.yml показывает три приёма подряд: ключ передаётся прокси через stdin и вычищается из окружения процесса, файл со сведениями о прокси получает права только на чтение и владельца root, а затем с пользователя раннера необратимо снимается sudo — и экшен тут же проверяет, что sudo действительно перестал работать, иначе падает.

Зачем такие сложности, объясняют сами авторы в разборе угроз экшена: на раннерах GitHub по умолчанию доступен sudo без пароля, а значит через procfs можно прочитать память чужого процесса и достать оттуда ключ. Комбинация «read-only песочница плюс отключённая сеть», которая многим кажется достаточной, ключ не защищает.

Отсюда практический вывод: safety-strategy по умолчанию (drop-sudo) менять не нужно, а значение unsafe на общем раннере ставить нельзя. Исключение одно — Windows, где других вариантов пока нет и экшен сам это проверяет первым шагом.

Ещё одна деталь для тех, кто читает только страницу документации: в action.yml объявлены входы, которых там нет. Это permission-profile (современная замена входу sandbox; в описании входа они прямо названы взаимоисключающими), output-schema (текст схемы прямо в workflow) и output-schema-file (путь к файлу схемы в репозитории), responses-api-endpoint (свой эндпоинт, например в Azure) и allow-bot-users (поимённый список доверенных ботов).

По умолчанию запустить такой workflow может только тот, у кого есть право записи в репозиторий, — это отдельный шаг проверки внутри экшена. Расширять список входами allow-users и allow-bots стоит с осторожностью: если открыть запуск всем, чужие люди начнут расходовать квоту вашего ключа.

Codex в GitLab CI и любом другом раннере: рецепт на голом CLI

Экшен удобен, но он не обязателен: codex exec — обычная консольная команда, и она одинаково работает в GitLab CI, Jenkins, Buildkite или в cron на своей машине. У OpenAI есть официальный cookbook именно для GitLab, а сам GitLab описывает связку в своём блоге, так что тема раннеров давно не сводится к GitHub.

Минимальная job для GitLab CI выглядит так:

codex_review:
  stage: codex
  image: node:24
  rules:
    - if: '$CI_MERGE_REQUEST_ID && $OPENAI_API_KEY'
  script:
    - npm -g i @openai/codex@0.147.0
    - codex --version
    - |
      CODEX_API_KEY="$OPENAI_API_KEY" codex exec --json \
        --sandbox read-only \
        -o codex-report.md \
        "Разбери изменения ветки против $CI_MERGE_REQUEST_TARGET_BRANCH_NAME и опиши риски" \
        < /dev/null > codex-events.jsonl
      echo "codex rc=$?"
  artifacts:
    when: always
    paths: [codex-report.md, codex-events.jsonl]

Здесь собраны все правила, разобранные выше: версия CLI закреплена, ключ живёт в переменной CI/CD и подставляется на одну команду, поток ввода закрыт, права минимальны, а артефакты сохраняются when: always — иначе при падении job вы не увидите ни отчёта, ни потока событий. Правило rules пропускает job, если ключа нет: на merge request из форка секреты не отдаются, и без такой проверки job будет падать без пользы.

Официальный cookbook делает ещё один шаг, полезный в GitLab: складывает вывод агента в формат CodeClimate, и тогда замечания видны прямо в виджете merge request, рядом с линтером и тестами.

Права и сеть автономного прогона: песочница и профили доступа

По умолчанию агент работает в режиме только для чтения: он видит репозиторий, но записать ничего не может. Это правильный дефолт для CI, и именно поэтому рецепт автофикса вынужден явно выдавать право на запись.

Три режима песочницы и их смысл в автоматическом прогоне:

  • read-only — анализ, ревью, сводки, генерация отчётов. Годится для большинства задач в конвейере.
  • workspace-write — правки файлов в рабочем каталоге: автофикс, миграции, обновление документации.
  • danger-full-access — снимает ограничения; документация допускает его только в изолированной среде вроде одноразового контейнера.

Флаг --ask-for-approval в автоматическом прогоне почти всегда бессмысленен: спрашивать некого. Значение never описано как «execution failures are immediately returned to the model» — то есть агент не остановится, а попробует решить проблему сам. Границу ему ставит песочница, а не политика одобрений; подробный разбор самих режимов одобрения и песочницы — в отдельном уроке.

Два флага изоляции стоит ставить в CI по умолчанию. --ignore-user-config отвязывает прогон от config.toml в домашнем каталоге (аутентификация при этом всё равно берётся из CODEX_HOME), а --ignore-rules — от пользовательских и проектных файлов .rules. Вместе они дают воспроизводимость: результат перестаёт зависеть от того, что лежало на конкретной машине.

Сколько стоит один прогон: курс кредита и расчёт по токенам

Стоимость автоматизации — то место, где обзоры обрываются на фразе «зависит от модели». Считать можно точнее, и для этого достаточно двух официальных таблиц.

Расход по подписке ChatGPT измеряется кредитами, расход по ключу — долларами. Величины связаны жёстко: если сопоставить обе таблицы на одну дату, множитель оказывается одинаковым для всех моделей и всех трёх классов токенов.

МодельКредиты за 1 млн (вход / кэш / выход)Доллары за 1 млн (вход / кэш / выход)
GPT-5.6 Sol125 / 12,5 / 750$5 / $0,50 / $30
GPT-5.6 Terra50 / 5 / 300$2 / $0,20 / $12
GPT-5.6 Luna5 / 0,5 / 30$0,20 / $0,02 / $1,20
GPT-5.462,5 / 6,25 / 375$2,50 / $0,25 / $15

Разделите любую пару — получится $0,04 за кредит, то есть 25 кредитов на доллар. Совпадение держится на 14 сверках из 15 (пять моделей на три класса токенов); единственное отклонение — выход GPT-5.4 mini, где в кредитной таблице стоит округлённое 113 вместо точного 112,5. Величина нигде не объявлена вендором как «курс» — это вывод из сопоставления официального прайса API с тарифной сеткой кредитов на 13 августа 2026.

Теперь прогон. Возьмём типовую ночную задачу: агент читает часть репозитория, гоняет тесты, правит файл и пишет отчёт. Допущения (это модель, а не счёт из личного кабинета): 150 тысяч входных токенов суммарно по ходам, из них 120 тысяч кэшированных, и 8 тысяч токенов на выходе.

МодельСтоимость прогона30 прогонов в месяц
GPT-5.6 Luna~$0,018~$0,54
GPT-5.6 Terra~$0,18~$5,40
GPT-5.6 Sol~$0,45~$13,50

В кредитах тот же прогон на Terra стоит 4,5 кредита — и $0,18 при курсе выше. Цифры скромные, но масштаб решает: ревью на каждый pull request при сотне PR в месяц даёт уже $18 на Terra и $45 на Sol.

Два рычага влияют на счёт сильнее выбора модели. Первый — кэш: повторный контекст стоит в десять раз дешевле свежего, поэтому длинная цепочка ходов по одному репозиторию обходится не так дорого, как кажется. Второй — объём выхода: он самый дорогой класс токенов, и просьба «покажи только диff и три строки объяснения» экономит больше, чем смена модели. Если прогоны идут по подписке, полезно понимать и устройство лимитов плана — кредиты начинают тратиться после того, как включённый объём исчерпан.

Отказы, ретраи и таймауты: что Codex делает сам, а что должен CI

Codex обороняется от сетевых сбоев сам, и знать глубину этой обороны полезно: она напрямую влияет на длину job. Измеренное поведение при недоступной модели (13 августа 2026, версия 0.147.0): пять попыток подключения по WebSocket, честное сообщение «Falling back from WebSockets to HTTPS transport», ещё пять попыток по HTTPS и выход с кодом 1. На пустом отказе весь цикл занял 21–22 секунды.

Замер совпадает с документированными значениями по умолчанию: stream_max_retries равен 5, request_max_retries — 4. То есть на реальной сетевой икоте прогон не упадёт с первой попытки, и добавлять свой цикл повторов поверх обычно не нужно.

А вот чего у команды нет — так это собственного потолка времени. Флага общего таймаута в справке 0.147.0 не существует; параметр stream_idle_timeout_ms со значением 300 000 мс — это окно тишины потока, а не предел длительности прогона. Вывод практический: ограничение обязан ставить конвейер.

# потолок в 15 минут средствами системы
timeout 900 codex exec --json "задача" < /dev/null
echo "rc=$?"   # 124 — сработал таймаут

В GitHub Actions ту же роль играет timeout-minutes у шага или job, в GitLab CI — свойство timeout. Ставить его нужно всегда: даже без ловушки stdin агент может уйти в долгую задачу, а раннер стоит денег.

СимптомВероятная причинаЧто проверить
Job висит, в логе «Reading additional input from stdin…»открытый stdinдобавить < /dev/null
Мгновенный выход с кодом 2неизвестный флаг или опечатка в командеcodex exec --help на своей версии
Код 1 и «Not inside a trusted directory»запуск вне git-репозиторияположить работу в репозиторий или --skip-git-repo-check
Код 1, в потоке turn.failed с 401ключ не доехал до командыключ ставится на сам вызов, а не на job
Прогон падает, хотя раньше работалобновился CLI, флаг исчеззакрепить версию, сверить справку
Пустой stdout при непустом stderrсмотрите не тот потокфинальный ответ в stdout, прогресс в stderr

Устаревшие рецепты: —full-auto и имена входов Codex Action

Эта тема стареет быстрее, чем пишутся статьи о ней, — включая официальные. Три расхождения, найденные 13 августа 2026 на версии 0.147.0.

Флага --full-auto больше нет. Проверено тремя путями: codex exec --full-auto отвечает «error: unexpected argument ‘—full-auto’ found» и кодом 2; codex --full-auto даёт то же самое; поиск строк по самому бинарнику находит ноль вхождений. Метод при этом проверен на контрольной группе — тем же поиском найдены девять других имён флагов и переменных (CODEX_HOME — 60 вхождений, ephemeral — 36, skip-git-repo-check — 2 и так далее). То есть ноль означает отсутствие, а не сломанный поиск.

При этом страница неинтерактивного режима на ту же дату утверждает, что флаг сохранён как устаревший ради совместимости и печатает предупреждение, а официальный cookbook по GitLab ставит codex exec --full-auto в рабочий пример — рядом с командой npm -g i @openai/codex@latest, то есть рецепт устанавливает свежую версию и тут же вызывает то, чего в ней нет.

Имена входов экшена расходятся между двумя официальными страницами. Cookbook по автофиксу использует openai_api_key и codex_args через подчёркивание, тогда как action.yml объявляет openai-api-key и codex-args через дефис. GitHub Actions сопоставляет входы по точному имени, поэтому скопированный рецепт даёт ровно тот симптом, который описан в разделе устранения неполадок официальной документации: прокси не стартует, потому что ключ до него не доехал.

Что написано в источникеЧто в артефакте на 13.08.2026Как писать
codex exec --full-auto (cookbook GitLab)флага нет, код возврата 2--sandbox workspace-write
«--full-auto сохранён как deprecated» (документация)в бинарнике 0 вхожденийсчитать флаг удалённым
openai_api_key, codex_args (cookbook автофикса)openai-api-key, codex-args в action.ymlчерез дефис
openai/codex-action@main (cookbook)тег @v1 в документациизакреплять версию

Отсюда правило, которое дороже любого из этих трёх фактов: закрепляйте версию CLI и тег экшена. npm -g i @openai/codex@latest в job означает, что однажды утром конвейер поедет на новой версии, о которой вы не знали. У экшена для этого есть вход codex-version.

Три рецепта: автофикс тестов, changelog и правка по репозиторию

Автофикс упавшего CI. Официальный шаблон устроен вокруг разделения прав, и это главное в нём. Job с Codex получает только contents: read и persist-credentials: false, агент чинит тесты, а результат сохраняется патчем-артефактом. Второй job с правами на запись применяет патч и открывает pull request — ключа OpenAI он при этом не видит вовсе. Человек остаётся в контуре: он смотрит PR, а не доверяет автоматике коммит в основную ветку.

Заметьте, что второй официальный источник — cookbook по автофиксу — делает иначе: коммитит и открывает PR в том же job. Схема проще, но права шире, и на публичном репозитории я бы выбрал вариант с двумя job.

Черновик changelog. Здесь агент вообще не должен ничего менять, поэтому режим только для чтения и труба:

git log --oneline v1.4.0..HEAD \
  | codex exec --sandbox read-only \
      "Сгруппируй коммиты по смыслу и напиши changelog для пользователей, без внутренних деталей" \
  > CHANGELOG.draft.md

Массовая правка по репозиторию. Задача вроде «переименуй устаревший вызов во всех сервисах» решается не одним прогоном, а циклом с проверкой. Здесь пригодятся --output-schema (чтобы получить машиночитаемый отчёт о том, что изменено) и двухшаговая работа через codex exec resume --last "теперь прогони тесты и почини, что сломал" — вторая команда продолжает ту же сессию, а не начинает с нуля. Файлы инструкций проекта агент читает и в неинтерактивном режиме, поэтому правила стиля лучше держать в AGENTS.md, а не переписывать в промпт каждый раз.

Codex SDK на TypeScript и Python: когда код лучше, чем exec

Если Codex становится частью вашего продукта, а не шагом конвейера, разбирать JSONL руками незачем — есть официальные SDK.

import { Codex } from "@openai/codex-sdk";

const codex = new Codex();
const thread = codex.startThread();
const turn = await thread.run("Найди причину падения тестов и предложи правку");

console.log(turn.finalResponse);

TypeScript-версия требует Node.js 18 и старше, умеет продолжать тред повторным run(), восстанавливать его по идентификатору через resumeThread() и отдавать события по мере поступления через runStreamed(). Схему ответа можно задать на каждый ход, в том числе сгенерировав её из Zod.

Python-версия ставится как pip install openai-codex, требует Python 3.10 и старше и устроена иначе: она управляет локальным app-server по JSON-RPC, а не гоняет CLI. Пресеты песочницы там заданы явно — Sandbox.read_only, Sandbox.workspace_write, Sandbox.full_access — и режим можно менять между ходами одного треда.

Ключевое отличие SDK от прямого вызова команды — не возможности, а форма. Под капотом TypeScript SDK, по его README, запускает тот же CLI и читает тот же поток JSONL, а CODEX_API_KEY подкладывает в окружение процесса сам. Поэтому выбор простой: если задача помещается в shell-скрипт — берите exec и не тащите рантайм в раннер; если вокруг агента нужна логика (очередь задач, свой интерфейс, разбор промежуточных событий) — берите SDK и получите типы вместо ручного парсинга строк.

Риски автономного прогона: утечка ключа и чужой текст в задаче

Автономность здесь означает, что ошибок никто не заметит в момент их совершения. Отсюда честный список того, где эта схема ломается.

  • Ключ утекает через права, а не через сеть. Пока у процесса есть sudo без пароля, содержимое памяти соседних процессов доступно на чтение — и режим «только чтение с диска» ключ не спасает. Поэтому в GitHub Actions работает drop-sudo, а в своём раннере ключ стоит держать в отдельном шаге и не пускать в job недоверенный код.
  • Недоверенный текст приезжает вместе с задачей. Тело pull request может содержать инструкции в HTML-комментарии, невидимом для человека; туда же относятся сообщения отдельных коммитов, скриншоты и файлы инструкций репозитория, если работа идёт над содержимым чужого PR. Промпт, собранный из таких данных, нужно чистить — и не давать агенту прав на запись в этом сценарии.
  • Состояние раннера после агента не гарантировано. Авторы экшена рекомендуют ставить его последним шагом job: агент мог оставить работающие процессы, переписать файлы других экшенов на хосте или дописать что-то в .git/hooks в расчёте на привилегированные шаги, которые пойдут следом.
  • Тихий провал дороже громкого. Прогон без потолка времени и без проверки кода возврата выглядит как успешный: job зелёный, артефакт пустой. Проверяйте $? и сохраняйте артефакты when: always.
  • Рецепты стареют. Три расхождения официальных источников с бинарником, разобранные выше, — не единичный случай, а свойство быстро меняющегося продукта. Незакреплённая версия превращает это свойство в поломку конвейера.

Что в этой схеме работает в вашу пользу: права по умолчанию узкие (только чтение), запуск вне репозитория запрещён, провал машиночитаем, а официальный шаблон с патчем-артефактом позволяет оставить человека в контуре, не замедляя конвейер.

Что устареет первым. Состав флагов и наличие отдельных опций — проверяйте командой codex exec --help на своей версии. Дальше — тарифная сетка и цены API (курс кредита придётся пересчитать), затем набор входов экшена: сверяйте с action.yml того тега, который закрепили. Статус экспериментальных команд вроде codex cloud exec тоже меняется.

FAQ

Какой код возврата даёт codex exec, если агент не справился? По замеру на версии 0.147.0 — 1. Тот же код приходит при запуске вне git-репозитория. Код 2 означает другое: Codex до работы не приступал, потому что не разобрал командную строку (неизвестный флаг, опечатка). Проверять $? обязательно: без этого упавший прогон выглядит в конвейере успешным, а артефакт остаётся пустым.

Почему codex exec завис и ничего не выводит? Скорее всего, открыт поток ввода. Codex поддерживает передачу данных через трубу и добавляет содержимое stdin к промпту, поэтому ждёт, пока труба закроется, даже если задача уже передана аргументом. В логе при этом одна строка — «Reading additional input from stdin…». Лечится добавлением < /dev/null к команде.

Можно ли запускать codex exec по расписанию через cron? Да, это обычная консольная команда. Три вещи обязательны: закрыть stdin, поставить внешний потолок времени через timeout и передавать ключ на сам вызов, а не экспортировать в окружение. Полезно добавить --ephemeral, чтобы прогон не оставлял файлов сессии, и писать поток --json в файл — иначе разбирать ночной инцидент будет нечем.

Нужен ли для CI ключ API или хватит подписки ChatGPT? Официально рекомендован ключ: его проще выдавать, отзывать и ротировать. Работа под аккаунтом ChatGPT поддержана, но требует возить между рейсами файл auth.json и соблюдать три правила: не перезаписывать его исходным секретом, не делить между параллельными задачами и не применять эту схему в публичных репозиториях.

Работает ли codex exec вне git-репозитория? По умолчанию нет: прогон завершается с кодом 1 и сообщением «Not inside a trusted directory and —skip-git-repo-check was not specified». Ограничение защищает от разрушительных правок там, где нельзя откатиться. Обойти можно флагом --skip-git-repo-check, но делать это стоит осознанно — например, в одноразовом контейнере, где терять нечего.

Чем Codex SDK отличается от вызова codex exec из своего кода? Возможности те же: TypeScript-версия запускает тот же CLI и читает тот же поток JSONL. Отличается форма работы — вы получаете треды, типизированные события, структурированный вывод и управление окружением вместо ручного разбора строк. Если задача помещается в shell-скрипт, SDK не нужен; если вокруг агента растёт своя логика, он экономит много кода.

Курс «OpenAI Codex: агентный кодинг» · модуль «PRO: автономность и качество». Полная программа и два маршрута обучения — на странице курса.

Предыдущий урок: Безопасность и песочница: сеть, секреты

BYBIT COPY TRADING
Копируй профи
Bybit повторит сделки трейдера за тебя
Начать
Поделиться
Связаться:
Крипто- и data-аналитик, инженер-программист (факультет компьютерных наук ХНУРЭ). В IT с 2008 года: администрировал корпоративный мониторинг в «Vodafone Украина», семь лет разрабатывал и продвигал веб-проекты, пять лет руководил маркетингом на метриках — конверсия, CTR, ROI, LTV.Криптовалютными рынками занимаюсь с 2021 года: ончейн-метрики, токеномика, макроэкономические индикаторы. Разработал собственную data-driven модель анализа рынка на 30+ метрик. Стек — Python (pandas, NumPy, SciPy, matplotlib), математическая статистика и EDA; сбор и сверку данных автоматизирую AI-агентами.Принцип — «Don't trust, verify»: каждая цифра проверена по первоисточнику, ключевые — минимум по двум независимым; прогнозы — только сценарии с условиями. Тезис без данных не публикуется.