Skip to content

Events

Codex is run with codex exec --json, which writes a line-delimited JSON stream on standard output. Each non-empty line is one complete JSON object carrying a top-level type. The harness layer parses that stream into the normalized harness events every caller consumes.

The stream has two layers: lifecycle events describing the conversation and turn boundaries, and item events that wrap a streamed item carrying its own type.

Codex eventHandling
thread.startedCaptures thread_id as the session ID for later events. No event.
turn.started, turn.completedTurn boundaries, consumed. turn.completed carries the usage totals used for metrics. No event.
item.startedThe in-progress half of an item, consumed. No event.
item.completedDrives the normalized event, derived from the completed item.
errorBecomes an error event.
any other typeBecomes an unknown event.

Items are reported first as item.started and then as item.completed. The normalized event is derived from the completed state so terminal information such as a command’s exit code is available.

A line that fails to parse as JSON is a diagnostic printed outside the stream and is surfaced as a warning event. Output on standard error is surfaced as a warning as well.

An item.completed event is unwrapped to its item and mapped by the item’s own type:

Codex item typeNormalized event
command_executioncommand, or a recognized file operation
file_changeone write per changed path
agent_messageagent message
errorerror
any other item typeunknown

An item.completed carrying no item, an unrecognized item type, and a line that fails to parse all become unknown events, so the stream stays lossless. file_change writes are reported with success set to true and no line range.

Codex exposes a single diagnostic channel through error items, which it uses for both errors and advisory notices, and it provides no severity signal, so every error item maps to an error event. Codex has no skill, warning, or orchestration source.

Codex runs file operations through shell commands rather than dedicated tools, so each command_execution is inspected before falling back to a command event. Only the first simple command is considered, and only commands that are confidently a file operation are reclassified:

CommandReclassified as
cat <path>read
sed -n '10,20p' <path>read, with start line 10 and end line 20
rg, grep, findsearch
ls <path>list
anything elsecommand, with the item’s exit code and success

A sed invocation is treated as a read when it is a -n print range. Every other command stays a command event, with the item’s exit_code mapped to the exit code and success fields.