This document describes how tools emit events during their execution lifecycle and how tool outputs are formatted, truncated, and delivered to different consumers (models, UI clients, persistence layer). Tool events enable real-time progress updates, approval workflows, and streaming output to clients while tool outputs are carefully formatted to stay within model context limits.
For information about tool registration and selection, see Tool Registry and Configuration. For tool execution orchestration and sandboxing, see Tool Orchestration and Approval and Sandboxing Implementation.
Tools emit events at different stages of their execution to provide real-time feedback and enable streaming workflows. All tool execution follows a common lifecycle managed by the ToolEmitter abstraction.
The ToolEventStage enum defines three phases:
ExecToolCallOutputSources: codex-rs/core/src/tools/events.rs52-62
Different tool types emit specialized events:
| Tool Type | Begin Event | End Event | Streaming Events | Special Events |
|---|---|---|---|---|
| Shell/Exec | ExecCommandBeginEvent | ExecCommandEndEvent | ExecCommandOutputDeltaEvent | - |
| UnifiedExec | ExecCommandBeginEvent | ExecCommandEndEvent | ExecCommandOutputDeltaEvent, TerminalInteraction | Background exit watching |
| ApplyPatch | PatchApplyBeginEvent | PatchApplyEndEvent | TurnDiffEvent | File change tracking |
| MCP Tools | McpToolCallBeginEvent | McpToolCallEndEvent | - | Elicitation requests |
| WebSearch | WebSearchBegin | WebSearchEndEvent | - | Query/action details |
Sources: codex-rs/core/src/tools/events.rs89-280 codex-rs/core/src/protocol/protocol.rs (event definitions)
The ToolEmitter enum provides a concrete, allocation-free abstraction for emitting events without trait objects or boxed futures. Each variant corresponds to a specific tool category.
The emitter pattern centralizes event logic:
ExecCommandBegin/End with parsed commands and outputPatchApplyBegin/End with file change summariesExecCommandBegin/End with optional process ID for long-lived PTYsSources: codex-rs/core/src/tools/events.rs89-149 codex-rs/core/src/tools/events.rs151-280
The ToolEventCtx carries session/turn references and the call ID for correlation:
Sources: codex-rs/core/src/tools/events.rs28-50 codex-rs/core/src/tools/handlers/shell.rs310-368
Tool outputs are formatted and truncated to fit within model context windows while preserving essential information. Different formatting strategies apply based on tool type and output characteristics.
The truncation system uses token-based limits with configurable policies:
approx_token_count(text) = text.chars().count() / 4HeadTailBuffer to preserve both start and end of outputSources: codex-rs/core/src/truncate.rs codex-rs/core/src/unified_exec/head_tail_buffer.rs
Each tool type has a dedicated formatter:
UnifiedExec Response Format:
Shell/Exec Output Format:
The format_exec_output_str function creates a structured output with exit status, timing, and truncated stdout/stderr streams.
Sources: codex-rs/core/src/tools/handlers/unified_exec.rs274-301 codex-rs/core/src/tools/format_exec_output.rs
UnifiedExec uses a sophisticated buffer system for long-running processes:
Key constants controlling buffering:
UNIFIED_EXEC_OUTPUT_MAX_BYTES: 1MB total buffer retentionUNIFIED_EXEC_OUTPUT_DELTA_MAX_BYTES: 8KB per delta eventMAX_EXEC_OUTPUT_DELTAS_PER_CALL: 50 deltas per tool callSources: codex-rs/core/src/unified_exec/async_watcher.rs26-172 codex-rs/core/src/unified_exec/head_tail_buffer.rs codex-rs/core/src/exec.rs17
Events follow different paths depending on consumer needs. The system distinguishes between real-time streaming (to UI clients), model submission (as ResponseItems), and persistence (to rollout files).
Sources: codex-rs/core/src/codex.rs (Session::send_event), codex-rs/core/src/rollout/policy.rs63-174
Not all events are persisted to rollout files. The EventPersistenceMode enum controls what gets saved:
Limited Mode (default) persists:
Extended Mode additionally persists:
ExecCommandEnd, PatchApplyEnd, McpToolCallEndError, WebSearchEndNever persisted (streaming-only):
AgentMessageDelta, ExecCommandOutputDelta)Sources: codex-rs/core/src/rollout/policy.rs6-174
Different interfaces consume events differently:
| Processor | Purpose | Events Displayed | Output Format |
|---|---|---|---|
EventProcessorWithHumanOutput | Exec mode (stderr) | Most events with formatting | Colored text with emojis |
EventProcessorWithJsonOutput | Exec mode (JSON) | All events | One JSON per line |
TUI ChatWidget | Interactive terminal | All events | Rendered cells with styling |
App Server bespoke_event_handling | IDE clients | All events | Protocol v2 notifications |
The human output processor applies terminal formatting:
Sources: codex-rs/exec/src/event_processor_with_human_output.rs56-126 codex-rs/exec/src/event_processor.rs6-26
Standard shell tools emit a straightforward begin/end pattern:
The ExecCommandBeginEvent includes parsed command details for approval UIs:
Sources: codex-rs/core/src/tools/events.rs64-88 codex-rs/core/src/tools/handlers/shell.rs254-368
UnifiedExec emits additional events for long-running interactive processes:
The streaming task emits delta events until either:
MAX_EXEC_OUTPUT_DELTAS_PER_CALL (50) is reachedSources: codex-rs/core/src/unified_exec/process_manager.rs157-289 codex-rs/core/src/unified_exec/async_watcher.rs39-141
For long-lived UnifiedExec sessions, write_stdin emits TerminalInteractionEvent:
This event is emitted after writing to the PTY but before returning the output snapshot, allowing clients to track what input was sent.
Sources: codex-rs/core/src/tools/handlers/unified_exec.rs208-232 codex-rs/core/src/protocol/protocol.rs (TerminalInteractionEvent definition)
Apply patch tools emit specialized events with file change details:
The FileChange enum supports three operation types:
Sources: codex-rs/core/src/tools/events.rs173-254 codex-rs/core/src/tools/handlers/apply_patch.rs80-169
MCP tools follow a simplified event pattern without streaming:
The McpInvocation struct captures the fully-qualified tool name (server.tool) and arguments for display:
Sources: codex-rs/core/src/protocol/protocol.rs (event definitions), codex-rs/exec/src/event_processor_with_human_output.rs351-392
Different interfaces format tool events differently for their target audience.
The exec mode processor formats events with ANSI colors and emojis:
Key formatting patterns:
A (add), M (modify), D (delete), R (rename)Sources: codex-rs/exec/src/event_processor_with_human_output.rs318-524
When Codex acts as an MCP server, events are translated to MCP-compatible notifications:
Most tool events are forwarded as generic notifications, with the exception of:
TurnComplete triggers a CallToolResult responseError triggers a CallToolResult with is_error: trueSources: codex-rs/mcp-server/src/codex_tool_runner.rs191-401 codex-rs/app-server/src/bespoke_event_handling.rs
The truncation policy preserves diagnostic value:
Before truncation (15,000 tokens):
[... full output ...]
After truncation (10,000 tokens):
[... first 5,000 tokens ...]
[... output truncated: 5,000 tokens omitted ...]
[... last 5,000 tokens ...]
UnifiedExec's HeadTailBuffer ensures both the start (for context) and end (for error messages) are visible even when output exceeds limits.
Sources: codex-rs/core/src/truncate.rs codex-rs/core/src/unified_exec/head_tail_buffer.rs
Event Emission Core:
ToolEmitter enum and emission logicemit_exec_command_begin helperOutput Formatting:
format_response for UnifiedExecformat_exec_output_str for shell toolsEvent Processing:
EventProcessor traitProtocol Integration:
Refresh this wiki