The Apply Patch System provides a specialized tool for file editing that uses a simplified, structured patch format designed to be easy for language models to generate and safe to parse. Unlike general shell execution, this system validates patches before applying them and emits granular events for tracking file changes.
For information about general command execution, see Shell Execution Tools. For unified exec process management, see Unified Exec Process Management. For tool approval and sandboxing orchestration, see Tool Orchestration and Approval.
The apply_patch tool accepts a stripped-down, file-oriented diff format with three fundamental operations:
*** Begin Patch
*** Add File: <path>
+<line1>
+<line2>
...
*** Update File: <path>
[*** Move to: <new_path>]
@@ [header]
<context_line>
-<removed_line>
+<added_line>
...
*** Delete File: <path>
*** End Patch
Key Features:
*** Move to:@@ headers to specify context (class, function) when needed ) disambiguate code locationsSources: codex-rs/core/src/tools/handlers/apply_patch.rs305-378
Sources: codex-rs/core/src/tools/handlers/apply_patch.rs278-288 codex-rs/core/src/tools/handlers/apply_patch.rs37
The freeform variant uses a Lark grammar definition that allows models to output patches directly without JSON wrapping:
ToolSpec::Freeform(FreeformTool {
name: "apply_patch",
format: FreeformToolFormat {
type: "grammar",
syntax: "lark",
definition: APPLY_PATCH_LARK_GRAMMAR
}
})
This is the preferred variant for GPT-5 class models that support custom tools.
Sources: codex-rs/core/src/tools/handlers/apply_patch.rs291-378
For models that don't support freeform tools, the JSON variant wraps the patch content in a structured function call:
The input field contains the entire patch as a string.
Sources: codex-rs/core/src/tools/handlers/apply_patch.rs80-188
The ApplyPatchHandler implements the ToolHandler trait and processes both JSON and freeform payloads:
| Payload Type | Extraction Method |
|---|---|
ToolPayload::Function { arguments } | Parse JSON to ApplyPatchToolArgs, extract args.input |
ToolPayload::Custom { input } | Use input directly |
Sources: codex-rs/core/src/tools/handlers/apply_patch.rs90-101
The handler delegates to codex_apply_patch::maybe_parse_apply_patch_verified() which returns:
MaybeApplyPatchVerified::Body(changes) - Valid patch, proceed to applicationMaybeApplyPatchVerified::CorrectnessError(err) - Patch format violationsMaybeApplyPatchVerified::ShellParseError(err) - Failed to parse as shell commandMaybeApplyPatchVerified::NotApplyPatch - Not an apply_patch commandSources: codex-rs/core/src/tools/handlers/apply_patch.rs107-187
When apply_patch::apply_patch() returns InternalApplyPatchInvocation::Output(item), the patch can be applied without exec orchestration (e.g., simple validations or auto-approved changes).
Sources: codex-rs/core/src/tools/handlers/apply_patch.rs109-116
For patches requiring approval or sandboxed execution:
ApplyPatchAction to protocol FileChange mapApplyPatchRequest with:
action: The parsed patch actionfile_paths: Absolute paths for approval trackingchanges: Protocol-format changes for eventsexec_approval_requirement: Pre-computed approval requirementtimeout_ms: Optional timeoutcodex_exe: Path to codex binary for sandbox executionSources: codex-rs/core/src/tools/handlers/apply_patch.rs118-137
Models sometimes generate shell commands like bash -c "apply_patch <<'EOF' ..." instead of using the dedicated tool. The interception system detects these patterns and routes them through the proper patch handler.
Sources: codex-rs/core/src/tools/handlers/apply_patch.rs192-274 codex-rs/core/src/tools/handlers/shell.rs295-308 codex-rs/core/src/tools/handlers/unified_exec.rs171-185
| Handler | Interception Location | Cleanup Required |
|---|---|---|
ShellHandler | Before ToolOrchestrator::run() | None |
ShellCommandHandler | Before ToolOrchestrator::run() | None |
UnifiedExecHandler | After allocate_process_id(), before open_session_with_sandbox() | Must release_process_id() |
Sources: codex-rs/core/src/tools/handlers/unified_exec.rs171-185
Returns Ok(Some(output)) when interception occurs, Ok(None) when the command is not apply_patch.
Sources: codex-rs/core/src/tools/handlers/apply_patch.rs192-201
When interception occurs, the system records a warning to the model:
"apply_patch was requested via {tool_name}. Use the apply_patch tool instead of exec_command."
This feedback trains models to use the proper tool.
Sources: codex-rs/core/src/tools/handlers/apply_patch.rs204-209
Sources: codex-rs/core/src/tools/handlers/apply_patch.rs130-156
The ApplyPatchRequest passed to the orchestrator contains:
Sources: codex-rs/core/src/tools/runtimes/apply_patch.rs (implied structure from usage)
The file_paths_for_action() function extracts all files involved in the patch, including move destinations:
This ensures approval requests cover both source and destination files.
Sources: codex-rs/core/src/tools/handlers/apply_patch.rs39-56
The orchestrator handles:
SandboxPolicy)Sources: codex-rs/core/src/tools/handlers/apply_patch.rs139-156
Sources: codex-rs/core/src/tools/events.rs170-254 codex-rs/core/src/tools/events.rs491-525
Emitted before execution with:
File changes format:
Sources: codex-rs/core/src/tools/events.rs178-192
Emitted after execution with:
Sources: codex-rs/core/src/tools/events.rs491-512
If a SharedTurnDiffTracker is provided, the system:
tracker.on_patch_begin(changes) at begin eventtracker.get_unified_diff()EventMsg::TurnDiff(TurnDiffEvent) with the complete unified diffThis enables UI clients to display cumulative file changes across all tools in a turn.
Sources: codex-rs/core/src/tools/events.rs514-524
The test suite verifies that exec_command via unified exec properly intercepts apply_patch:
The test confirms:
PatchApplyBegin emitted with correct file changesPatchApplyEnd emitted with success statusExecCommandBegin never emitted (intercepted)Sources: codex-rs/core/tests/suite/unified_exec.rs159-285
The Apply Patch System provides a structured, safe file editing mechanism with:
| Component | Responsibility |
|---|---|
| Patch Format | Simplified diff syntax with Add/Update/Delete operations |
| Tool Variants | Freeform (Lark grammar) for advanced models, JSON for legacy |
| Handler | Parsing, validation, and delegation to orchestrator |
| Interception | Detects apply_patch in shell/exec commands, routes to handler |
| Orchestration | Approval prompting, sandbox selection, execution retry |
| Events | Granular begin/end events with file change details, diff tracking |
This design ensures models can edit files reliably while maintaining full visibility and control through the approval and sandboxing systems.
Refresh this wiki