codex exec запускает агента без TUI - это точка входа в неинтерактивную работу, скрипты и CI. Ключевое проектное решение здесь - как устроен вывод. Прогресс идёт в stderr, а финальное сообщение агента - в stdout. Это разделение не косметическое: оно позволяет безопасно направлять вывод по конвейеру, не смешивая результат с ходом рассуждения. Скрипт получает в stdout чистый результат, а весь шум прогресса остаётся в stderr, куда его и ждут.
Базовое использование читается как обычная команда, встроенная в shell. Полезно один раз увидеть примеры. Ниже - разовый запрос, перенаправление результата через tee в файл и эфемерный прогон, не оставляющий сессии. Именно потому, что финальный результат идёт в stdout, его можно передать дальше как вывод любого другого инструмента - записать в файл, передать в следующую команду, обработать. exec превращает агента в звено конвейера, а не в отдельное приложение.
Для программного разбора есть машиночитаемый режим. Флаг --json выдаёт поток событий, который можно обработать через jq: вместо человекочитаемого текста вы получаете структурированные события хода работы. Это основа для интеграции в скрипты, которым нужно не просто финальное сообщение, а видимость происходящего - какие шаги агент сделал, что вызвал, чем закончил. Машиночитаемый поток - это то, что делает exec пригодным для автоматизации, а не только для разового запуска.
Structured output - самая мощная часть exec для интеграции. Полезно один раз увидеть, как это устроено. Ниже - JSON Schema, описывающая ожидаемую форму результата: например, число рисков и массив их описаний. Задав схему, вы получаете от агента не свободный текст, а данные заданной структуры, которые сразу можно разобрать без парсинга прозы. Это превращает вывод агента из того, что нужно интерпретировать, в то, что можно потреблять программно.
Схему подключают явными флагами, и результат кладут в файл. Ниже - запрос с --output-schema, указывающим на файл схемы, и --output-last-message, сохраняющим финальный результат в файл. Связка проста и надёжна: схема задаёт форму, последнее сообщение сохраняется отдельно от потока прогресса. Скрипт после прогона читает готовый JSON заданной структуры, а не вычитывает результат из смешанного вывода, гадая, где кончается прогресс и начинается ответ.
Дисциплина exec - это дисциплина автоматизации, а не интерактива. В неинтерактивном прогоне некому одобрять действия на лету, поэтому границы задают заранее: sandbox, permissions, режим подтверждения - всё в самой команде или профиле, а не по ходу. Это ровно та причина, по которой для CI надёжнее явные флаги: прогон должен вести себя одинаково без человека за терминалом. exec не прощает "поправлю на ходу" - он либо настроен верно заранее, либо ведёт себя непредсказуемо.
Смысл exec - встроить агента в существующий инструментарий, а не заменить его собой. Разделение stdout и stderr, машиночитаемые события и structured output - всё это делает агента таким же звеном, как компилятор или линтер: он получает вход, отдаёт структурированный выход, встраивается в конвейер. Это и есть путь от разового удобства к воспроизводимой автоматизации: агент, чей вывод можно надёжно потребить программно, а не пересказать глазами.
Типичные провалы вокруг exec предсказуемы. Смешать прогресс и результат, читая всё из одного потока вместо stdout для ответа. Разбирать свободный текст там, где стоило задать output-schema и получить структуру. Понадеяться на подтверждение по ходу в неинтерактивном прогоне, где его некому дать. И не задать sandbox и permissions явно в команде для CI. Разделяйте stdout и stderr, задавайте схему для структурированного результата и настраивайте границы заранее - exec силён именно предсказуемостью.
codex exec "Summarize repository structure and list five risky areas"
codex exec "Generate release notes for the last ten commits" | tee release-notes.md
codex exec --ephemeral "Triage this repository"
# машиночитаемый поток событий
codex exec --json "Summarize repository structure" | jq
# progress -> stderr, final message -> stdout (безопасный pipe)# Structured output по JSON Schema
codex exec "Extract the repository risk summary" \
--output-schema ./schema.json \
--output-last-message ./risk-summary.json
# schema.json: { "type":"object","properties":{
# "risk_count":{"type":"integer"},
# "risks":{"type":"array","items":{"type":"string"}} }, "required":["risk_count","risks"] }