Skip to main content

codex_codes/
protocol.rs

1//! App-server protocol types for the Codex CLI.
2//!
3//! Every wire type is generated from the upstream JSON Schema bundle by
4//! `scripts/codegen_protocol.py` and lives in [`crate::protocol_generated::types`].
5//! This module re-exports them and adds the JSON-RPC method-name constants
6//! the dispatch layer matches against.
7//!
8//! # Parsing notifications
9//!
10//! Prefer the typed dispatch in [`crate::messages`] over manual `method` checks:
11//!
12//! ```
13//! use codex_codes::{Notification, ServerMessage};
14//!
15//! fn handle(msg: ServerMessage) {
16//!     if let ServerMessage::Notification(Notification::TurnCompleted(c)) = msg {
17//!         println!("Turn on thread {} completed", c.thread_id);
18//!     }
19//! }
20//! ```
21
22pub use crate::protocol_generated::types::*;
23
24/// JSON-RPC method names used by the app-server protocol.
25///
26/// Use these constants when matching on [`crate::ServerMessage::Notification`] or
27/// [`crate::ServerMessage::Request`] method fields to avoid typos.
28pub mod methods {
29    // Client → server requests
30    pub const INITIALIZE: &str = "initialize";
31    pub const INITIALIZED: &str = "initialized";
32    pub const THREAD_START: &str = "thread/start";
33    pub const THREAD_ARCHIVE: &str = "thread/archive";
34    pub const THREAD_DELETE: &str = "thread/delete";
35    pub const TURN_START: &str = "turn/start";
36    pub const TURN_INTERRUPT: &str = "turn/interrupt";
37    pub const TURN_STEER: &str = "turn/steer";
38    pub const THREAD_RESUME: &str = "thread/resume";
39    pub const THREAD_FORK: &str = "thread/fork";
40    pub const THREAD_UNSUBSCRIBE: &str = "thread/unsubscribe";
41    pub const THREAD_NAME_SET: &str = "thread/name/set";
42    pub const THREAD_METADATA_UPDATE: &str = "thread/metadata/update";
43    pub const THREAD_ATTACHMENT_ADD: &str = "thread/attachment/add";
44    pub const THREAD_ATTACHMENT_LIST: &str = "thread/attachment/list";
45    pub const THREAD_ATTACHMENT_REMOVE: &str = "thread/attachment/remove";
46    pub const THREAD_UNARCHIVE: &str = "thread/unarchive";
47    pub const THREAD_COMPACT_START: &str = "thread/compact/start";
48    pub const THREAD_SHELLCOMMAND: &str = "thread/shellCommand";
49    pub const THREAD_APPROVEGUARDIANDENIEDACTION: &str = "thread/approveGuardianDeniedAction";
50    pub const THREAD_ROLLBACK: &str = "thread/rollback";
51    pub const THREAD_LIST: &str = "thread/list";
52    pub const THREAD_LOADED_LIST: &str = "thread/loaded/list";
53    pub const THREAD_READ: &str = "thread/read";
54    pub const THREAD_INJECT_ITEMS: &str = "thread/inject_items";
55    pub const THREAD_ITEMS_LIST: &str = "thread/items/list";
56    pub const THREAD_TURNS_LIST: &str = "thread/turns/list";
57    pub const THREAD_REVERT: &str = "thread/revert";
58    pub const SKILLS_LIST: &str = "skills/list";
59    pub const HOOKS_LIST: &str = "hooks/list";
60    pub const MARKETPLACE_ADD: &str = "marketplace/add";
61    pub const MARKETPLACE_REMOVE: &str = "marketplace/remove";
62    pub const MARKETPLACE_UPGRADE: &str = "marketplace/upgrade";
63    pub const PLUGIN_LIST: &str = "plugin/list";
64    pub const PLUGIN_READ: &str = "plugin/read";
65    pub const PLUGIN_SKILL_READ: &str = "plugin/skill/read";
66    pub const PLUGIN_SHARE_SAVE: &str = "plugin/share/save";
67    pub const PLUGIN_SHARE_UPDATETARGETS: &str = "plugin/share/updateTargets";
68    pub const PLUGIN_SHARE_LIST: &str = "plugin/share/list";
69    pub const PLUGIN_SHARE_CHECKOUT: &str = "plugin/share/checkout";
70    pub const PLUGIN_SHARE_DELETE: &str = "plugin/share/delete";
71    pub const APP_LIST: &str = "app/list";
72    pub const APP_READ: &str = "app/read";
73    pub const APP_INSTALLED: &str = "app/installed";
74    pub const FS_READFILE: &str = "fs/readFile";
75    pub const FS_WRITEFILE: &str = "fs/writeFile";
76    pub const FS_CREATEDIRECTORY: &str = "fs/createDirectory";
77    pub const FS_GETMETADATA: &str = "fs/getMetadata";
78    pub const FS_READDIRECTORY: &str = "fs/readDirectory";
79    pub const FS_REMOVE: &str = "fs/remove";
80    pub const FS_COPY: &str = "fs/copy";
81    pub const FS_WATCH: &str = "fs/watch";
82    pub const FS_UNWATCH: &str = "fs/unwatch";
83    pub const SKILLS_CONFIG_WRITE: &str = "skills/config/write";
84    pub const PLUGIN_INSTALL: &str = "plugin/install";
85    pub const PLUGIN_UNINSTALL: &str = "plugin/uninstall";
86    pub const REVIEW_START: &str = "review/start";
87    pub const MODEL_LIST: &str = "model/list";
88    pub const MODELPROVIDER_CAPABILITIES_READ: &str = "modelProvider/capabilities/read";
89    pub const EXPERIMENTALFEATURE_LIST: &str = "experimentalFeature/list";
90    pub const EXPERIMENTALFEATURE_ENABLEMENT_SET: &str = "experimentalFeature/enablement/set";
91    pub const MCPSERVER_OAUTH_LOGIN: &str = "mcpServer/oauth/login";
92    pub const CONFIG_MCPSERVER_RELOAD: &str = "config/mcpServer/reload";
93    pub const MCPSERVERSTATUS_LIST: &str = "mcpServerStatus/list";
94    pub const MCPSERVER_RESOURCE_READ: &str = "mcpServer/resource/read";
95    pub const MCPSERVER_TOOL_CALL: &str = "mcpServer/tool/call";
96    pub const WINDOWSSANDBOX_SETUPSTART: &str = "windowsSandbox/setupStart";
97    pub const WINDOWSSANDBOX_READINESS: &str = "windowsSandbox/readiness";
98    pub const ACCOUNT_LOGIN_START: &str = "account/login/start";
99    pub const ACCOUNT_LOGIN_CANCEL: &str = "account/login/cancel";
100    pub const ACCOUNT_LOGOUT: &str = "account/logout";
101    pub const ACCOUNT_RATELIMITS_READ: &str = "account/rateLimits/read";
102    pub const ACCOUNT_SENDADDCREDITSNUDGEEMAIL: &str = "account/sendAddCreditsNudgeEmail";
103    pub const FEEDBACK_UPLOAD: &str = "feedback/upload";
104    pub const COMMAND_EXEC: &str = "command/exec";
105    pub const COMMAND_EXEC_WRITE: &str = "command/exec/write";
106    pub const COMMAND_EXEC_TERMINATE: &str = "command/exec/terminate";
107    pub const COMMAND_EXEC_RESIZE: &str = "command/exec/resize";
108    pub const CONFIG_READ: &str = "config/read";
109    pub const EXTERNALAGENTCONFIG_DETECT: &str = "externalAgentConfig/detect";
110    pub const EXTERNALAGENTCONFIG_IMPORT: &str = "externalAgentConfig/import";
111    pub const CONFIG_VALUE_WRITE: &str = "config/value/write";
112    pub const CONFIG_BATCHWRITE: &str = "config/batchWrite";
113    pub const CONFIGREQUIREMENTS_READ: &str = "configRequirements/read";
114    pub const ACCOUNT_READ: &str = "account/read";
115    pub const FUZZYFILESEARCH: &str = "fuzzyFileSearch";
116    pub const ACCOUNT_USAGE_READ: &str = "account/usage/read";
117    pub const PERMISSION_PROFILE_LIST: &str = "permissionProfile/list";
118    pub const PLUGIN_INSTALLED: &str = "plugin/installed";
119    pub const PLUGIN_RECONCILE: &str = "plugin/reconcile";
120    pub const SKILLS_EXTRA_ROOTS_SET: &str = "skills/extraRoots/set";
121    pub const THREAD_GOAL_GET: &str = "thread/goal/get";
122    pub const THREAD_GOAL_SET: &str = "thread/goal/set";
123    pub const THREAD_GOAL_CLEAR: &str = "thread/goal/clear";
124    pub const THREADSECTION_LIST: &str = "threadSection/list";
125    pub const THREADSECTION_CREATE: &str = "threadSection/create";
126    pub const THREADSECTION_UPDATE: &str = "threadSection/update";
127    pub const THREADSECTION_DELETE: &str = "threadSection/delete";
128    pub const THREAD_SECTION_MOVE: &str = "thread/section/move";
129    pub const ACCOUNT_RATELIMITRESETCREDIT_CONSUME: &str = "account/rateLimitResetCredit/consume";
130    pub const ACCOUNT_WORKSPACEMESSAGES_READ: &str = "account/workspaceMessages/read";
131    pub const EXTERNALAGENTCONFIG_IMPORT_READHISTORIES: &str =
132        "externalAgentConfig/import/readHistories";
133    pub const EXTERNALAGENTCONFIG_IMPORT_RECORDHISTORY: &str =
134        "externalAgentConfig/import/recordHistory";
135
136    // Server → client notifications
137    pub const THREAD_STARTED: &str = "thread/started";
138    pub const STRICT_REVIEW_REQUIRED: &str = "autoApprovalReview/strictReviewRequired";
139    pub const PROJECT_CHANGED: &str = "project/changed";
140    pub const THREAD_PROJECT_UPDATED: &str = "thread/project/updated";
141    pub const THREAD_QUEUE_CHANGED: &str = "thread/queue/changed";
142    pub const THREAD_REVERTED: &str = "thread/reverted";
143    pub const MCP_SERVER_EVENT_STREAM: &str = "mcpServer/event/stream/notification";
144    pub const THREAD_STATUS_CHANGED: &str = "thread/status/changed";
145    pub const THREAD_TOKEN_USAGE_UPDATED: &str = "thread/tokenUsage/updated";
146    pub const TURN_STARTED: &str = "turn/started";
147    pub const TURN_COMPLETED: &str = "turn/completed";
148    pub const ITEM_STARTED: &str = "item/started";
149    pub const ITEM_COMPLETED: &str = "item/completed";
150    pub const AGENT_MESSAGE_DELTA: &str = "item/agentMessage/delta";
151    pub const CMD_OUTPUT_DELTA: &str = "item/commandExecution/outputDelta";
152    pub const FILE_CHANGE_OUTPUT_DELTA: &str = "item/fileChange/outputDelta";
153    pub const REASONING_DELTA: &str = "item/reasoning/summaryTextDelta";
154    pub const ERROR: &str = "error";
155    pub const ACCOUNT_RATE_LIMITS_UPDATED: &str = "account/rateLimits/updated";
156    pub const MCP_SERVER_STARTUP_STATUS_UPDATED: &str = "mcpServer/startupStatus/updated";
157    pub const MCP_SERVER_OAUTH_LOGIN_COMPLETED: &str = "mcpServer/oauthLogin/completed";
158    pub const REMOTE_CONTROL_STATUS_CHANGED: &str = "remoteControl/status/changed";
159    pub const FILE_CHANGE_PATCH_UPDATED: &str = "item/fileChange/patchUpdated";
160    pub const PLAN_DELTA: &str = "item/plan/delta";
161    pub const TURN_PLAN_UPDATED: &str = "turn/plan/updated";
162    pub const TURN_DIFF_UPDATED: &str = "turn/diff/updated";
163    pub const REASONING_SUMMARY_PART_ADDED: &str = "item/reasoning/summaryPartAdded";
164    pub const REASONING_TEXT_DELTA: &str = "item/reasoning/textDelta";
165    pub const ACCOUNT_LOGIN_COMPLETED: &str = "account/login/completed";
166    pub const DEPRECATION_NOTICE: &str = "deprecationNotice";
167    pub const GUARDIAN_WARNING: &str = "guardianWarning";
168    pub const WARNING: &str = "warning";
169    pub const THREAD_ARCHIVED: &str = "thread/archived";
170    pub const THREAD_CLOSED: &str = "thread/closed";
171    pub const THREAD_DELETED: &str = "thread/deleted";
172    pub const THREAD_UNARCHIVED: &str = "thread/unarchived";
173    pub const THREAD_GOAL_CLEARED: &str = "thread/goal/cleared";
174    pub const THREAD_NAME_UPDATED: &str = "thread/name/updated";
175    pub const THREAD_ATTACHMENT_UPDATED: &str = "thread/attachment/updated";
176    pub const SKILLS_CHANGED: &str = "skills/changed";
177    pub const FS_CHANGED: &str = "fs/changed";
178    pub const CONFIG_WARNING: &str = "configWarning";
179    pub const ACCOUNT_UPDATED: &str = "account/updated";
180    pub const APP_LIST_UPDATED: &str = "app/list/updated";
181    pub const COMMAND_EXEC_OUTPUT_DELTA: &str = "command/exec/outputDelta";
182    pub const EXTERNAL_AGENT_CONFIG_IMPORT_COMPLETED: &str = "externalAgentConfig/import/completed";
183    pub const FUZZY_FILE_SEARCH_SESSION_COMPLETED: &str = "fuzzyFileSearch/sessionCompleted";
184    pub const FUZZY_FILE_SEARCH_SESSION_UPDATED: &str = "fuzzyFileSearch/sessionUpdated";
185    pub const HOOK_COMPLETED: &str = "hook/completed";
186    pub const HOOK_STARTED: &str = "hook/started";
187    pub const ITEM_AUTO_APPROVAL_REVIEW_COMPLETED: &str = "item/autoApprovalReview/completed";
188    pub const ITEM_AUTO_APPROVAL_REVIEW_STARTED: &str = "item/autoApprovalReview/started";
189    pub const ITEM_COMMAND_EXEC_TERMINAL_INTERACTION: &str =
190        "item/commandExecution/terminalInteraction";
191    pub const ITEM_MCP_TOOL_CALL_PROGRESS: &str = "item/mcpToolCall/progress";
192    pub const MODEL_REROUTED: &str = "model/rerouted";
193    pub const MODEL_VERIFICATION: &str = "model/verification";
194    pub const PROCESS_EXITED: &str = "process/exited";
195    pub const PROCESS_OUTPUT_DELTA: &str = "process/outputDelta";
196    pub const SERVER_REQUEST_RESOLVED: &str = "serverRequest/resolved";
197    pub const THREAD_COMPACTED: &str = "thread/compacted";
198    pub const THREAD_GOAL_UPDATED: &str = "thread/goal/updated";
199    pub const THREAD_REALTIME_CLOSED: &str = "thread/realtime/closed";
200    pub const THREAD_REALTIME_ERROR: &str = "thread/realtime/error";
201    pub const THREAD_REALTIME_ITEM_ADDED: &str = "thread/realtime/itemAdded";
202    pub const THREAD_REALTIME_OUTPUT_AUDIO_DELTA: &str = "thread/realtime/outputAudio/delta";
203    pub const THREAD_REALTIME_SDP: &str = "thread/realtime/sdp";
204    pub const THREAD_REALTIME_STARTED: &str = "thread/realtime/started";
205    pub const THREAD_REALTIME_TRANSCRIPT_DELTA: &str = "thread/realtime/transcript/delta";
206    pub const THREAD_REALTIME_TRANSCRIPT_DONE: &str = "thread/realtime/transcript/done";
207    pub const THREAD_REALTIME_ITEM_STARTED: &str = "thread/realtime/item/started";
208    pub const THREAD_REALTIME_ITEM_COMPLETED: &str = "thread/realtime/item/completed";
209    pub const THREAD_REALTIME_ITEM_TRANSCRIPT_DELTA: &str = "thread/realtime/item/transcript/delta";
210    pub const MODEL_PROVIDER_AUTH_RECOVERY_STARTED: &str = "modelProvider/authRecoveryStarted";
211    pub const MODEL_PROVIDER_AUTH_RECOVERY_COMPLETED: &str = "modelProvider/authRecoveryCompleted";
212    pub const WINDOWS_WORLD_WRITABLE_WARNING: &str = "windows/worldWritableWarning";
213    pub const WINDOWS_SANDBOX_SETUP_COMPLETED: &str = "windowsSandbox/setupCompleted";
214    pub const THREAD_SETTINGS_UPDATED: &str = "thread/settings/updated";
215    pub const TURN_MODERATION_METADATA: &str = "turn/moderationMetadata";
216    pub const EXTERNAL_AGENT_CONFIG_IMPORT_PROGRESS: &str = "externalAgentConfig/import/progress";
217    pub const MODEL_SAFETY_BUFFERING_UPDATED: &str = "model/safetyBuffering/updated";
218    pub const THREAD_ENVIRONMENT_CONNECTED: &str = "thread/environment/connected";
219    pub const THREAD_ENVIRONMENT_DISCONNECTED: &str = "thread/environment/disconnected";
220
221    // Server → client requests (approval flow, v2 envelope)
222    pub const CMD_EXEC_APPROVAL: &str = "item/commandExecution/requestApproval";
223    pub const FILE_CHANGE_APPROVAL: &str = "item/fileChange/requestApproval";
224    pub const TOOL_REQUEST_USER_INPUT: &str = "item/tool/requestUserInput";
225    pub const MCP_SERVER_ELICITATION_REQUEST: &str = "mcpServer/elicitation/request";
226    pub const PERMISSIONS_REQUEST_APPROVAL: &str = "item/permissions/requestApproval";
227    pub const ITEM_TOOL_CALL: &str = "item/tool/call";
228    pub const CHATGPT_AUTH_TOKENS_REFRESH: &str = "account/chatgptAuthTokens/refresh";
229    pub const ATTESTATION_GENERATE: &str = "attestation/generate";
230    pub const APPLY_PATCH_APPROVAL: &str = "applyPatchApproval";
231    pub const EXEC_COMMAND_APPROVAL: &str = "execCommandApproval";
232}
233
234// ──────────────────────────────────────────────────────────────────────────
235// Ergonomic constructors over the generated wire types.
236//
237// The types themselves are code-generated from the upstream schema; these
238// hand-written impls live here so they survive regeneration. (`Default` for
239// params whose fields are all serde-defaultable is derived by the codegen
240// itself since #203.) They cover one pain point for downstream consumers:
241//
242//   * `accept` / `decline` / `approved` / `denied` constructors for the
243//     approval-response payloads, so callers don't hand-roll `serde_json`
244//     objects and can't typo the wire `decision` string.
245// ──────────────────────────────────────────────────────────────────────────
246
247impl FileChangeRequestApprovalResponse {
248    /// Approve this file-change request (`{"decision":"accept"}`).
249    pub fn accept() -> Self {
250        Self {
251            decision: FileChangeApprovalDecision::Accept,
252        }
253    }
254
255    /// Approve this and future file changes for the session.
256    pub fn accept_for_session() -> Self {
257        Self {
258            decision: FileChangeApprovalDecision::AcceptForSession,
259        }
260    }
261
262    /// Decline this file-change request (`{"decision":"decline"}`).
263    pub fn decline() -> Self {
264        Self {
265            decision: FileChangeApprovalDecision::Decline,
266        }
267    }
268
269    /// Cancel the turn in response to this request.
270    pub fn cancel() -> Self {
271        Self {
272            decision: FileChangeApprovalDecision::Cancel,
273        }
274    }
275}
276
277impl CommandExecutionRequestApprovalResponse {
278    /// Approve this command execution (`{"decision":"accept"}`).
279    pub fn accept() -> Self {
280        Self {
281            decision: CommandExecutionApprovalDecision::Accept,
282        }
283    }
284
285    /// Approve this and future command executions for the session.
286    pub fn accept_for_session() -> Self {
287        Self {
288            decision: CommandExecutionApprovalDecision::AcceptForSession,
289        }
290    }
291
292    /// Decline this command execution (`{"decision":"decline"}`).
293    pub fn decline() -> Self {
294        Self {
295            decision: CommandExecutionApprovalDecision::Decline,
296        }
297    }
298
299    /// Cancel the turn in response to this request.
300    pub fn cancel() -> Self {
301        Self {
302            decision: CommandExecutionApprovalDecision::Cancel,
303        }
304    }
305}
306
307impl ExecCommandApprovalResponse {
308    /// Approve the exec command (`{"decision":"approved"}`).
309    pub fn approved() -> Self {
310        Self {
311            decision: ReviewDecision::Approved,
312        }
313    }
314
315    /// Approve the exec command for the rest of the session.
316    pub fn approved_for_session() -> Self {
317        Self {
318            decision: ReviewDecision::ApprovedForSession,
319        }
320    }
321
322    /// Deny the exec command (`{"decision":{"denied":{"rejection":...}}}`).
323    pub fn denied(rejection: impl Into<String>) -> Self {
324        Self {
325            decision: ReviewDecision::Denied {
326                rejection: rejection.into(),
327            },
328        }
329    }
330
331    /// Abort the turn in response to the request.
332    pub fn abort() -> Self {
333        Self {
334            decision: ReviewDecision::Abort,
335        }
336    }
337}
338
339impl ApplyPatchApprovalResponse {
340    /// Approve the patch (`{"decision":"approved"}`).
341    pub fn approved() -> Self {
342        Self {
343            decision: ReviewDecision::Approved,
344        }
345    }
346
347    /// Approve this and future patches for the session.
348    pub fn approved_for_session() -> Self {
349        Self {
350            decision: ReviewDecision::ApprovedForSession,
351        }
352    }
353
354    /// Deny the patch (`{"decision":{"denied":{"rejection":...}}}`).
355    pub fn denied(rejection: impl Into<String>) -> Self {
356        Self {
357            decision: ReviewDecision::Denied {
358                rejection: rejection.into(),
359            },
360        }
361    }
362
363    /// Abort the turn in response to the request.
364    pub fn abort() -> Self {
365        Self {
366            decision: ReviewDecision::Abort,
367        }
368    }
369}
370
371#[cfg(test)]
372mod tests {
373    use super::*;
374
375    #[test]
376    fn thread_start_params_default_is_empty_object() {
377        let p = ThreadStartParams::default();
378        assert_eq!(serde_json::to_value(&p).unwrap(), serde_json::json!({}));
379    }
380
381    #[test]
382    fn turn_start_params_default_round_trips() {
383        let p = TurnStartParams::default();
384        let v = serde_json::to_value(&p).unwrap();
385        // thread_id + input are required-but-defaulted; everything else omits.
386        assert_eq!(v["threadId"], "");
387        assert_eq!(v["input"], serde_json::json!([]));
388    }
389
390    #[test]
391    fn thread_resume_and_fork_params_default() {
392        let _ = ThreadResumeParams::default();
393        let _ = ThreadForkParams::default();
394    }
395
396    #[test]
397    fn file_change_approval_response_wire_shape() {
398        assert_eq!(
399            serde_json::to_value(FileChangeRequestApprovalResponse::accept()).unwrap(),
400            serde_json::json!({"decision": "accept"})
401        );
402        assert_eq!(
403            serde_json::to_value(FileChangeRequestApprovalResponse::decline()).unwrap(),
404            serde_json::json!({"decision": "decline"})
405        );
406    }
407
408    #[test]
409    fn command_execution_approval_response_wire_shape() {
410        assert_eq!(
411            serde_json::to_value(CommandExecutionRequestApprovalResponse::accept()).unwrap(),
412            serde_json::json!({"decision": "accept"})
413        );
414        assert_eq!(
415            serde_json::to_value(CommandExecutionRequestApprovalResponse::cancel()).unwrap(),
416            serde_json::json!({"decision": "cancel"})
417        );
418    }
419
420    #[test]
421    fn exec_and_apply_patch_approval_response_wire_shape() {
422        assert_eq!(
423            serde_json::to_value(ExecCommandApprovalResponse::approved()).unwrap(),
424            serde_json::json!({"decision": "approved"})
425        );
426        assert_eq!(
427            serde_json::to_value(ApplyPatchApprovalResponse::denied("keep the original file"))
428                .unwrap(),
429            serde_json::json!({"decision": {"denied": {"rejection": "keep the original file"}}})
430        );
431    }
432}