codex exec runs the agent without a TUI - it is the entry point to non-interactive work, scripts and CI. The key design decision here is how the output is arranged. Progress goes to stderr, and the agent's final message to stdout. This separation is not cosmetic: it lets you safely pipe the output without mixing the result with the course of reasoning. A script gets a clean result on stdout, while all the progress noise stays on stderr, where it is expected.
Basic use reads like an ordinary command embedded in the shell. It helps to see examples once. Below are a one-off request, redirecting the result via tee into a file and an ephemeral run that leaves no session. Precisely because the final result goes to stdout, it can be passed on like the output of any other tool - written to a file, passed to the next command, processed. exec turns the agent into a link of a pipeline rather than a separate application.
For programmatic parsing there is a machine-readable mode. The --json flag emits a stream of events that can be processed via jq: instead of human-readable text you get structured events of the work's course. This is the basis for integration into scripts that need not just the final message but visibility of what is happening - which steps the agent took, what it called, how it ended. A machine-readable stream is what makes exec suitable for automation, not only for a one-off run.
Structured output is the most powerful part of exec for integration. It helps to see how it works once. Below is a JSON Schema describing the expected shape of the result: for example, the number of risks and an array of their descriptions. By setting a schema, you get from the agent not free text but data of a defined structure that can be parsed at once without parsing prose. This turns the agent's output from something to interpret into something that can be consumed programmatically.
The schema is attached with explicit flags, and the result is put into a file. Below is a request with --output-schema pointing to a schema file and --output-last-message saving the final result to a file. The bundle is simple and reliable: the schema sets the shape, the last message is saved separately from the progress stream. After the run a script reads a ready JSON of the defined structure rather than reading the result out of mixed output, guessing where progress ends and the answer begins.
The discipline of exec is the discipline of automation, not interactive work. In a non-interactive run there is no one to approve actions on the fly, so the boundaries are set in advance: the sandbox, permissions, the approval mode - all in the command itself or a profile, not along the way. This is exactly why explicit flags are more reliable for CI: the run must behave the same without a human at the terminal. exec does not forgive "I'll fix it on the fly" - it is either configured correctly in advance or behaves unpredictably.
The point of exec is to embed the agent into the existing toolset, not to replace it. The separation of stdout and stderr, machine-readable events and structured output all make the agent the same kind of link as a compiler or a linter: it gets an input, gives a structured output, fits into a pipeline. This is the path from one-off convenience to reproducible automation: an agent whose output can be reliably consumed programmatically rather than retold by eye.
The typical failures around exec are predictable. Mixing progress and the result by reading everything from one stream instead of stdout for the answer. Parsing free text where it was worth setting an output-schema and getting a structure. Relying on approval on the fly in a non-interactive run where there is no one to give it. And not setting the sandbox and permissions explicitly in the command for CI. Separate stdout and stderr, set a schema for a structured result and configure the boundaries in advance - exec is strong precisely in its predictability.
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"
# a machine-readable event stream
codex exec --json "Summarize repository structure" | jq
# progress -> stderr, final message -> stdout (safe pipe)# Structured output by 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"] }