Files
codex/codex-rs/docs/orchestrator_executor.md
2026-03-22 10:19:49 -07:00

5.2 KiB

Orchestrator and Executor Split

Goal

Codex should be able to route tool calls through a remote executor without teaching every tool implementation about remote filesystems, RPC retries, or model-specific defaults.

For unified exec, the main rule should be:

  • the executor advertises the exec_command and write_stdin tool contracts
  • the orchestrator forwards tool calls plus any orchestrator-owned overrides
  • the executor owns host-local execution details, session ids, and process lifecycle
  • the executor does not invent model-dependent policy that only the orchestrator can know

Current Ownership Leak

Today the unified exec path is split across several layers:

  • core/src/tools/handlers/unified_exec.rs parses model args and normalizes approval-related fields
  • core/src/unified_exec/process_manager.rs still derives execution env, approval requirements, and other execution inputs from TurnContext
  • core/src/tools/runtimes/unified_exec.rs still rewrites commands for shell snapshot and PowerShell handling
  • core/src/tools/spec.rs still statically advertises unified exec from the orchestrator side instead of learning it from the executor

That makes the executor boundary fuzzy. A future remote executor would need to know more than "handle this tool call" because some request fields are still hidden behind local helpers and the tool itself is not yet executor-owned.

Ownership Rule

The orchestrator owns:

  • model sampling
  • tool routing and dynamic tool registration
  • model-facing tool-call parsing
  • shell selection and final argv construction
  • working-directory resolution
  • execution environment construction
  • approval-policy evaluation
  • output-policy selection, including max output truncation for the tool result

The executor owns:

  • advertising host-local tool specs such as unified exec
  • spawning and tracking the process
  • streaming and buffering raw output
  • minting unified-exec session ids
  • applying the already selected sandbox attempt
  • returning the requested output slice for the current poll
  • filesystem and host-local resource access that should happen on the executor host

Unified Exec Wire Contract

The unified exec boundary should be expressed as an executor-advertised tool contract plus explicit orchestrator overrides that can be serialized and sent over a future executor transport.

UnifiedExecExecCommandRequest

  • command: final argv vector
  • cwd: absolute working directory
  • env: fully constructed environment for the command
  • tty: whether to allocate a PTY
  • yield_time_ms: initial poll window
  • max_output_tokens: tool-output truncation budget selected by the orchestrator
  • sandbox_permissions: already normalized sandbox request
  • additional_permissions: already normalized additional permissions
  • additional_permissions_preapproved: whether those permissions are already sticky-approved
  • justification: optional user-facing approval reason
  • exec_approval_requirement: resolved approval plan for this request

The executor's exec_command tool result should include:

  • process_id: stable unified-exec session id chosen by the executor when the session stays open after the initial poll
  • no process_id for short-lived commands that exit before the initial poll completes

UnifiedExecWriteStdinRequest

  • process_id: existing unified-exec session id
  • input: bytes to write, expressed as text for the tool path
  • yield_time_ms: poll window for this write or empty poll
  • max_output_tokens: tool-output truncation budget selected by the orchestrator

These are intentionally higher level than codex-exec-server's low-level process/start, process/read, and process/write methods. Unified exec is a tool contract owned by the executor; the executor transport can map that contract onto lower-level process RPCs internally.

Phase Plan

  1. Let the executor advertise unified exec tool specs to the orchestrator, similar to MCP listTools.
  2. Define protocol-owned unified-exec request types for executor-owned tool calls plus orchestrator-owned overrides.
  3. Make the executor side mint unified-exec session ids and return them in tool results.
  4. Move the host-local unified-exec implementation behind the executor boundary.
  5. Reuse the same request types for a remote executor transport.

Crate Split

  • codex-executor-protocol: shared executor transport types with minimal dependencies
  • codex-executor: executor-side receive loop and future transport adapter
  • codex-cli: codex executor subcommand that launches the executor process

Follow-ups

This work does not fully remove every host-local concern yet. In particular:

  • remote network-proxy binding is still local to the executor path
  • zsh-fork backend setup remains local because it depends on executor-host binaries and inherited file descriptors
  • shell snapshot capture and executor bootstrapping still need a broader context-gathering protocol
  • unified exec is still statically registered by the orchestrator today rather than advertised by the executor

Those should be follow-up steps, but they should build on the same principle: the orchestrator chooses only the policy and routing inputs that are truly orchestrator-owned, while the executor owns host-local tool behavior.