Codex App Server
Codex app-server 是 Codex 用于支持丰富客户端的接口(例如 Codex VS Code extension)。当你希望在自己的产品中实现深度集成时,可以使用它:包括身份验证、对话历史记录、审批和流式代理事件。app-server 的实现已在 Codex GitHub 仓库中开源(openai/codex/codex-rs/app-server)。完整的开源 Codex 组件列表,请参阅开源页面。
如果你要自动化作业或在 CI 中运行 Codex,请改用 Codex SDK。
连接 CLI 终端界面
Section titled “连接 CLI 终端界面”远程终端界面模式允许你在一台机器上运行 app-server,并从另一台机器连接 Codex CLI 终端界面。启动 WebSocket 监听器:
codex app-server --listen ws://127.0.0.1:4500然后连接终端界面:
codex --remote ws://127.0.0.1:4500对于非本地连接,请配置 WebSocket 身份验证,并将连接置于 TLS 后。将 bearer token 存储在环境变量中,并传递变量名,而不要将 token 放在命令行中:
export CODEX_REMOTE_TOKEN="$(cat "$HOME/.codex/app-server-token")"codex --remote wss://remote-host:4500 \ --remote-auth-token-env CODEX_REMOTE_TOKEN--remote 选项接受 ws://、wss://、unix:// 和
unix://PATH 端点。仅在 localhost 或通过 SSH 端口转发的连接中使用普通 WebSocket。
与 MCP 一样,codex app-server 使用 JSON-RPC 2.0 消息支持双向通信(在网络传输时省略 "jsonrpc":"2.0" 标头)。
支持的传输方式:
stdio(--listen stdio://,默认):以换行分隔的 JSON(JSONL)。websocket(--listen ws://IP:PORT,实验性且不受支持):每个 WebSocket 文本帧包含一条 JSON-RPC 消息。- Unix 套接字(
--listen unix://或--listen unix://PATH):通过 Codex 的默认 app-server 控制套接字或自定义 Unix 套接字路径建立 WebSocket 连接,并使用标准 HTTP Upgrade 握手。 off(--listen off):不公开本地传输方式。
当你使用 --listen ws://IP:PORT 运行时,同一个监听器还会提供基本的
HTTP 健康探测:
GET /readyz会在监听器接受新连接后返回200 OK。- 当请求不包含
Origin标头时,GET /healthz返回200 OK。 - 包含
Origin标头的请求会被拒绝,并返回403 Forbidden。
WebSocket 传输方式处于实验阶段且不受支持。本地监听器(例如
ws://127.0.0.1:PORT)适用于 localhost 和 SSH 端口转发工作流。非回环 WebSocket 监听器在当前部署阶段默认允许未经身份验证的连接,因此在远程公开监听器之前,请先配置 WebSocket 身份验证。
支持的 WebSocket 身份验证标志:
--ws-auth capability-token --ws-token-file /absolute/path--ws-auth capability-token --ws-token-sha256 HEX--ws-auth signed-bearer-token --ws-shared-secret-file /absolute/path
对于签名 bearer token,你还可以设置 --ws-issuer、--ws-audience 和
--ws-max-clock-skew-seconds。客户端在 WebSocket 握手期间以
Authorization: Bearer <token> 的形式提供凭据,app-server 会在 JSON-RPC initialize 之前强制执行身份验证。
优先使用 --ws-token-file,而不是在命令行中传递原始 bearer token。仅当客户端将原始高熵 token 保存在单独的本地密钥存储中时,才使用
--ws-token-sha256;哈希值仅用于验证,客户端仍然需要原始 token。
在 WebSocket 模式下,app-server 使用有界队列。当请求入口已满时,服务器会使用 JSON-RPC 错误代码 -32001 拒绝新请求,并返回消息
"Server overloaded; retry later." 客户端应使用指数递增的延迟和抖动进行重试。
请求包含 method、params 和 id:
{ "method": "thread/start", "id": 10, "params": { "model": "gpt-5.4" } }响应会回显 id,并包含 result 或 error:
{ "id": 10, "result": { "thread": { "id": "thr_123" } } }{ "id": 10, "error": { "code": 123, "message": "Something went wrong" } }通知省略 id,仅使用 method 和 params:
{ "method": "turn/started", "params": { "turn": { "id": "turn_456" } } }你可以通过 CLI 生成 TypeScript 架构或 JSON Schema 包。每个输出都对应你运行的 Codex 版本,因此生成的构件与该版本完全匹配:
codex app-server generate-ts --out ./schemascodex app-server generate-json-schema --out ./schemas- 使用
codex app-server(默认 stdio 传输方式)、codex app-server --listen ws://127.0.0.1:4500(TCP WebSocket)或codex app-server --listen unix://(默认 Unix 套接字)启动服务器。 - 通过选定的传输方式连接客户端,然后发送
initialize,再发送initialized通知。 - 启动一个线程和一个回合,然后持续从活动传输流中读取通知。
示例(Node.js / TypeScript):
const proc = spawn("codex", ["app-server"], { stdio: ["pipe", "pipe", "inherit"],});const rl = readline.createInterface({ input: proc.stdout });
const send = (message: unknown) => { proc.stdin.write(`${JSON.stringify(message)}\n`);};
let threadId: string | null = null;
rl.on("line", (line) => { const msg = JSON.parse(line) as any; console.log("server:", msg);
if (msg.id === 1 && msg.result?.thread?.id && !threadId) { threadId = msg.result.thread.id; send({ method: "turn/start", id: 2, params: { threadId, input: [{ type: "text", text: "Summarize this repo." }], }, }); }});
send({ method: "initialize", id: 0, params: { clientInfo: { name: "my_product", title: "My Product", version: "0.1.0", }, },});send({ method: "initialized", params: {} });send({ method: "thread/start", id: 1, params: { model: "gpt-5.4" } });- Thread:用户与 Codex 代理之间的对话。线程包含多个回合。
- Turn:一次用户请求及代理随后执行的工作。回合包含多个项目,并以流式方式传递增量更新。
- Item:输入或输出的单元(用户消息、代理消息、命令运行、文件更改、工具调用等)。
使用线程 API 创建、列出或归档对话。通过回合 API 驱动对话,并通过回合通知以流式方式传递进度。
生命周期概览
Section titled “生命周期概览”- 每个连接初始化一次:打开传输连接后,立即发送包含客户端元数据的
initialize请求,然后发出initialized。在完成此握手前,服务器会拒绝该连接上的任何请求。 - 启动(或恢复)线程:调用
thread/start创建新对话,调用thread/resume继续已有对话,或调用thread/fork将历史记录分支到新的线程 ID。 - 开始一个回合:使用目标
threadId和用户输入调用turn/start。可选字段可以覆盖模型、个性、cwd、沙箱策略等设置。 - 引导活动回合:调用
turn/steer,将用户输入追加到当前正在进行的回合中,而不创建新的回合。 - 流式传输事件:在
turn/start之后,持续从 stdout 读取通知:thread/archived、thread/unarchived、item/started、item/completed、item/agentMessage/delta、工具进度以及其他更新。 - 完成回合:模型完成运行或在
turn/interrupt取消后,服务器会发出包含最终状态的turn/completed。
客户端必须在每个传输连接上调用任何其他方法之前,先发送一次 initialize 请求,然后使用 initialized 通知进行确认。在初始化之前发送的请求会收到 Not initialized 错误;在同一连接上重复调用 initialize 会返回 Already initialized。
服务器会返回它将向上游服务提供的用户代理字符串,以及描述运行时目标的 platformFamily 和 platformOs 值。设置 clientInfo 以标识你的集成。
initialize.params.capabilities 还支持以下客户端能力:
optOutNotificationMethods- 要为此连接抑制的确切通知方法名称。匹配必须完全一致(不支持通配符或前缀);未知名称会被接受并忽略。requestAttestation- 选择加入由服务器发起的attestation/generate请求。提供上游证明的桌面主机会返回不透明的{ "token": "..." }值。mcpServerOpenaiFormElicitation- 允许下游 MCP 服务器发送mcpServer/elicitation/request的 OpenAI 扩展表单变体。
重要:使用 clientInfo.name 在 OpenAI Compliance Logs Platform 中标识你的客户端。如果你正在开发面向企业使用的新 Codex 集成,请联系 OpenAI,将其添加到已知客户端列表中。有关更多背景信息,请参阅 Codex 日志参考。
示例(来自 Codex VS Code extension):
{ "method": "initialize", "id": 0, "params": { "clientInfo": { "name": "codex_vscode", "title": "Codex VS Code Extension", "version": "0.1.0" } }}带有通知退出选项的示例:
{ "method": "initialize", "id": 1, "params": { "clientInfo": { "name": "my_client", "title": "My Client", "version": "0.1.0" }, "capabilities": { "experimentalApi": true, "optOutNotificationMethods": ["thread/started", "item/agentMessage/delta"] } }}实验性 API 选择加入
Section titled “实验性 API 选择加入”某些 app-server 方法和字段特意通过 experimentalApi 能力进行限制。
- 省略
capabilities(或将experimentalApi设置为false)即可继续使用稳定 API 表面;服务器会拒绝实验性方法和字段。 - 将
capabilities.experimentalApi设置为true,即可启用实验性方法和字段。
{ "method": "initialize", "id": 1, "params": { "clientInfo": { "name": "my_client", "title": "My Client", "version": "0.1.0" }, "capabilities": { "experimentalApi": true } }}如果客户端在未选择加入的情况下发送实验性方法或字段,app-server 会返回:
<descriptor> requires experimentalApi capability
API 概览
Section titled “API 概览”thread/start- 创建新线程;发出thread/started,并自动订阅该线程的回合/项目事件。thread/resume- 按 ID 重新打开现有线程,使后续的turn/start调用追加到该线程。thread/fork- 通过复制已存储的历史记录,将线程分叉为新的线程 ID。传入lastTurnId可复制截至该回合的历史记录,并省略后续回合。为新线程发出thread/started;返回的线程在可用时包含forkedFromId。thread/read- 按 ID 读取已存储的线程,但不恢复该线程;将includeTurns设置为返回完整的回合历史记录。返回的thread对象包含运行时status。thread/list- 分页浏览已存储的线程日志;支持基于游标的分页,以及modelProviders、sourceKinds、archived、cwd、useStateDbOnly、searchTerm和实验性的parentThreadId或ancestorThreadId过滤器。返回的thread对象包含运行时status。thread/turns/list- 实验性功能;分页浏览已存储线程的回合历史记录,但不恢复该线程。itemsView控制是否省略回合项目、返回摘要或完整加载。thread/items/list- 实验性功能;分页浏览持久化的线程项目,可选择限制为单个turnId。活动线程存储必须支持项目分页。thread/loaded/list- 列出当前加载到内存中的线程 ID。thread/name/set- 为已加载的线程或持久化的 rollout 设置或更新面向用户显示的名称;发出thread/name/updated。thread/goal/set- 设置线程目标;发出thread/goal/updated。thread/goal/get- 读取线程的当前目标。thread/goal/clear- 清除线程目标;发出thread/goal/cleared。thread/metadata/update- 更新由 SQLite 支持的已存储线程元数据;当前支持持久化的gitInfo。thread/archive- 将线程日志文件移入归档目录,并尝试归档尚未归档的已生成后代线程日志;成功时返回{},并为每个已归档线程发出thread/archived。thread/delete- 永久删除持久化的活动线程或已归档线程,以及其所有已生成的后代线程;成功时返回{},并为每个已删除线程发出thread/deleted。thread/unsubscribe- 取消此连接对线程回合/项目事件的订阅。如果这是最后一个订阅者,服务器会在线程无订阅者闲置宽限期结束后卸载该线程,并发出thread/closed。thread/unarchive- 将已归档的线程 rollout 恢复到活动会话目录;返回恢复后的thread,并发出thread/unarchived。thread/status/changed- 在已加载线程的运行时status发生变化时发出的通知。thread/compact/start- 触发线程的对话历史压缩;立即返回{},进度则通过turn/*和item/*通知流式传输。thread/shellCommand- 针对线程运行用户发起的 shell 命令。该命令在沙箱之外运行,具有完整访问权限,并且不会继承线程的沙箱策略。thread/backgroundTerminals/clean- 停止线程的所有正在运行的后台终端(实验性功能;需要capabilities.experimentalApi)。thread/backgroundTerminals/list- 列出已加载线程正在运行的后台终端(实验性功能;需要capabilities.experimentalApi)。thread/backgroundTerminals/terminate- 根据 app-serverprocessId终止一个正在运行的后台终端(实验性功能;需要capabilities.experimentalApi)。thread/rollback- 已弃用;从内存中的上下文中删除最后 N 个回合,并持久化回滚标记;返回更新后的thread。turn/start- 向线程添加用户输入并开始 Codex 生成;返回初始turn并流式传输事件。对于collaborationMode,settings.developer_instructions: null表示“使用所选模式的内置指令”。thread/inject_items- 将原始 Responses API 项目追加到已加载线程的模型可见历史记录中,但不启动用户回合。turn/steer- 将用户输入追加到线程当前正在进行的回合;返回已接受的turnId。turn/interrupt- 请求取消正在进行的回合;成功时返回{},且该回合以status: "interrupted"结束。review/start- 为线程启动 Codex 审查器;发出enteredReviewMode和exitedReviewMode项目。command/exec- 在服务器沙箱下运行单个命令,但不启动线程或回合。command/exec/write- 将stdin字节写入正在运行的command/exec会话,或关闭stdin。command/exec/resize- 调整由 PTY 支持的正在运行的command/exec会话的大小。command/exec/terminate- 停止正在运行的command/exec会话。command/exec/outputDelta(notify) - 为流式command/exec会话发出的、经过 base64 编码的 stdout/stderr 数据块。process/spawn- 在 Codex 沙箱之外启动显式进程会话(实验性功能;需要capabilities.experimentalApi)。process/writeStdin- 将 stdin 字节写入正在运行的process/spawn会话,或关闭 stdin(实验性功能)。process/resizePty- 调整由 PTY 支持的正在运行的进程会话的大小(实验性功能)。process/kill- 终止正在运行的进程会话(实验性功能)。process/outputDelta和process/exited(notify) - 为流式进程输出和进程退出状态发出(实验性功能)。model/list- 列出可用模型(设置includeHidden: true可包含hidden: true的条目),并返回推理选项、可选的upgrade和inputModalities。modelProvider/capabilities/read- 读取模型/提供商组合的提供商能力边界。experimentalFeature/list- 列出带有生命周期阶段元数据和游标分页的功能标志。experimentalFeature/enablement/set- 为受支持的功能键(如apps和plugins)更新内存中的运行时设置。environment/info- 实验性功能;连接到已配置的执行环境,并返回其 shell 及默认工作目录。permissionProfile/list- 列出 beta 权限配置文件,以及有效要求是否允许使用这些配置文件,并支持游标分页。collaborationMode/list- 列出协作模式预设(实验性功能,不分页)。skills/list- 列出一个或多个cwd值对应的技能(支持forceReload和可选的perCwdExtraUserRoots)。skills/extraRoots/set- 替换用于发现独立技能的进程级额外根目录,但不持久化这些目录。skills/changed(notify) - 在受监视的本地技能文件发生变化时发出。hooks/list- 列出一个或多个cwd值对应的已发现生命周期钩子。marketplace/add- 添加远程插件市场,并将其持久化到用户的市场配置中。marketplace/remove- 移除已配置的市场,并在存在时移除其已安装的市场根目录。marketplace/upgrade- 刷新已配置的 Git 市场;省略市场名称时,刷新所有已配置的 Git 市场。plugin/list- 开发中;列出已发现的插件市场和插件状态,包括安装/身份验证策略元数据、市场加载错误、精选插件 ID,以及本地、Git、包注册表或远程插件源元数据。摘要可以包含远程version、本地localVersion、结构化的浅色/深色图标,以及installPolicySource;对于当前的远程行,该字段可以是null、WORKSPACE_SETTING或IMPLICIT_CANONICAL_APP。生产客户端暂时不要调用此方法。plugin/read- 开发中;根据市场路径,或远程市场名称和插件名称读取单个插件,包括捆绑的技能、应用、MCP 服务器名称,以及在远程目录提供时返回远程插件的shareUrl。生产客户端暂时不要调用此方法。plugin/install- 开发中;从市场路径或远程市场名称安装插件。生产客户端暂时不要调用此方法。plugin/uninstall- 开发中;卸载已安装的插件。生产客户端暂时不要调用此方法。plugin/skill/read- 根据远程市场、插件 ID 和技能名称,按需读取远程插件技能 Markdown。app/list- 分页列出可用应用(连接器),以及可访问性/启用状态元数据。skills/config/write- 按路径启用或禁用技能。mcpServer/oauth/login- 为已配置的 MCP 服务器启动 OAuth 登录;返回授权 URL,并在完成时发出mcpServer/oauthLogin/completed。tool/requestUserInput- 针对工具调用向用户提出 1-3 个简短问题(实验性功能);问题可以将isOther设置为自由输入选项。mcpServer/elicitation/request(server request) - 请求客户端提供结构化表单输入,或确认 MCP 服务器请求的 URL 流程。item/permissions/requestApproval(server request) - 请求客户端授予内置request_permissions工具所请求的部分网络或文件系统权限。config/mcpServer/reload- 从磁盘重新加载 MCP 服务器配置,并为已加载的线程排队刷新操作。mcpServerStatus/list- 列出 MCP 服务器、工具、资源和身份验证状态(支持游标和限制分页)。使用detail: "full"获取完整数据,或使用detail: "toolsAndAuthOnly"省略资源。mcpServer/resource/read- 通过已初始化的 MCP 服务器读取单个 MCP 资源。mcpServer/tool/call- 调用线程已配置 MCP 服务器上的工具。mcpServer/startupStatus/updated(notify) - 在已加载线程的已配置 MCP 服务器启动状态发生变化时发出。windowsSandbox/setupStart- 开始为elevated或unelevated模式设置 Windows 沙箱;快速返回,随后发出windowsSandbox/setupCompleted。feedback/upload- 提交反馈报告(分类 + 可选原因/日志 + 对话 ID,以及可选的extraLogFiles附件)。config/read- 在解析配置分层后,从磁盘获取生效的配置。externalAgentConfig/detect- 检测可迁移的外部代理构件,可使用includeHome和可选的cwds;每个检测到的项目都包含cwd(对于主目录为null)。externalAgentConfig/import- 通过传入带有cwd(对于主目录为null)的显式migrationItems,应用选定的外部代理迁移项目。支持的项目类型包括配置、技能、AGENTS.md、插件、MCP 服务器配置、子代理、钩子、命令和会话;非空导入会在工作完成时发出externalAgentConfig/import/progress和externalAgentConfig/import/completed。插件和会话导入可以异步完成。config/value/write- 将单个配置键/值写入用户磁盘上的config.toml。config/batchWrite- 将配置编辑原子性地应用到用户磁盘上的config.toml。configRequirements/read- 从requirements.toml和/或 MDM 获取要求,包括允许列表、固定的featureRequirements以及驻留/网络要求(如果尚未设置,则为null)。fs/readFile、fs/writeFile、fs/createDirectory、fs/getMetadata、fs/readDirectory、fs/remove、fs/copy、fs/watch、fs/unwatch和fs/changed(notify) - 通过 app-server v2 文件系统 API 对绝对文件系统路径执行操作。
插件摘要包含一个 source 联合类型。本地插件返回
{ "type": "local", "path": ... },由 Git 支持的市场条目返回
{ "type": "git", "url": ..., "path": ..., "refName": ..., "sha": ... },
包注册表条目返回
{ "type": "npm", "package": ..., "version": ..., "registry": ... },远程目录条目返回 { "type": "remote" }。对于仅远程目录条目,PluginMarketplaceEntry.path 可以为 null;读取或安装这些插件时,请传递 remoteMarketplaceName,而不是 marketplacePath。
列出模型(model/list)
Section titled “列出模型(model/list)”在渲染模型或个性选择器之前,调用 model/list 来发现可用模型及其能力。
{ "method": "model/list", "id": 6, "params": { "limit": 20, "includeHidden": false } }{ "id": 6, "result": { "data": [{ "id": "gpt-5.4", "model": "gpt-5.4", "displayName": "GPT-5.4", "hidden": false, "defaultReasoningEffort": "medium", "supportedReasoningEfforts": [{ "reasoningEffort": "low", "description": "Lower latency" }], "inputModalities": ["text", "image"], "supportsPersonality": true, "isDefault": true }], "nextCursor": null} }每个模型条目可以包含:
supportedReasoningEfforts- 模型支持的推理力度选项。defaultReasoningEffort- 为客户端建议的默认推理力度。upgrade- 可选的推荐升级模型 ID,用于客户端中的迁移提示。upgradeInfo- 可选的升级元数据,用于客户端中的迁移提示。hidden- 模型是否从默认选择器列表中隐藏。inputModalities- 模型支持的输入类型(例如text、image)。supportsPersonality- 模型是否支持个性专属指令,例如/personality。isDefault- 模型是否为推荐的默认模型。
默认情况下,model/list 仅返回在选择器中可见的模型。如果需要完整列表并希望在客户端使用 hidden 进行筛选,请设置 includeHidden: true。
当缺少 inputModalities 时(较旧的模型目录可能如此),为保持向后兼容,请将其视为 ["text", "image"]。
列出实验性功能(experimentalFeature/list)
Section titled “列出实验性功能(experimentalFeature/list)”使用此端点可以发现包含元数据和生命周期阶段的功能标志:
{ "method": "experimentalFeature/list", "id": 7, "params": { "limit": 20 } }{ "id": 7, "result": { "data": [{ "name": "unified_exec", "stage": "beta", "displayName": "Unified exec", "description": "Use the unified PTY-backed execution tool.", "announcement": "Beta rollout for improved command execution reliability.", "enabled": false, "defaultEnabled": false }], "nextCursor": null} }stage 可以是 beta、underDevelopment、stable、deprecated 或 removed。对于非 beta 标志,displayName、description 和 announcement 可能为 null。
检查执行环境(实验性)
Section titled “检查执行环境(实验性)”使用 environment/info 可以在开始工作前检查已配置的远程环境。此方法要求 capabilities.experimentalApi = true。
{ "method": "environment/info", "id": 8, "params": { "environmentId": "devbox" } }{ "id": 8, "result": { "shell": { "name": "zsh", "path": "/bin/zsh" }, "cwd": "file:///workspace/project"} }cwd 可以为 null。如果存在,它是使用环境原生路径语法的规范 file: URI。未知环境 ID,以及连接或协议失败,都会返回请求错误。
thread/read读取已存储的线程,但不会订阅该线程;设置includeTurns可包含各轮对话。thread/turns/list为实验性方法,用于分页读取已存储线程的历史轮次,但不会恢复该线程。使用itemsView选择是否省略、摘要化或完整加载轮次项目。thread/items/list为实验性方法,用于分页读取持久化的线程项目,也可以限制为某一轮。thread/list支持游标分页,以及modelProviders、sourceKinds、archived、cwd、useStateDbOnly、searchTerm和实验性的parentThreadId或ancestorThreadId筛选。thread/loaded/list返回当前加载到内存中的线程 ID。thread/archive将线程的持久化 JSONL 日志移动到归档目录,并尝试归档尚未归档的已生成后代线程日志。thread/delete永久删除持久化的活动线程或已归档线程,以及其已生成的后代线程。thread/metadata/update更新已存储的线程元数据,目前包括持久化的gitInfo。thread/unsubscribe取消当前连接对已加载线程的订阅,并可能在非活动宽限期结束后触发thread/closed。thread/unarchive将已归档的线程运行记录恢复到活动会话目录。thread/compact/start触发压缩并立即返回{}。thread/rollback已弃用。它会从内存上下文中删除最后 N 轮对话,并在持久化线程 JSONL 日志中记录回滚标记。thread/inject_items将原始 Responses API 项目追加到已加载线程的模型可见历史记录中,但不会开始用户轮次。
启动或恢复线程
Section titled “启动或恢复线程”需要开始新的 Codex 对话时,请启动一个全新的线程。
{ "method": "thread/start", "id": 10, "params": { "model": "gpt-5.4", "cwd": "/Users/me/project", "approvalPolicy": "never", "sandbox": "workspaceWrite", "personality": "friendly", "serviceName": "my_app_server_client"} }{ "id": 10, "result": { "thread": { "id": "thr_123", "sessionId": "thr_123", "preview": "", "ephemeral": false, "modelProvider": "openai", "createdAt": 1730910000 }} }{ "method": "thread/started", "params": { "thread": { "id": "thr_123" } } }serviceName 是可选的。当你希望 app-server 使用集成的服务名称标记线程级指标时,请设置此字段。
thread/start、thread/resume 和 thread/fork 会返回
instructionSources,这是一个已加载指令文件路径的数组。每个路径都使用其源环境的原生绝对路径语法,远程环境也不例外。
实验性客户端可以在 thread/start 上将 historyMode 设置为 "legacy"(默认值)或 "paginated"。分页式线程创建目前尚不支持,并会返回 JSON-RPC 错误 -32601。App-server 可以列出并读取现有分页记录的摘要,但在支持分页历史记录之前,读取完整历史、分页读取轮次和恢复操作都会安全失败。
选择加入 capabilities.experimentalApi 的 Beta 客户端可以在 permissions 中传递命名的权限配置文件 ID,以代替旧版的 sandbox 字段。不要同时发送 permissions 和 sandbox。使用带项目 cwd 的 permissionProfile/list 来发现可用配置文件,以及托管要求是否允许使用每个配置文件。
thread.sessionId 标识当前活动会话树的根。根线程使用自身的线程 ID 作为会话 ID;分叉线程保留其来源根线程的会话 ID。客户端应从 thread.sessionId 读取会话 ID,而不是根据线程 ID 推导。
要继续已存储的会话,请使用之前记录的 thread.id 调用 thread/resume。响应结构与 thread/start 相同。你还可以传递 thread/start 支持的相同配置覆盖项,例如 personality:
{ "method": "thread/resume", "id": 11, "params": { "threadId": "thr_123", "personality": "friendly"} }{ "id": 11, "result": { "thread": { "id": "thr_123", "name": "Bug bash notes", "ephemeral": false } } }恢复线程本身不会更新 thread.updatedAt(也不会更新运行记录文件的修改时间)。开始一轮对话后,时间戳才会更新。
如果你在配置中将已启用的 MCP 服务器标记为 required,而该服务器初始化失败,则 thread/start 和 thread/resume 会失败,而不是在没有该服务器的情况下继续。
thread/start 上的 dynamicTools 是一个实验性字段(要求 capabilities.experimentalApi = true)。Codex 会将这些动态工具持久化到线程运行记录元数据中;当你未提供新的动态工具时,thread/resume 会恢复这些工具。
如果恢复线程时使用的模型不同于运行记录中记录的模型,Codex 会发出警告,并在下一轮对话中应用一次性模型切换指令。
管理线程目标
Section titled “管理线程目标”使用 thread/goal/set、thread/goal/get 和 thread/goal/clear 管理由 TUI 中的 /goal 展示的同一持久化目标状态。
{ "method": "thread/goal/set", "id": 13, "params": { "threadId": "thr_123", "objective": "Finish the migration and keep tests green", "status": "active", "tokenBudget": 40000} }{ "id": 13, "result": { "goal": { "threadId": "thr_123", "objective": "Finish the migration and keep tests green", "status": "active", "tokenBudget": 40000, "tokensUsed": 0, "timeUsedSeconds": 0} } }{ "method": "thread/goal/updated", "params": { "threadId": "thr_123", "goal": { "threadId": "thr_123", "objective": "Finish the migration and keep tests green", "status": "active", "tokenBudget": 40000, "tokensUsed": 0, "timeUsedSeconds": 0 }} }目标内容不得为空,且最多为 4,000 个字符。提供新目标会替换现有目标并重置使用量统计。提供当前的非终止目标,或省略 objective,会在保留使用历史的同时更新状态或令牌预算。
要从已存储的会话创建分支,请使用 thread.id 调用 thread/fork。这会创建新的线程 ID,并为其发出 thread/started 通知。传递 lastTurnId 可复制截至该轮(包括该轮)的历史记录,并省略之后的轮次:
{ "method": "thread/fork", "id": 12, "params": { "threadId": "thr_123", "lastTurnId": "turn_456" } }{ "id": 12, "result": { "thread": { "id": "thr_456", "sessionId": "thr_123", "forkedFromId": "thr_123" } } }{ "method": "thread/started", "params": { "thread": { "id": "thr_456" } } }App-server 会拒绝进行中的 lastTurnId。如果源线程正处于一轮对话中时省略此字段,分叉会记录中断标记,而不会保留未标记的部分轮次。
设置面向用户的线程标题后,app-server 会在 thread/list、thread/read、thread/resume、thread/unarchive 和 thread/rollback 的响应中填充 thread.name。在稍后设置标题之前,thread/start 和 thread/fork 可能省略 name(或返回 null)。
读取已存储的线程(不恢复)
Section titled “读取已存储的线程(不恢复)”当你需要已存储的线程数据,但不希望恢复线程或订阅其事件时,请使用 thread/read。
includeTurns- 为true时,响应包含线程的轮次;为false或省略时,仅返回线程摘要。- 返回的
thread对象包含运行时status(notLoaded、idle、systemError,或带有activeFlags的active)。
{ "method": "thread/read", "id": 19, "params": { "threadId": "thr_123", "includeTurns": true } }{ "id": 19, "result": { "thread": { "id": "thr_123", "name": "Bug bash notes", "ephemeral": false, "status": { "type": "notLoaded" }, "turns": [] } } }与 thread/resume 不同,thread/read 不会将线程加载到内存中,也不会发出 thread/started。
列出线程轮次
Section titled “列出线程轮次”thread/turns/list 为实验性方法。使用它可以分页读取已存储线程的历史轮次,而无需恢复线程。结果默认按最新优先排序,因此客户端可以使用 nextCursor 获取较早的轮次。响应还包含 backwardsCursor;将其作为 cursor 并配合 sortDirection: "asc",即可获取早于上一页第一项的轮次之后更新的轮次。
itemsView 控制响应包含多少轮次项目数据:
notLoaded不包含项目。summary返回项目数据摘要;省略时默认为此值。full返回完整的项目数据。
{ "method": "thread/turns/list", "id": 20, "params": { "threadId": "thr_123", "limit": 50, "sortDirection": "desc", "itemsView": "summary"} }{ "id": 20, "result": { "data": [], "nextCursor": "older-turns-cursor-or-null", "backwardsCursor": "newer-turns-cursor-or-null"} }thread/items/list 同样是实验性方法。它可以分页读取持久化项目,而无需恢复线程。传递 turnId 可将结果限制为某一轮;省略该参数则可分页读取整个线程中的项目。活动线程存储必须支持项目分页;否则,服务器会返回不支持该方法的错误。
列出线程(支持分页和筛选)
Section titled “列出线程(支持分页和筛选)”thread/list 可用于渲染历史记录界面。结果默认按 createdAt 从新到旧排列。筛选会在分页前应用。可传入以下参数的任意组合:
cursor- 上一次响应中的不透明字符串;第一页省略。limit- 未设置时,服务器会使用合理的默认页面大小。sortKey-created_at(默认)、updated_at或recency_at。sortDirection-desc(默认)或asc。modelProviders- 将结果限制为指定的提供商;未设置、为 null 或为空数组时,包含所有提供商。sourceKinds- 将结果限制为指定的线程来源。省略或传入[]时,服务器默认仅返回交互式来源:cli和vscode。archived- 为true时,仅列出已归档的线程。为false或省略时,列出未归档的线程(默认)。cwd- 将结果限制为会话当前工作目录与此路径完全匹配的线程,或与数组中的某个路径匹配的线程。相对路径根据 app-server 进程的工作目录解析。useStateDbOnly- 为true时,返回状态数据库中的结果,不扫描 JSONL 线程日志来修复元数据。省略此参数或传入false时,使用默认的扫描并修复行为。searchTerm- 将结果限制为提取出的标题包含此区分大小写文本片段的线程。parentThreadId- 将结果限制为给定父线程的直接子线程。此筛选器为实验性功能,需要设置capabilities.experimentalApi = true。ancestorThreadId- 将结果限制为给定线程在任意深度上生成的后代线程。此筛选器为实验性功能,需要设置capabilities.experimentalApi = true;不要与parentThreadId组合使用。
sourceKinds 接受以下值:
clivscodeexecappServersubAgentsubAgentReviewsubAgentCompactsubAgentThreadSpawnsubAgentOtherunknown
示例:
{ "method": "thread/list", "id": 20, "params": { "cursor": null, "limit": 25, "sortKey": "created_at"} }{ "id": 20, "result": { "data": [ { "id": "thr_a", "preview": "Create a TUI", "ephemeral": false, "modelProvider": "openai", "createdAt": 1730831111, "updatedAt": 1730831111, "name": "TUI prototype", "status": { "type": "notLoaded" } }, { "id": "thr_b", "preview": "Fix tests", "ephemeral": true, "modelProvider": "openai", "createdAt": 1730750000, "updatedAt": 1730750000, "status": { "type": "notLoaded" } } ], "nextCursor": "opaque-token-or-null"} }当 nextCursor 为 null 时,表示已到达最后一页。
更新已存储的线程元数据
Section titled “更新已存储的线程元数据”使用 thread/metadata/update 可在不恢复线程的情况下更新已存储的线程元数据。目前支持持久化的 gitInfo;省略的字段保持不变,显式设置为 null 会清除已存储的值。
{ "method": "thread/metadata/update", "id": 21, "params": { "threadId": "thr_123", "gitInfo": { "branch": "feature/sidebar-pr" }} }{ "id": 21, "result": { "thread": { "id": "thr_123", "gitInfo": { "sha": null, "branch": "feature/sidebar-pr", "originUrl": null } }} }跟踪线程状态变化
Section titled “跟踪线程状态变化”每当已加载线程的运行时状态发生变化时,都会发出 thread/status/changed。负载包含 threadId 和新的 status。
{ "method": "thread/status/changed", "params": { "threadId": "thr_123", "status": { "type": "active", "activeFlags": ["waitingOnApproval"] } }}列出已加载的线程
Section titled “列出已加载的线程”thread/loaded/list 返回当前加载到内存中的线程 ID。
{ "method": "thread/loaded/list", "id": 21 }{ "id": 21, "result": { "data": ["thr_123", "thr_456"] } }取消订阅已加载的线程
Section titled “取消订阅已加载的线程”使用 thread/unsubscribe 可移除当前连接对某个线程的订阅。响应状态为以下值之一:
unsubscribed:连接之前已订阅该线程,现在已移除订阅。notSubscribed:连接未订阅该线程。notLoaded:线程未加载。
如果这是最后一个订阅者,服务器会继续保持线程加载状态,直到该线程没有订阅者且 30 分钟内没有线程活动。宽限期结束后,app-server 会卸载线程,并发出状态转换为 notLoaded 的 thread/status/changed,以及 thread/closed。
{ "method": "thread/unsubscribe", "id": 22, "params": { "threadId": "thr_123" } }{ "id": 22, "result": { "status": "unsubscribed" } }如果线程之后过期:
{ "method": "thread/status/changed", "params": { "threadId": "thr_123", "status": { "type": "notLoaded" }} }{ "method": "thread/closed", "params": { "threadId": "thr_123" } }使用 thread/archive 可将持久化的线程日志(以 JSONL 文件形式存储在磁盘上)移动到已归档会话目录。归档线程时,还会尝试归档尚未归档的已生成后代线程。
{ "method": "thread/archive", "id": 22, "params": { "threadId": "thr_b" } }{ "id": 22, "result": {} }{ "method": "thread/archived", "params": { "threadId": "thr_b" } }{ "method": "thread/archived", "params": { "threadId": "thr_child" } }除非传入 archived: true,否则已归档线程不会出现在之后的 thread/list 调用中。服务器会为实际归档的每个线程发出一条 thread/archived 通知;如果某个已生成的后代线程无法归档,请求仍可成功,但不会为该后代线程发出归档通知。
使用 thread/delete 可永久删除持久化的活动线程或已归档线程,以及其已生成的后代线程。服务器会在返回成功前移除现有的 rollout 文件和关联元数据;缺失的 rollout 文件视为已删除。临时根线程无法删除。
{ "method": "thread/delete", "id": 23, "params": { "threadId": "thr_b" } }{ "id": 23, "result": {} }{ "method": "thread/deleted", "params": { "threadId": "thr_b" } }{ "method": "thread/deleted", "params": { "threadId": "thr_child" } }取消归档线程
Section titled “取消归档线程”使用 thread/unarchive 可将已归档线程的 rollout 移回活动会话目录。
{ "method": "thread/unarchive", "id": 24, "params": { "threadId": "thr_b" } }{ "id": 24, "result": { "thread": { "id": "thr_b", "name": "Bug bash notes" } } }{ "method": "thread/unarchived", "params": { "threadId": "thr_b" } }触发线程压缩
Section titled “触发线程压缩”使用 thread/compact/start 可为线程触发手动历史记录压缩。请求会立即返回 {}。
App-server 会在同一个 threadId 上通过标准的 turn/* 和 item/* 通知发出进度,其中包括 contextCompaction 项的生命周期(先是 item/started,然后是 item/completed)。
{ "method": "thread/compact/start", "id": 25, "params": { "threadId": "thr_b" } }{ "id": 25, "result": {} }运行线程 Shell 命令
Section titled “运行线程 Shell 命令”使用 thread/shellCommand 可运行属于某个线程的用户发起的 Shell 命令。请求会立即返回 {},进度则通过标准的 turn/* 和 item/* 通知流式传输。
此 API 在沙箱之外运行,具有完整访问权限,并且不会继承线程沙箱策略。客户端应仅为用户明确发起的命令开放此 API。
如果线程已有活动中的 turn,该命令会作为该 turn 上的辅助操作运行,其格式化输出会注入该 turn 的消息流。如果线程处于空闲状态,app-server 会为该 Shell 命令启动一个独立 turn。
{ "method": "thread/shellCommand", "id": 26, "params": { "threadId": "thr_b", "command": "git status --short" } }{ "id": 26, "result": {} }清理后台终端
Section titled “清理后台终端”使用 thread/backgroundTerminals/clean 可停止与某个线程关联的所有运行中后台终端。此方法为实验性功能,需要设置 capabilities.experimentalApi = true。
{ "method": "thread/backgroundTerminals/clean", "id": 27, "params": { "threadId": "thr_b" } }{ "id": 27, "result": {} }使用 thread/backgroundTerminals/list 可检查已加载线程的运行中后台终端。请求支持标准的 cursor 和 limit 分页,返回的 processId 是 app-server 的进程 ID。此方法为实验性功能,需要设置 capabilities.experimentalApi = true:
{ "method": "thread/backgroundTerminals/list", "id": 28, "params": { "threadId": "thr_b" } }{ "id": 28, "result": { "data": [ { "itemId": "item_456", "processId": "42", "command": "python3 -m http.server", "cwd": "/workspace", "osPid": null, "cpuPercent": null, "rssKb": null }], "nextCursor": null } }使用该 processId 调用 thread/backgroundTerminals/terminate 可停止一个后台终端。此方法为实验性功能,需要设置 capabilities.experimentalApi = true:
{ "method": "thread/backgroundTerminals/terminate", "id": 29, "params": { "threadId": "thr_b", "processId": "42" } }{ "id": 29, "result": { "terminated": true } }回滚最近的 turn
Section titled “回滚最近的 turn”thread/rollback 已弃用,未来将被移除。它会从内存中的上下文移除最后的 numTurns 个条目,并在 rollout 日志中持久化一个回滚标记。返回的 thread 包含回滚后填充的 turns。
{ "method": "thread/rollback", "id": 30, "params": { "threadId": "thr_b", "numTurns": 1 } }{ "id": 30, "result": { "thread": { "id": "thr_b", "name": "Bug bash notes", "ephemeral": false } } }input 字段接受项目列表:
{ "type": "text", "text": "Explain this diff" }{ "type": "image", "url": "https://.../design.png" }{ "type": "localImage", "path": "/tmp/screenshot.png" }
你可以按 turn 覆盖配置设置(模型、effort、personality、cwd、沙箱策略、摘要)。指定后,这些设置会成为同一线程后续 turn 的默认值。outputSchema 仅应用于当前 turn。对于 sandboxPolicy.type = "externalSandbox",将 networkAccess 设置为 restricted 或 enabled;对于 workspaceWrite,networkAccess 仍为布尔值。
对于 turn/start.collaborationMode,settings.developer_instructions: null 表示“使用所选模式的内置指令”,而不是清除模式指令。
沙箱读取访问权限(ReadOnlyAccess)
Section titled “沙箱读取访问权限(ReadOnlyAccess)”sandboxPolicy 支持显式的读取访问控制:
readOnly:可选的access(默认为{ "type": "fullAccess" },也可以指定受限根目录)。workspaceWrite:可选的readOnlyAccess(默认为{ "type": "fullAccess" },也可以指定受限根目录)。
受限读取访问权限的结构:
{ "type": "restricted", "includePlatformDefaults": true, "readableRoots": ["/Users/me/shared-read-only"]}在 macOS 上,includePlatformDefaults: true 会为受限读取会话追加经过整理的平台默认 Seatbelt 策略。这可以改善工具兼容性,同时不会广泛允许访问整个 /System。
示例:
{ "type": "readOnly", "access": { "type": "fullAccess" } }{ "type": "workspaceWrite", "writableRoots": ["/Users/me/project"], "readOnlyAccess": { "type": "restricted", "includePlatformDefaults": true, "readableRoots": ["/Users/me/shared-read-only"] }, "networkAccess": false}开始一个 turn
Section titled “开始一个 turn”{ "method": "turn/start", "id": 30, "params": { "threadId": "thr_123", "input": [ { "type": "text", "text": "Run tests" } ], "cwd": "/Users/me/project", "approvalPolicy": "unlessTrusted", "sandboxPolicy": { "type": "workspaceWrite", "writableRoots": ["/Users/me/project"], "networkAccess": true }, "model": "gpt-5.4", "effort": "medium", "summary": "concise", "personality": "friendly", "outputSchema": { "type": "object", "properties": { "answer": { "type": "string" } }, "required": ["answer"], "additionalProperties": false }} }{ "id": 30, "result": { "turn": { "id": "turn_456", "status": "inProgress", "items": [], "error": null } } }将项目注入线程
Section titled “将项目注入线程”使用 thread/inject_items 可将预构建的 Responses API 项目追加到已加载线程的提示历史记录中,而无需启动用户 turn。这些项目会持久化到 rollout 中,并包含在后续的模型请求中。
{ "method": "thread/inject_items", "id": 31, "params": { "threadId": "thr_123", "items": [ { "type": "message", "role": "assistant", "content": [{ "type": "output_text", "text": "Previously computed context." }] } ]} }{ "id": 31, "result": {} }引导活动中的 turn
Section titled “引导活动中的 turn”使用 turn/steer 可向正在进行的活动 turn 追加更多用户输入。
- 包含
expectedTurnId;它必须与活动 turn ID 匹配。 - 如果线程上没有活动 turn,请求将失败。
turn/steer不会发出新的turn/started通知。turn/steer不接受 turn 级别的覆盖设置(model、cwd、sandboxPolicy或outputSchema)。
{ "method": "turn/steer", "id": 32, "params": { "threadId": "thr_123", "input": [ { "type": "text", "text": "Actually focus on failing tests first." } ], "expectedTurnId": "turn_456"} }{ "id": 32, "result": { "turnId": "turn_456" } }开始一个 turn(调用技能)
Section titled “开始一个 turn(调用技能)”在文本输入中包含 $<skill-name>,并在其旁添加一个 skill 输入项目,即可显式调用技能。
{ "method": "turn/start", "id": 33, "params": { "threadId": "thr_123", "input": [ { "type": "text", "text": "$skill-creator Add a new skill for triaging flaky CI and include step-by-step usage." }, { "type": "skill", "name": "skill-creator", "path": "/Users/me/.codex/skills/skill-creator/SKILL.md" } ]} }{ "id": 33, "result": { "turn": { "id": "turn_457", "status": "inProgress", "items": [], "error": null } } }中断 turn
Section titled “中断 turn”{ "method": "turn/interrupt", "id": 31, "params": { "threadId": "thr_123", "turnId": "turn_456" } }{ "id": 31, "result": {} }成功后,该 turn 会以 status: "interrupted" 状态结束。
Review
Section titled “Review”review/start 会为线程运行 Codex reviewer,并流式传输审查项目。目标包括:
uncommittedChangesbaseBranch(与某个分支比较差异)commit(审查指定提交)custom(自由格式的指令)
使用 delivery: "inline"(默认)可在现有线程上运行审查,或使用 delivery: "detached" 创建新的审查线程。
示例请求/响应:
{ "method": "review/start", "id": 40, "params": { "threadId": "thr_123", "delivery": "inline", "target": { "type": "commit", "sha": "1234567deadbeef", "title": "Polish tui colors" }} }{ "id": 40, "result": { "turn": { "id": "turn_900", "status": "inProgress", "items": [ { "type": "userMessage", "id": "turn_900", "content": [ { "type": "text", "text": "Review commit 1234567: Polish tui colors" } ] } ], "error": null }, "reviewThreadId": "thr_123"} }对于分离式审查,使用 "delivery": "detached"。响应结构相同,但 reviewThreadId 将是新审查线程的 ID(不同于原始的 threadId)。服务器还会在流式传输审查 turn 之前,为该新线程发出 thread/started 通知。
Codex 会先流式传输通常的 turn/started 通知,随后传输包含 enteredReviewMode 项的 item/started:
{ "method": "item/started", "params": { "item": { "type": "enteredReviewMode", "id": "turn_900", "review": "current changes" } }}审核者完成后,服务器会发出 item/started 和 item/completed,其中包含带有最终审核文本的 exitedReviewMode 项:
{ "method": "item/completed", "params": { "item": { "type": "exitedReviewMode", "id": "turn_900", "review": "Looks solid overall..." } }}使用此通知在客户端中呈现审核者输出。
process/* 是实验性的显式进程控制 API。它要求设置
capabilities.experimentalApi = true,并且运行在 Codex 沙箱之外。仅当你的客户端有意在没有沙箱的情况下公开本地进程控制时,才使用它。
使用 process/spawn 启动进程并提供 processHandle,然后使用该句柄发送 stdin、调整大小和终止请求。输出通过 process/outputDelta 通知进行流式传输,完成信息通过 process/exited 进行流式传输。
{ "method": "process/spawn", "id": 48, "params": { "command": ["python3", "-m", "pytest", "-q"], "processHandle": "pytest-1", "cwd": "/Users/me/project", "tty": true} }{ "id": 48, "result": {} }{ "method": "process/outputDelta", "params": { "processHandle": "pytest-1", "stream": "stdout", "deltaBase64": "Li4u"} }{ "method": "process/exited", "params": { "processHandle": "pytest-1", "exitCode": 0} }使用 deltaBase64、closeStdin 或两者,通过 process/writeStdin 发送输入。使用 process/resizePty 处理 PTY 调整大小事件,使用 process/kill 终止正在运行的进程。
command/exec 在服务器沙箱中运行单个命令(argv 数组),且不会创建线程。
{ "method": "command/exec", "id": 50, "params": { "command": ["ls", "-la"], "cwd": "/Users/me/project", "sandboxPolicy": { "type": "workspaceWrite" }, "timeoutMs": 10000} }{ "id": 50, "result": { "exitCode": 0, "stdout": "...", "stderr": "" } }如果你已经将服务器进程置于沙箱中,并希望 Codex 跳过自身的沙箱强制执行,请使用 sandboxPolicy.type = "externalSandbox"。对于外部沙箱模式,将 networkAccess 设置为 restricted(默认值)或 enabled。对于 readOnly 和 workspaceWrite,使用上文所示的相同可选 access / readOnlyAccess 结构。
注意:
- 服务器会拒绝空的
command数组。 sandboxPolicy接受与turn/start使用的相同结构(例如dangerFullAccess、readOnly、workspaceWrite、externalSandbox)。- 省略时,
timeoutMs将回退到服务器默认值。 - 对于基于 PTY 的会话,设置
tty: true;如果计划后续使用command/exec/write、command/exec/resize或command/exec/terminate,请使用processId。 - 设置
streamStdoutStderr: true,以便在命令运行期间接收command/exec/outputDelta通知。
读取管理员要求(configRequirements/read)
Section titled “读取管理员要求(configRequirements/read)”使用 configRequirements/read 检查从 requirements.toml 和/或 MDM 加载的有效管理员要求。
{ "method": "configRequirements/read", "id": 52, "params": {} }{ "id": 52, "result": { "requirements": { "allowedApprovalPolicies": ["onRequest", "unlessTrusted"], "allowedSandboxModes": ["readOnly", "workspaceWrite"], "featureRequirements": { "personality": true, "unified_exec": false }, "network": { "enabled": true, "allowedDomains": ["api.openai.com"], "allowUnixSockets": ["/tmp/example.sock"], "dangerouslyAllowAllUnixSockets": false } }} }未配置任何要求时,result.requirements 为 null。有关支持的键和值的详细信息,请参阅 requirements.toml 文档。
Windows 沙箱设置(windowsSandbox/setupStart)
Section titled “Windows 沙箱设置(windowsSandbox/setupStart)”自定义 Windows 客户端可以异步触发沙箱设置,而无需在启动检查时阻塞。
{ "method": "windowsSandbox/setupStart", "id": 53, "params": { "mode": "elevated" } }{ "id": 53, "result": { "started": true } }App-server 在后台开始设置,之后发出完成通知:
{ "method": "windowsSandbox/setupCompleted", "params": { "mode": "elevated", "success": true, "error": null }}模式:
elevated- 运行提升权限的 Windows 沙箱设置路径。unelevated- 运行旧版设置/预检路径。
v2 文件系统 API 作用于绝对路径。当客户端需要在文件或目录发生变化后使 UI 状态失效时,请使用 fs/watch。
{ "method": "fs/watch", "id": 54, "params": { "watchId": "0195ec6b-1d6f-7c2e-8c7a-56f2c4a8b9d1", "path": "/Users/me/project/.git/HEAD"} }{ "id": 54, "result": { "path": "/Users/me/project/.git/HEAD" } }{ "method": "fs/changed", "params": { "watchId": "0195ec6b-1d6f-7c2e-8c7a-56f2c4a8b9d1", "changedPaths": ["/Users/me/project/.git/HEAD"]} }{ "method": "fs/unwatch", "id": 55, "params": { "watchId": "0195ec6b-1d6f-7c2e-8c7a-56f2c4a8b9d1"} }{ "id": 55, "result": {} }监视文件时,该文件路径会触发 fs/changed,其中包括通过替换或重命名操作传递的更新。
事件通知是服务器针对线程生命周期、回合生命周期及其中项目发起的流。启动或恢复线程后,持续读取活动传输流,以获取 thread/started、thread/archived、thread/unarchived、thread/closed、thread/status/changed、turn/*、item/* 和 serverRequest/resolved 通知。
选择退出通知
Section titled “选择退出通知”客户端可以通过在 initialize.params.capabilities.optOutNotificationMethods 中发送准确的方法名称,按连接抑制特定通知。
- 仅进行精确匹配:
item/agentMessage/delta只会抑制该方法。 - 未知的方法名称会被忽略。
- 适用于当前的
thread/*、turn/*、item/*及相关 v2 通知。 - 不适用于请求、响应或错误。
模糊文件搜索事件(实验性)
Section titled “模糊文件搜索事件(实验性)”模糊文件搜索会话 API 会针对每个查询发出通知:
fuzzyFileSearch/sessionUpdated-{ sessionId, query, files },包含当前活动查询的匹配项。fuzzyFileSearch/sessionCompleted-{ sessionId },在该查询的索引和匹配完成后发出。
configWarning-{ summary, details?, path?, range? },用于可恢复的配置或初始化问题。warning-{ threadId?, message },用于非致命的运行时警告。
Windows 沙箱设置事件
Section titled “Windows 沙箱设置事件”windowsSandbox/setupCompleted-{ mode, success, error },在windowsSandbox/setupStart请求完成后发出。
turn/started-{ turn },包含回合 ID、空的items以及status: "inProgress"。turn/completed-{ turn },其中turn.status为completed、interrupted或failed;失败时包含{ error: { message, codexErrorInfo?, additionalDetails? } }。turn/diff/updated-{ threadId, turnId, diff },包含回合中每次文件变更的最新聚合统一差异。turn/plan/updated-{ turnId, explanation?, plan },每当代理共享或更改其计划时发出;每个plan条目为{ step, status },其中status为pending、inProgress或completed。hook/started和hook/completed-{ threadId, turnId?, run },分别在生命周期钩子启动以及最终运行摘要可用时发出。model/safetyBuffering/updated-{ threadId, turnId, model, useCases, reasons, showBufferingUi, fasterModel },当响应进入临时安全缓冲时发出。model/rerouted-{ threadId, turnId, fromModel, toModel, reason },当服务将请求路由到另一个模型时发出。model/verification-{ threadId, turnId, verifications },当服务要求额外的帐户验证时发出。thread/tokenUsage/updated- 活动线程的使用量更新。
即使项目事件正在流式传输,turn/diff/updated 和 turn/plan/updated 当前也会包含空的 items 数组。请将 item/* 通知作为回合项目的事实来源。
ThreadItem 是回合响应和 item/* 通知中携带的标记联合类型。常见的项目类型包括:
userMessage-{id, content},其中content是用户输入列表(text、image或localImage)。agentMessage-{id, text, phase?},包含累积的代理回复。存在时,phase使用 Responses API 的线路值(commentary、final_answer)。plan-{id, text},在计划模式下包含提议的计划文本。将item/completed中的最终plan项视为权威状态。reasoning-{id, summary, content},其中summary包含流式传输的推理摘要,content包含原始推理块。commandExecution-{id, command, cwd, status, commandActions, aggregatedOutput?, exitCode?, durationMs?}。fileChange-{id, changes, status},描述提议的编辑;changes列表包含{path, kind, diff}。mcpToolCall-{id, server, tool, status, arguments, appContext?, pluginId?, result?, error?}。对于受信任的 MCP 应用,appContext可以包含connectorId、linkId、resourceUri、appName、templateId和稳定的连接器actionName。较早持久化的项目可能缺少较新的元数据。请使用appContext.resourceUri,而不是已弃用的顶层mcpAppResourceUri。dynamicToolCall-{id, tool, arguments, status, contentItems?, success?, durationMs?},用于客户端执行的动态工具调用。collabToolCall-{id, tool, status, senderThreadId, receiverThreadId?, newThreadId?, prompt?, agentStatus?}。webSearch-{id, query, action?},用于代理发起的网页搜索请求。imageView-{id, path},在代理调用图像查看器工具时发出。enteredReviewMode-{id, review},在审核者开始时发送。exitedReviewMode-{id, review},在审核者完成时发出。contextCompaction-{id},在 Codex 压缩对话历史时发出。
对于 webSearch.action,操作 type 可以是 search(query?、queries?)、openPage(url?)或 findInPage(url?、pattern?)。
App server 已弃用旧版 thread/compacted 通知;请改用 contextCompaction 项。
所有项目都会发出两个共享的生命周期事件:
item/started- 新的工作单元开始时发出完整的item;item.id与增量所使用的itemId匹配。item/completed- 工作完成后发送最终的item;请将其视为权威状态。
item/agentMessage/delta- 追加代理消息的流式文本。item/plan/delta- 流式传输提议的计划文本。最终的plan项可能与拼接后的增量文本并不完全相同。item/reasoning/summaryTextDelta- 流式传输可读的推理摘要;开始新的摘要部分时,summaryIndex会递增。item/reasoning/summaryPartAdded- 标记推理摘要部分之间的边界。item/reasoning/textDelta- 流式传输原始推理文本(模型支持时)。item/commandExecution/outputDelta- 流式传输命令的 stdout/stderr;按顺序追加增量内容。item/fileChange/outputDelta- 适用于旧版apply_patch文本输出的弃用兼容性通知。当前版本的 app-server 不再发出此通知;请改用fileChange项和turn/diff/updated。
如果一个 turn 失败,服务器会发送包含 { error: { message, codexErrorInfo?, additionalDetails? } } 的 error 事件,然后以 status: "failed" 结束该 turn。如果上游 HTTP 状态可用,则会出现在 codexErrorInfo.httpStatusCode 中。
常见的 codexErrorInfo 值包括:
ContextWindowExceededUsageLimitExceededHttpConnectionFailed(上游 4xx/5xx 错误)ResponseStreamConnectionFailedResponseStreamDisconnectedResponseTooManyFailedAttemptsBadRequest、Unauthorized、SandboxError、InternalServerError、Other
如果上游 HTTP 状态可用,服务器会在相关 codexErrorInfo 变体的 httpStatusCode 中转发该状态。
根据用户的 Codex 设置,命令执行和文件更改可能需要审批。app-server 会向客户端发送由服务器发起的 JSON-RPC 请求,客户端则使用决策载荷进行响应。
-
命令执行决策:
accept、acceptForSession、decline、cancel,或{ "acceptWithExecpolicyAmendment": { "execpolicy_amendment": ["cmd", "..."] } }。 -
文件更改决策:
accept、acceptForSession、decline、cancel。 -
请求包含
threadId和turnId—— 使用它们将 UI 状态限定到当前活动对话。 -
服务器会继续或拒绝该工作,并以
item/completed结束此项。
命令执行审批
Section titled “命令执行审批”消息顺序:
item/started显示待处理的commandExecution项,其中包含command、cwd和其他字段。item/commandExecution/requestApproval包含itemId、threadId、turnId、可选的reason、可选的command、可选的cwd、可选的commandActions、可选的proposedExecpolicyAmendment、可选的networkApprovalContext以及可选的availableDecisions。当initialize.params.capabilities.experimentalApi = true时,载荷还可以包含描述所请求的逐命令沙箱访问权限的实验性additionalPermissions。additionalPermissions中的所有文件系统路径在传输时都是绝对路径。- 客户端使用上述命令执行审批决策之一进行响应。
serverRequest/resolved确认待处理请求已得到响应或已清除。item/completed返回最终的commandExecution项,其status为completed | failed | declined。
存在 networkApprovalContext 时,该提示请求的是受管网络访问权限(而非一般的 shell 命令审批)。当前 v2 架构会公开目标 host 和 protocol;客户端应呈现网络专用提示,不应依赖 command 作为对用户有意义的 shell 命令预览。
Codex 会按目标地址(host、协议和端口)将并发的网络审批提示分组。因此,app-server 可能会发送一个提示,以解除对同一目标地址的多个排队请求;而同一主机上的不同端口会被分别处理。
文件更改审批
Section titled “文件更改审批”消息顺序:
item/started发出一个fileChange项,其中包含拟议的changes和status: "inProgress"。item/fileChange/requestApproval包含itemId、threadId、turnId、可选的reason以及可选的grantRoot。- 客户端使用上述文件更改审批决策之一进行响应。
serverRequest/resolved确认待处理请求已得到响应或已清除。item/completed返回最终的fileChange项,其status为completed | failed | declined。
tool/requestUserInput
Section titled “tool/requestUserInput”客户端响应 item/tool/requestUserInput 后,app-server 会发送包含 { threadId, requestId } 的 serverRequest/resolved。如果待处理请求在客户端响应前因 turn 开始、turn 完成或 turn 中断而被清除,服务器也会针对该清理操作发送相同的通知。
请求参数包含 autoResolutionMs,其值为整数形式的毫秒超时时间,或
null。存在该参数时,宿主客户端可以在该时间间隔后自动处理提示,前提是用户未作答。
内置的 request_permissions 工具会发送
item/permissions/requestApproval,其中包含 threadId、turnId、itemId、
environmentId、cwd、可选的 reason,以及所请求的网络或文件系统权限。
使用仅包含已授予权限的 permissions 进行响应。
将 scope 设置为 "session",可将授权持久化到同一会话中的后续 turn;省略该字段或使用
"turn",则表示仅对当前 turn 授权。未请求的权限会被忽略。
MCP 服务器引导请求
Section titled “MCP 服务器引导请求”MCP 服务器可以通过 mcpServer/elicitation/request 中断一个 turn。该请求包含
threadId、可选的 turnId、serverName,以及以下请求形状之一:
mode: "form"或mode: "openai/form",包含message和requestedSchema。mode: "url",包含message、url和elicitationId。
使用 action: "accept" 和请求的 content 进行响应,或者使用
action: "decline" 或 "cancel",并将 content 设置为 null。随后,app-server 会发送
serverRequest/resolved。如需接收 openai/form 变体,请通过
initialize.params.capabilities.mcpServerOpenaiFormElicitation 选择加入。
动态工具调用(实验性)
Section titled “动态工具调用(实验性)”thread/start 中的 dynamicTools 以及相应的 item/tool/call 请求或响应流程属于实验性 API。
动态工具名称和命名空间名称必须遵循 Responses API 的命名约束。 请避免使用内置 Codex 工具所使用的保留命名空间名称。
turn 中调用动态工具时,app-server 会发送:
item/started,其中item.type = "dynamicToolCall"、status = "inProgress",并包含tool和arguments。item/tool/call,作为发送给客户端的服务器请求。- 包含返回内容项的客户端响应载荷。
item/completed,其中包含item.type = "dynamicToolCall"、最终的status,以及任何返回的contentItems或success值。
MCP 工具调用审批(应用)
Section titled “MCP 工具调用审批(应用)”应用(连接器)的工具调用也可能需要审批。当应用工具调用具有副作用时,服务器可能会通过 tool/requestUserInput 请求审批,并提供 接受、拒绝 和 取消 等选项。即使工具同时声明了权限较低的提示,破坏性工具注释也始终会触发审批。如果用户拒绝或取消,相关的 mcpToolCall 项会以错误状态完成,而不会运行该工具。
在用户文本输入中加入 $<skill-name> 即可调用技能。建议添加 skill 输入项,以便服务器注入完整的技能说明,而不依赖模型解析名称。
{ "method": "turn/start", "id": 101, "params": { "threadId": "thread-1", "input": [ { "type": "text", "text": "$skill-creator Add a new skill for triaging flaky CI." }, { "type": "skill", "name": "skill-creator", "path": "/Users/me/.codex/skills/skill-creator/SKILL.md" } ] }}如果省略 skill 项,模型仍会解析 $<skill-name> 标记并尝试定位技能,这可能会增加延迟。
示例:
$skill-creator Add a new skill for triaging flaky CI and include step-by-step usage.使用 skills/list 获取可用技能(可选择通过 cwds 限定范围,并使用 forceReload)。你还可以使用 perCwdExtraUserRoots,针对特定的 cwd 值,将额外的绝对路径作为 user 范围进行扫描。app-server 会忽略 cwd 不在 cwds 中的条目。skills/list 可能会按 cwd 重用缓存结果;设置 forceReload: true 可从磁盘刷新结果。如果存在,服务器会从 SKILL.json 中读取 interface 和 dependencies。
{ "method": "skills/list", "id": 25, "params": { "cwds": ["/Users/me/project", "/Users/me/other-project"], "forceReload": true, "perCwdExtraUserRoots": [ { "cwd": "/Users/me/project", "extraUserRoots": ["/Users/me/shared-skills"] } ]} }{ "id": 25, "result": { "data": [{ "cwd": "/Users/me/project", "skills": [ { "name": "skill-creator", "description": "Create or update a Codex skill", "enabled": true, "interface": { "displayName": "Skill Creator", "shortDescription": "Create or update a Codex skill" }, "dependencies": { "tools": [ { "type": "env_var", "value": "GITHUB_TOKEN", "description": "GitHub API token" }, { "type": "mcp", "value": "github", "transport": "streamable_http", "url": "https://example.com/mcp" } ] } } ], "errors": [] }]} }当受监视的本地技能文件发生更改时,服务器还会发送 skills/changed 通知。将其视为缓存失效信号,并在需要时使用当前参数重新运行 skills/list。
要按路径启用或禁用技能:
{ "method": "skills/config/write", "id": 26, "params": { "path": "/Users/me/.codex/skills/skill-creator/SKILL.md", "enabled": false }}应用(连接器)
Section titled “应用(连接器)”使用 app/list 获取可用应用。在 CLI/TUI 中,/apps 是面向用户的选择器;在自定义客户端中,直接调用 app/list。每个条目同时包含 isAccessible(用户可用)和 isEnabled(在 config.toml 中启用),以便客户端区分安装/访问状态与本地启用状态。应用条目还可以包含可选的 branding、appMetadata 和 labels 字段。
{ "method": "app/list", "id": 50, "params": { "cursor": null, "limit": 50, "threadId": "thread-1", "forceRefetch": false} }{ "id": 50, "result": { "data": [ { "id": "demo-app", "name": "Demo App", "description": "Example connector for documentation.", "logoUrl": "https://example.com/demo-app.png", "logoUrlDark": null, "distributionChannel": null, "branding": null, "appMetadata": null, "labels": null, "installUrl": "https://chatgpt.com/apps/demo-app/demo-app", "isAccessible": true, "isEnabled": true } ], "nextCursor": null} }如果提供 threadId,应用功能门控(features.apps)会使用该 thread 的配置快照。省略时,app-server 使用最新的全局配置。
app/list 会在可访问应用和目录应用都加载完成后返回。设置 forceRefetch: true 可绕过应用缓存并获取最新数据。只有刷新成功时,缓存条目才会被替换。
服务器还会在任一来源(可访问的应用或目录应用)完成加载时发送 app/list/updated 通知。每条通知都包含最新的合并应用列表。
{ "method": "app/list/updated", "params": { "data": [ { "id": "demo-app", "name": "Demo App", "description": "Example connector for documentation.", "logoUrl": "https://example.com/demo-app.png", "logoUrlDark": null, "distributionChannel": null, "branding": null, "appMetadata": null, "labels": null, "installUrl": "https://chatgpt.com/apps/demo-app/demo-app", "isAccessible": true, "isEnabled": true } ] }}通过在文本输入中插入 $<app-slug>,并添加路径为 app://<id> 的 mention 输入项来调用应用(推荐)。
{ "method": "turn/start", "id": 51, "params": { "threadId": "thread-1", "input": [ { "type": "text", "text": "$demo-app Pull the latest updates from the team." }, { "type": "mention", "name": "Demo App", "path": "app://demo-app" } ] }}应用设置的 Config RPC 示例
Section titled “应用设置的 Config RPC 示例”使用 config/read、config/value/write 和 config/batchWrite 检查或更新 config.toml 中的应用控制项。
读取生效的应用配置结构(包括 _default 和按工具划分的覆盖设置):
{ "method": "config/read", "id": 60, "params": { "includeLayers": false } }{ "id": 60, "result": { "config": { "apps": { "_default": { "enabled": true, "destructive_enabled": true, "open_world_enabled": true, "approvals_reviewer": "user", "default_tools_approval_mode": "auto" }, "google_drive": { "enabled": true, "destructive_enabled": false, "approvals_reviewer": "auto_review", "default_tools_approval_mode": "prompt", "tools": { "files/delete": { "enabled": false, "approval_mode": "approve" } } } } }} }apps._default.approvals_reviewer 为所有应用设置审核者,除非某个应用的值覆盖了它。如果两者都省略,应用将继承顶层的 approvals_reviewer 值。apps._default.default_tools_approval_mode 为没有按应用或按工具覆盖设置的工具设置备用审批模式。托管的审批模式要求会覆盖工具的审批模式设置。
更新单个应用设置:
{ "method": "config/value/write", "id": 61, "params": { "keyPath": "apps.google_drive.default_tools_approval_mode", "value": "prompt", "mergeStrategy": "replace" }}以原子方式应用多个应用编辑:
{ "method": "config/batchWrite", "id": 62, "params": { "edits": [ { "keyPath": "apps._default.destructive_enabled", "value": false, "mergeStrategy": "upsert" }, { "keyPath": "apps.google_drive.tools.files/delete.approval_mode", "value": "approve", "mergeStrategy": "upsert" } ] }}检测并导入外部 Agent 配置
Section titled “检测并导入外部 Agent 配置”使用 externalAgentConfig/detect 查找可迁移的外部 Agent 工件,然后将选中的条目传递给 externalAgentConfig/import。
检测示例:
{ "method": "externalAgentConfig/detect", "id": 63, "params": { "includeHome": true, "cwds": ["/Users/me/project"]} }{ "id": 63, "result": { "items": [ { "itemType": "AGENTS_MD", "description": "Import /Users/me/project/CLAUDE.md to /Users/me/project/AGENTS.md.", "cwd": "/Users/me/project" }, { "itemType": "SKILLS", "description": "Copy skill folders from /Users/me/.claude/skills to /Users/me/.agents/skills.", "cwd": null } ]} }导入示例:
{ "method": "externalAgentConfig/import", "id": 64, "params": { "migrationItems": [ { "itemType": "AGENTS_MD", "description": "Import /Users/me/project/CLAUDE.md to /Users/me/project/AGENTS.md.", "cwd": "/Users/me/project" } ], "source": "claude-code"} }{ "id": 64, "result": { "importId": "8ae96ff3-3425-4f4c-8772-b6fd61502868" } }可选的顶层 source 导入参数用于标记生成所选迁移项的产品。
服务器会在各项类型完成时发送 externalAgentConfig/import/progress,并在所有同步和后台导入完成后发送 externalAgentConfig/import/completed。这些通知包含响应中的同一个 importId,以及带有每种类型的 successes 和 failures 的 itemTypeResults。完成通知可能紧随响应立即到达,也可能在后台远程导入完成后到达。
{ "method": "externalAgentConfig/import/progress", "params": { "importId": "8ae96ff3-3425-4f4c-8772-b6fd61502868", "itemTypeResults": [ { "itemType": "AGENTS_MD", "successes": [ { "itemType": "AGENTS_MD", "cwd": "/Users/me/project", "source": null, "target": "/Users/me/project/AGENTS.md" } ], "failures": [] } ]} }{ "method": "externalAgentConfig/import/completed", "params": { "importId": "8ae96ff3-3425-4f4c-8772-b6fd61502868", "itemTypeResults": [ { "itemType": "AGENTS_MD", "successes": [ { "itemType": "AGENTS_MD", "cwd": "/Users/me/project", "source": null, "target": "/Users/me/project/AGENTS.md" } ], "failures": [] } ]} }读取之前已完成的导入:
{ "method": "externalAgentConfig/import/readHistories", "id": 65 }{ "id": 65, "result": { "data": [ { "importId": "8ae96ff3-3425-4f4c-8772-b6fd61502868", "completedAtMs": 1781784000000, "successes": [ { "itemType": "AGENTS_MD", "cwd": "/Users/me/project", "source": null, "target": "/Users/me/project/AGENTS.md" } ], "failures": [] }] } }支持的 itemType 值包括 AGENTS_MD、CONFIG、SKILLS、PLUGINS、MCP_SERVER_CONFIG、SUBAGENTS、HOOKS、COMMANDS 和 SESSIONS。对于 PLUGINS 项,details.plugins 列出每个 marketplaceName 以及 Codex 可尝试迁移的 pluginNames。检测只返回仍有待处理工作的项目。例如,如果 AGENTS.md 已存在且非空,Codex 会跳过 AGENTS 迁移;技能导入不会覆盖现有技能目录。
从 .claude/settings.json 检测插件时,Codex 会从 extraKnownMarketplaces 读取已配置的市场源。如果 enabledPlugins 包含来自 claude-plugins-official 的插件,但缺少市场源,Codex 会推断 anthropics/claude-plugins-official 为该源。
身份验证端点
Section titled “身份验证端点”JSON-RPC 身份验证/账户接口提供请求/响应方法以及服务器发起的通知(无 id)。使用这些接口可以确定身份验证状态、开始或取消登录、退出登录、检查 ChatGPT 速率限制,并在积分耗尽或达到使用限制时通知工作区所有者。
身份验证模式
Section titled “身份验证模式”Codex 支持以下身份验证模式。account/updated.authMode 显示当前活动模式,并在可用时包含当前 ChatGPT 的 planType。account/read 还会报告账户和套餐详细信息。
- API 密钥(
apikey) - 调用方提供类型为apiKey的 OpenAI API 密钥,Codex 会保存该密钥以供 API 请求使用。 - ChatGPT 托管(
chatgpt) - Codex 负责 ChatGPT OAuth 流程、持久化令牌并自动刷新令牌。浏览器流程使用type: "chatgpt"启动,设备代码流程使用type: "chatgptDeviceCode"启动。 - ChatGPT 外部令牌(
chatgptAuthTokens) - 实验性模式,适用于已经负责用户 ChatGPT 身份验证生命周期的宿主应用。宿主应用直接提供accessToken、chatgptAccountId和可选的chatgptPlanType,并且必须在收到请求时刷新令牌。 - Amazon Bedrock -
account/read会将 Bedrock 账户报告为type: "amazonBedrock",并指出凭据来自 Codex 管理的 Bedrock API 密钥(credentialSource: "codexManaged")还是外部 AWS 凭据链(credentialSource: "awsManaged")。account/updated.authMode使用bedrockApiKey表示 Codex 管理的 Bedrock API 密钥。
API 概览
Section titled “API 概览”account/read- 获取当前账户信息;可选择刷新令牌。account/login/start- 开始登录(apiKey、chatgpt、chatgptDeviceCode或实验性的chatgptAuthTokens)。account/login/completed(通知)- 在登录尝试完成时发送(成功或出错)。account/login/cancel- 通过loginId取消待处理的托管 ChatGPT 登录。account/logout- 退出登录;触发account/updated。account/updated(通知)- 在身份验证模式发生变化时发送(authMode:apikey、chatgpt、chatgptAuthTokens、agentIdentity、personalAccessToken、bedrockApiKey或null),并在可用时包含planType。account/chatgptAuthTokens/refresh(服务器请求)- 在发生授权错误后请求新的外部托管 ChatGPT 令牌。account/rateLimits/read- 获取 ChatGPT 速率限制。account/rateLimits/updated(通知)- 在用户的 ChatGPT 速率限制发生变化时发送。account/sendAddCreditsNudgeEmail- 请求 ChatGPT 向工作区所有者发送电子邮件,告知其积分已耗尽或已达到使用限制。account/rateLimitResetCredit/consume- 使用调用方提供的idempotencyKey值消耗一个已获得的速率限制重置额度。account/usage/read- 获取 ChatGPT 账户令牌活动摘要和每日分桶数据。account/workspaceMessages/read- 获取活动工作区消息,包括可用的通知标题。mcpServer/oauthLogin/completed(通知)- 在mcpServer/oauth/login流程完成后发送;负载包括{ name, threadId, success, error? }。对于应用范围或插件 OAuth 流程,threadId可以为null。mcpServer/startupStatus/updated(通知)- 在已配置 MCP 服务器的启动状态发生变化时发送;负载包括{ threadId, name, status, error, failureReason }。对于应用范围的启动,threadId为null。启动失败时,failureReason: "reauthenticationRequired"表示存储的 OAuth 凭据已过期且无法刷新,因此客户端应提供重新连接服务器的选项。
1)检查身份验证状态
Section titled “1)检查身份验证状态”请求:
{ "method": "account/read", "id": 1, "params": { "refreshToken": false } }响应示例:
{ "id": 1, "result": { "account": null, "requiresOpenaiAuth": false } }{ "id": 1, "result": { "account": null, "requiresOpenaiAuth": true } }{ "id": 1, "result": { "account": { "type": "apiKey" }, "requiresOpenaiAuth": true }}{ "id": 1, "result": { "account": { "type": "amazonBedrock", "credentialSource": "codexManaged" }, "requiresOpenaiAuth": false }}{ "id": 1, "result": { "account": { "type": "amazonBedrock", "credentialSource": "awsManaged" }, "requiresOpenaiAuth": false }}{ "id": 1, "result": { "account": { "type": "chatgpt", "email": "user@example.com", "planType": "pro" }, "requiresOpenaiAuth": true }}字段说明:
refreshToken(布尔值):在 ChatGPT 托管模式下设为true可强制刷新令牌。在外部令牌模式(chatgptAuthTokens)下,app-server 会忽略此标志。- 当 ChatGPT 账户没有电子邮件地址时,
email为null。 requiresOpenaiAuth反映当前活动提供商;当其为false时,Codex 无需 OpenAI 凭据即可运行。- Amazon Bedrock 使用 Codex 管理的 Bedrock API 密钥时,会报告
credentialSource: "codexManaged";使用外部 AWS 凭据路径时,会报告credentialSource: "awsManaged"。这表示所选的凭据来源,但不会验证 AWS 凭据链能否解析凭据。
2)使用 API 密钥登录
Section titled “2)使用 API 密钥登录”-
发送:
{"method": "account/login/start","id": 2,"params": { "type": "apiKey", "apiKey": "sk-..." }} -
预期结果:
{ "id": 2, "result": { "type": "apiKey" } } -
通知:
{"method": "account/login/completed","params": { "loginId": null, "success": true, "error": null }}{"method": "account/updated","params": { "authMode": "apikey", "planType": null }}
3)使用 ChatGPT 登录(浏览器流程)
Section titled “3)使用 ChatGPT 登录(浏览器流程)”-
开始:
{"method": "account/login/start","id": 3,"params": {"type": "chatgpt","useHostedLoginSuccessPage": true,"appBrand": "chatgpt"}}默认情况下,成功的浏览器回调会重定向到本地成功页面。 当不需要组织设置时,将
useHostedLoginSuccessPage: true设置为使用托管成功页面。启用托管成功页面后,appBrand可以是"codex"或"chatgpt";省略或设置为null时,默认为"codex"。{"id": 3,"result": {"type": "chatgpt","loginId": "<uuid>","authUrl": "https://chatgpt.com/...&redirect_uri=http%3A%2F%2Flocalhost%3A<port>%2Fauth%2Fcallback"}} -
在浏览器中打开
authUrl;app-server 会托管本地回调。 -
等待通知:
{"method": "account/login/completed","params": { "loginId": "<uuid>", "success": true, "error": null }}{"method": "account/updated","params": { "authMode": "chatgpt", "planType": "plus" }}
3b)使用 ChatGPT 登录(设备代码流程)
Section titled “3b)使用 ChatGPT 登录(设备代码流程)”当客户端负责登录流程,或浏览器回调不稳定时,使用此流程。
-
启动:
{"method": "account/login/start","id": 4,"params": { "type": "chatgptDeviceCode" }}{"id": 4,"result": {"type": "chatgptDeviceCode","loginId": "<uuid>","verificationUrl": "https://auth.openai.com/codex/device","userCode": "ABCD-1234"}} -
向用户显示
verificationUrl和userCode;前端负责用户体验。 -
等待通知:
{"method": "account/login/completed","params": { "loginId": "<uuid>", "success": true, "error": null }}{"method": "account/updated","params": { "authMode": "chatgpt", "planType": "plus" }}
3c) 使用外部管理的 ChatGPT 令牌登录(chatgptAuthTokens)
Section titled “3c) 使用外部管理的 ChatGPT 令牌登录(chatgptAuthTokens)”仅当宿主应用负责管理用户的 ChatGPT 身份验证生命周期并直接提供令牌时,才使用此实验模式。客户端必须在使用此登录类型之前,在 initialize 期间设置 capabilities.experimentalApi = true。
-
发送:
{"method": "account/login/start","id": 7,"params": {"type": "chatgptAuthTokens","accessToken": "<jwt>","chatgptAccountId": "org-123","chatgptPlanType": "business"}} -
预期结果:
{ "id": 7, "result": { "type": "chatgptAuthTokens" } } -
通知:
{"method": "account/login/completed","params": { "loginId": null, "success": true, "error": null }}{"method": "account/updated","params": { "authMode": "chatgptAuthTokens", "planType": "business" }}
当服务器收到 401 Unauthorized 时,它可能会向宿主应用请求刷新后的令牌:
{ "method": "account/chatgptAuthTokens/refresh", "id": 8, "params": { "reason": "unauthorized", "previousAccountId": "org-123" }}{ "id": 8, "result": { "accessToken": "<jwt>", "chatgptAccountId": "org-123", "chatgptPlanType": "business" } }刷新响应成功后,服务器会重试原始请求。请求约在 10 秒后超时。
4) 取消 ChatGPT 登录
Section titled “4) 取消 ChatGPT 登录”{ "method": "account/login/cancel", "id": 4, "params": { "loginId": "<uuid>" } }{ "method": "account/login/completed", "params": { "loginId": "<uuid>", "success": false, "error": "..." } }{ "method": "account/logout", "id": 5 }{ "id": 5, "result": {} }{ "method": "account/updated", "params": { "authMode": null, "planType": null } }6) 速率限制(ChatGPT)
Section titled “6) 速率限制(ChatGPT)”{ "method": "account/rateLimits/read", "id": 6 }{ "id": 6, "result": { "rateLimits": { "limitId": "codex", "limitName": null, "primary": { "usedPercent": 25, "windowDurationMins": 15, "resetsAt": 1730947200 }, "secondary": null, "rateLimitReachedType": null }, "rateLimitsByLimitId": { "codex": { "limitId": "codex", "limitName": null, "primary": { "usedPercent": 25, "windowDurationMins": 15, "resetsAt": 1730947200 }, "secondary": null, "rateLimitReachedType": null }, "codex_other": { "limitId": "codex_other", "limitName": "codex_other", "primary": { "usedPercent": 42, "windowDurationMins": 60, "resetsAt": 1730950800 }, "secondary": null, "rateLimitReachedType": null } }, "rateLimitResetCredits": { "availableCount": 2, "credits": [{ "id": "RateLimitResetCredit_1", "resetType": "codexRateLimits", "status": "available", "grantedAt": 1781654400, "expiresAt": 1784246400, "title": "Rate-limit reset", "description": "Reset an eligible Codex rate-limit window." }] }} }{ "method": "account/rateLimits/updated", "params": { "rateLimits": { "limitId": "codex", "primary": { "usedPercent": 31, "windowDurationMins": 15, "resetsAt": 1730948100 } }} }字段说明:
rateLimits是向后兼容的单桶视图。rateLimitsByLimitId(如果存在)是按计量的limit_id(例如codex)键控的多桶视图。limitId是计量桶标识符。limitName是该桶面向用户显示的可选标签。usedPercent是当前配额窗口内的使用量。windowDurationMins是配额窗口的长度。resetsAt是下一次重置时间的 Unix 时间戳(秒)。- 当服务器返回与某个桶关联的 ChatGPT 方案时,会包含
planType。 - 当服务器返回剩余工作区额度详情时,会包含
credits。 - 达到限制时,
rateLimitReachedType会标识服务器分类的限制状态。 - 当服务提供时,
rateLimitResetCredits包含可用的已赚取重置次数;否则为null。 - 当仅知道数量时,
rateLimitResetCredits.credits为null。空数组表示服务已获取详情,但没有返回可用额度。服务可以限制详情行数,因此应以availableCount为准。 - 每个详情行都包含不透明的
id、resetType、status、grantedAt、expiresAt(可以为null)、title(可以为null)和description(可以为null)。 - 消耗重置额度后,获取
account/rateLimits/read。
7) 令牌使用量(ChatGPT)
Section titled “7) 令牌使用量(ChatGPT)”使用 account/usage/read 获取 ChatGPT 令牌活动摘要字段和
可选的每日分桶。
{ "method": "account/usage/read", "id": 7 }{ "id": 7, "result": { "summary": { "lifetimeTokens": 1234567, "peakDailyTokens": 45678, "longestRunningTurnSec": 540, "currentStreakDays": 8, "longestStreakDays": 14 }, "dailyUsageBuckets": [ { "startDate": "2026-06-18", "tokens": 12345 } ]} }字段说明:
- 当服务尚未返回某项指标时,
summary值可能为null。 dailyUsageBuckets可能为null;如果存在,每个分桶都包含startDate和tokens。- 此端点要求使用由 Codex 服务支持的身份验证。ChatGPT、外部 ChatGPT 令牌、代理身份和个人访问令牌身份验证均可用;仅 API 密钥身份验证和 Bedrock 身份验证不可用。
8) 已赚取的速率限制重置(ChatGPT)
Section titled “8) 已赚取的速率限制重置(ChatGPT)”使用 account/rateLimitResetCredit/consume 消耗一个已赚取的重置额度。
{ "method": "account/rateLimitResetCredit/consume", "id": 8, "params": { "idempotencyKey": "8ae96ff3-3425-4f4c-8772-b6fd61502868", "creditId": "RateLimitResetCredit_1" } }{ "id": 8, "result": { "outcome": "reset" } }字段说明:
idempotencyKey必须非空。为每次逻辑兑换尝试使用一个 UUID,并在重试该尝试时复用相同的值。creditId是可选的。提供时,它必须是来自account/rateLimits/read的非空不透明 ID。省略时,服务会选择下一个可用额度。reset表示已消耗一个额度。alreadyRedeemed表示相同的兑换操作之前已经完成。将其视为幂等成功,并刷新账户限制。nothingToReset表示没有符合条件的速率限制窗口可供重置。noCredit表示账户没有可用的已赚取重置额度。- 消耗重置额度后,获取
account/rateLimits/read,不要根据此响应推断更新后的窗口。
9) 通知工作区所有者有关限制的信息
Section titled “9) 通知工作区所有者有关限制的信息”使用 account/sendAddCreditsNudgeEmail,在额度耗尽或达到使用限制时,请求 ChatGPT 向工作区所有者发送电子邮件。
{ "method": "account/sendAddCreditsNudgeEmail", "id": 9, "params": { "creditType": "credits" } }{ "id": 9, "result": { "status": "sent" } }工作区额度耗尽时,使用 creditType: "credits";达到工作区使用限制时,使用 creditType: "usage_limit"。如果所有者最近已收到通知,响应状态为 cooldown_active。
10) 工作区消息(ChatGPT)
Section titled “10) 工作区消息(ChatGPT)”使用 account/workspaceMessages/read 获取当前工作区的活动消息,其中包括可用时的通知标题。
{ "method": "account/workspaceMessages/read", "id": 10 }{ "id": 10, "result": { "featureEnabled": true, "messages": [ { "messageId": "msg_123", "messageType": "headline", "messageBody": "Workspace maintenance starts at 5pm.", "createdAt": 1781395200, "archivedAt": null }] } }