feat: codex exec writes only the final message to stdout (#4644)

This updates `codex exec` so that, by default, most of the agent's
activity is written to stderr so that only the final agent message is
written to stdout. This makes it easier to pipe `codex exec` into
another tool without extra filtering.

I introduced `#![deny(clippy::print_stdout)]` to help enforce this
change and renamed the `ts_println!()` macro to `ts_msg()` because (1)
it no longer calls `println!()` and (2), `ts_eprintln!()` seemed too
long of a name.

While here, this also adds `-o` as an alias for `--output-last-message`.

Fixes https://github.com/openai/codex/issues/1670
This commit is contained in:
Michael Bolin
2025-10-03 09:22:12 -07:00
committed by GitHub
parent 5af08e0719
commit 042d4d55d9
6 changed files with 99 additions and 67 deletions

View File

@@ -10,12 +10,18 @@ In non-interactive mode, Codex does not ask for command or edit approvals. By de
Use `codex exec --full-auto` to allow file edits. Use `codex exec --sandbox danger-full-access` to allow edits and networked commands.
### Default output mode
By default, Codex streams its activity to stderr and only writes the final message from the agent to stdout. This makes it easier to pipe `codex exec` into another tool without extra filtering.
To write the output of `codex exec` to a file, in addition to using a shell redirect like `>`, there is also a dedicated flag to specify an output file: `-o`/`--output-last-message`.
### JSON output mode
`codex exec` supports a `--json` mode that streams events to stdout as JSON Lines (JSONL) while the agent runs.
Supported event types:
- `thread.started` - when a thread is started or resumed.
- `turn.started` - when a turn starts. A turn encompasses all events between the user message and the assistant response.
- `turn.completed` - when a turn completes; includes token usage.
@@ -23,6 +29,7 @@ Supported event types:
- `item.started`/`item.updated`/`item.completed` - when a thread item is added/updated/completed.
Supported item types:
- `assistant_message` - assistant message.
- `reasoning` - a summary of the assistant's thinking.
- `command_execution` - assistant executing a command.
@@ -33,6 +40,7 @@ Supported item types:
Typically, an `assistant_message` is added at the end of the turn.
Sample output:
```jsonl
{"type":"thread.started","thread_id":"0199a213-81c0-7800-8aa1-bbab2a035a53"}
{"type":"turn.started"}
@@ -54,13 +62,13 @@ Sample schema:
```json
{
"type": "object",
"properties": {
"project_name": { "type": "string" },
"programming_languages": { "type": "array", "items": { "type": "string" } }
},
"required": ["project_name", "programming_languages"],
"additionalProperties": false
"type": "object",
"properties": {
"project_name": { "type": "string" },
"programming_languages": { "type": "array", "items": { "type": "string" } }
},
"required": ["project_name", "programming_languages"],
"additionalProperties": false
}
```
@@ -77,17 +85,16 @@ Combine `--output-schema` with `-o` to only print the final JSON output. You can
Codex requires a Git repository to avoid destructive changes. To disable this check, use `codex exec --skip-git-repo-check`.
### Resuming non-interactive sessions
Resume a previous non-interactive session with `codex exec resume <SESSION_ID>` or `codex exec resume --last`. This preserves conversation context so you can ask follow-up questions or give new tasks to the agent.
Resume a previous non-interactive session with `codex exec resume <SESSION_ID>` or `codex exec resume --last`. This preserves conversation context so you can ask follow-up questions or give new tasks to the agent.
```shell
codex exec "Review the change, look for use-after-free issues"
codex exec resume --last "Fix use-after-free issues"
```
Only the conversation context is preserved; you must still provide flags to customize Codex behavior.
Only the conversation context is preserved; you must still provide flags to customize Codex behavior.
```shell
codex exec --model gpt-5-codex --json "Review the change, look for use-after-free issues"