codex-rs/docs/protocol_v1.md
Overview of Protocol defined in protocol.rs and agent.rs.
The goal of this document is to define terminology used in the system and explain the expected behavior of the system.
NOTE: The code might not completely match this spec. There are a few minor changes that need to be made after this spec has been reviewed, which will not alter the existing TUI's functionality.
These are entities exit on the codex backend. The intent of this section is to establish vocabulary and construct a shared mental model for the Codex core system.
Model
Codex
Model, executes commands and applies patches.Session
Codex's current configuration and stateCodex starts with no Session, and it is initialized by Op::ConfigureSession, which should be the first message sent by the UI.Session can be reconfigured with additional Op::ConfigureSession calls.Task
Task is Codex executing work in response to user input.Session has at most one Task running at a time.Op::UserTurn starts a Task (Op::UserInput is legacy)TurnsTask executes to until:
Model completes the task and there is no output to feed into an additional TurnOp::InterruptModel connection exceeding retry limitsTurn
Task, consists of:
Model - (initially) prompt + (optional) last_response_id, or (in loop) previous turn outputModel streams responses back in an SSE, which are collected until "completed" message and the SSE terminatesCodex then executes command(s), applies patch(es), and outputs message(s) returned by the ModelTurn is the input to the next TurnTurn yielding no output terminates the TaskThe term "UI" is used to refer to the application driving Codex. This may be the CLI / TUI chat-like interface that users operate, or it may be a GUI interface like a VSCode extension. The UI is external to Codex, as Codex is intended to be operated by arbitrary UI implementations.
When a Turn completes, the response_id from the Model's final response.completed message is stored in the Session state to resume the thread given the next user turn. The response_id is also returned in the EventMsg::TurnComplete to the UI, which can be used to fork the thread from an earlier point by providing it in a future user turn.
Since only 1 Task can be run at a time, for parallel tasks it is recommended that a single Codex be run for each thread of work.
Codex
SQ (Submission Queue) and EQ (Event Queue).Submission
SQ (UI -> Codex)sub_idOp refers to the enum of all possible Submission payloads
non_exhaustive; variants can be added at future datesEvent
EQ (Codex -> UI)Event has a non-unique ID, matching the sub_id from the user-turn op that started the current task.EventMsg refers to the enum of all possible Event payloads
non_exhaustive; variants can be added at future datesEventMsg variants will be added over time to expose more detailed information about the model's actions.For complete documentation of the Op and EventMsg variants, refer to protocol.rs. Some example payload types:
Op
Op::UserTurn – Any input from the user to kick off a TurnOp::UserInput – Legacy form of user inputOp::Interrupt – Interrupts a running turnOp::ExecApproval – Approve or deny code executionOp::UserInputAnswer – Provide answers for a request_user_input tool callOp::ListSkills – Request skills for one or more cwd values (optionally force_reload)Op::UserTurn and Op::OverrideTurnContext accept an optional personality override that updates the model’s communication styleValid personality values are friendly, pragmatic, and none. When none is selected, the personality placeholder is replaced with an empty string.
EventMsg
EventMsg::AgentMessage – Messages from the ModelEventMsg::AgentMessageContentDelta – Streaming assistant textEventMsg::PlanDelta – Streaming proposed plan text when the model emits a <proposed_plan> block in plan modeEventMsg::ExecApprovalRequest – Request approval from user to execute a commandEventMsg::RequestUserInput – Request user input for a tool call (questions can include options plus isOther to add a free-form choice)EventMsg::TurnStarted – Turn start metadata including model_context_window and collaboration_mode_kindEventMsg::TurnComplete – A turn completed successfullyEventMsg::Error – A turn stopped with an errorEventMsg::Warning – A non-fatal warning that the client should surface to the userEventMsg::TurnComplete – Contains a response_id bookmark for last response_id executed by the turn. This can be used to continue the turn at a later point in time, perhaps with additional user input.EventMsg::ListSkillsResponse – Response payload with per-cwd skill entries (cwd, skills, errors)Op::UserTurn content items can include:
text – Plain text plus optional UI text elements.image / local_image – Image inputs.skill – Explicit skill selection (name, path to SKILL.md).mention – Explicit app/connector selection (name, path in app://{connector_id} form).Note: For v1 wire compatibility, EventMsg::TurnStarted and EventMsg::TurnComplete serialize as task_started / task_complete. The deserializer accepts both task_* and turn_* tags.
The response_id returned from each turn matches the OpenAI response_id stored in the API's /responses endpoint. It can be stored and used in future Sessions to resume threads of work.
Can operate over any transport that supports bi-directional streaming. - cross-thread channels - IPC channels - stdin/stdout - TCP - HTTP2 - gRPC
Non-framed transports, such as stdin/stdout and TCP, should use newline-delimited JSON in sending messages.
Sequence diagram examples of common interactions. In each diagram, some unimportant events may be eliminated for simplicity.
A single user input, followed by a 2-turn task
sequenceDiagram
box UI
participant user as User
end
box Daemon
participant codex as Codex
participant session as Session
participant task as Task
end
box Rest API
participant agent as Model
end
user->>codex: Op::ConfigureSession
codex-->>session: create session
codex->>user: Event::SessionConfigured
user->>session: Op::UserTurn
session-->>+task: start task
task->>user: Event::TurnStarted
task->>agent: prompt
agent->>task: response (exec)
task->>-user: Event::ExecApprovalRequest
user->>+task: Op::ExecApproval::Allow
task->>user: Event::ExecStart
task->>task: exec
task->>user: Event::ExecStop
task->>user: Event::TurnComplete
task->>agent: stdout
agent->>task: response (patch)
task->>task: apply patch (auto-approved)
task->>agent: success
agent->>task: response
(msg + completed)
task->>user: Event::AgentMessage
task->>user: Event::TurnComplete
task->>-user: Event::TurnComplete
Interrupting a task and continuing with additional user input.
sequenceDiagram
box UI
participant user as User
end
box Daemon
participant session as Session
participant task1 as Task1
participant task2 as Task2
end
box Rest API
participant agent as Model
end
user->>session: Op::UserTurn
session-->>+task1: start task
task1->>user: Event::TurnStarted
task1->>agent: prompt
agent->>task1: response (exec)
task1->>task1: exec (auto-approved)
task1->>user: Event::TurnComplete
task1->>agent: stdout
task1->>agent: response (exec)
task1->>task1: exec (auto-approved)
user->>task1: Op::Interrupt
task1->>-user: Event::Error("interrupted")
user->>session: Op::UserTurn w/ response bookmark
session-->>+task2: start task
task2->>user: Event::TurnStarted
task2->>agent: prompt + Task1 last_response_id
agent->>task2: response (exec)
task2->>task2: exec (auto-approve)
task2->>user: Event::TurnComplete
task2->>agent: stdout
agent->>task2: msg + completed
task2->>user: Event::AgentMessage
task2->>user: Event::TurnComplete
task2->>-user: Event::TurnComplete