Codex App Server
Codex app-server는 Codex VS Code extension 같은 rich client를 구동하기 위해 Codex가 사용하는 interface입니다. 자체 product 안에 authentication, conversation history, approvals, streamed agent event를 깊게 통합하고 싶을 때 사용합니다. App-server 구현은 Codex GitHub repository의 openai/codex/codex-rs/app-server에 open source로 공개되어 있습니다. Open-source Codex component 전체 목록은 Open Source를 참고하십시오.
Job automation이나 CI 실행이 목적이라면 app-server 대신 Codex SDK를 사용하십시오.
Protocol
codex app-server는 MCP처럼 JSON-RPC 2.0 message를 사용해 bidirectional communication을 지원합니다. Wire에서는 "jsonrpc":"2.0" header를 생략합니다.
지원 transport:
stdio:--listen stdio://, 기본값. Newline-delimited JSON(JSONL)을 사용합니다.websocket:--listen ws://IP:PORT, experimental 및 unsupported. WebSocket text frame마다 JSON-RPC message 하나를 보냅니다.off:--listen off. Local transport를 노출하지 않습니다.
--listen ws://IP:PORT로 실행하면 같은 listener가 기본 HTTP health probe도 제공합니다.
GET /readyz: listener가 새 연결을 받을 수 있으면200 OK를 반환합니다.GET /healthz: request에Originheader가 없으면200 OK를 반환합니다.Originheader가 있는 request는403 Forbidden으로 거부됩니다.
WebSocket transport는 experimental 및 unsupported입니다. ws://127.0.0.1:PORT 같은 loopback listener는 localhost와 SSH port-forwarding workflow에 적합합니다. Non-loopback WebSocket listener는 rollout 중 기본적으로 unauthenticated connection을 허용하므로 원격에 노출하기 전에 WebSocket auth를 구성하십시오.
지원 WebSocket auth flag:
--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
Signed bearer token에는 --ws-issuer, --ws-audience, --ws-max-clock-skew-seconds도 설정할 수 있습니다. Client는 WebSocket handshake에서 credential을 Authorization: Bearer {token}으로 제시하고, app-server는 JSON-RPC initialize 전에 auth를 강제합니다.
Raw bearer token을 command line에 전달하는 대신 --ws-token-file을 권장합니다. --ws-token-sha256은 client가 raw high-entropy token을 별도 local secret store에 보관할 때만 사용하십시오. Hash는 verifier일 뿐이며 client는 여전히 원래 token이 필요합니다.
WebSocket mode에서 app-server는 bounded queue를 사용합니다. Request ingress가 가득 차면 server는 JSON-RPC error code -32001과 "Server overloaded; retry later." message로 새 request를 거부합니다. Client는 jitter가 있는 exponential backoff로 재시도해야 합니다.
Message schema
Request는 method, params, id를 포함합니다.
{ "method": "thread/start", "id": 10, "params": { "model": "gpt-5.4" } }
Response는 같은 id를 사용하고 result 또는 error를 포함합니다.
{ "id": 10, "result": { "thread": { "id": "thr_123" } } }
{ "id": 10, "error": { "code": 123, "message": "Something went wrong" } }
Notification은 id를 생략하고 method와 params만 사용합니다.
{ "method": "turn/started", "params": { "turn": { "id": "turn_456" } } }
CLI에서 TypeScript schema 또는 JSON Schema bundle을 생성할 수 있습니다. 각 output은 실행한 Codex version에 맞춰 생성됩니다.
codex app-server generate-ts --out ./schemas
codex app-server generate-json-schema --out ./schemas
시작하기
codex app-server로 server를 시작합니다. 기본 transport는 stdio입니다. Experimental WebSocket에는codex app-server --listen ws://127.0.0.1:4500을 사용합니다.- 선택한 transport로 client를 연결한 뒤
initialize를 보내고initializednotification을 보냅니다. - Thread와 turn을 시작한 뒤 활성 transport stream에서 notification을 계속 읽습니다.
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" } });
Core primitives
- Thread: 사용자와 Codex agent 사이의 대화입니다. Thread는 turn을 포함합니다.
- Turn: 단일 사용자 요청과 그 뒤의 agent work입니다. Turn은 item을 포함하고 incremental update를 stream합니다.
- Item: 입력 또는 출력 단위입니다. User message, agent message, command run, file change, tool call 등이 포함됩니다.
Thread API로 conversation을 만들고, 나열하고, archive합니다. Turn API로 conversation을 진행하고 turn notification으로 progress를 stream합니다.
Lifecycle overview
- Connection마다 한 번 initialize: Transport connection을 연 직후 client metadata가 포함된
initializerequest를 보내고initializednotification을 emit합니다. 이 handshake 전의 request는 거부됩니다. - Thread 시작 또는 재개: 새 conversation에는
thread/start, 기존 conversation continuation에는thread/resume, history branch에는thread/fork를 호출합니다. - Turn 시작:
threadId와 user input으로turn/start를 호출합니다. Optional field로 model, personality,cwd, sandbox policy 등을 override할 수 있습니다. - Active turn steer:
turn/steer로 현재 진행 중인 turn에 user input을 추가합니다. 새 turn을 만들지 않습니다. - Event stream:
turn/start뒤 stdout notification을 계속 읽습니다.thread/archived,thread/unarchived,item/started,item/completed,item/agentMessage/delta, tool progress 등이 포함됩니다. - Turn 종료: Model이 끝나거나
turn/interruptcancellation 뒤 server가 final status가 포함된turn/completed를 emit합니다.
Initialization
Client는 transport connection마다 다른 method를 호출하기 전에 initialize request를 한 번 보내고, 이어서 initialized notification으로 acknowledge해야 합니다. Initialization 전에 보낸 request는 Not initialized error를 받고, 같은 connection에서 반복 initialize를 호출하면 Already initialized가 반환됩니다.
Server는 upstream service에 제시할 user agent string과 runtime target을 설명하는 platformFamily, platformOs 값을 반환합니다. Integration 식별에는 clientInfo를 설정합니다.
initialize.params.capabilities는 connection별 notification opt-out도 지원합니다. optOutNotificationMethods는 해당 connection에서 억제할 정확한 method 이름 목록입니다. Matching은 exact입니다. Unknown method name은 허용되고 무시됩니다.
Enterprise 사용을 위한 새 Codex integration을 개발한다면 Compliance Logs Platform 식별을 위해 clientInfo.name을 안정적으로 설정하고, known clients list 추가를 위해 OpenAI에 문의하십시오.
예:
{
"method": "initialize",
"id": 0,
"params": {
"clientInfo": {
"name": "codex_vscode",
"title": "Codex VS Code Extension",
"version": "0.1.0"
}
}
}
Notification opt-out 예:
{
"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"]
}
}
}
Experimental API opt-in
일부 app-server method와 field는 의도적으로 experimentalApi capability 뒤에 gate되어 있습니다.
- Stable API surface에 머무르려면
capabilities를 생략하거나experimentalApi를false로 둡니다. Server는 experimental method/field를 거부합니다. - Experimental method와 field를 사용하려면
capabilities.experimentalApi를true로 설정합니다.
Opt-in 없이 experimental method 또는 field를 보내면 app-server는 다음 오류를 반환합니다.
descriptor requires experimentalApi capability
API overview
Thread methods
| Method | 설명 |
|---|---|
thread/start | 새 thread를 만들고 thread/started를 emit하며 해당 thread event에 자동 subscribe합니다. |
thread/resume | 기존 thread id를 다시 열어 이후 turn/start가 이어 붙게 합니다. |
thread/fork | 저장된 history를 복사해 새 thread id로 fork하고 thread/started를 emit합니다. |
thread/read | Thread를 resume하지 않고 stored thread를 읽습니다. includeTurns로 turn history 포함 여부를 정합니다. |
thread/list | Stored thread log를 pagination과 filter로 나열합니다. |
thread/turns/list | Stored thread의 turn history를 resume 없이 page합니다. |
thread/loaded/list | Memory에 loaded된 thread id를 나열합니다. |
thread/name/set | Loaded thread 또는 persisted rollout의 user-facing name을 설정합니다. |
thread/goal/set, thread/goal/get, thread/goal/clear | Experimental goal을 설정, 조회, 제거합니다. |
thread/metadata/update | SQLite-backed stored thread metadata를 patch합니다. 현재 gitInfo를 지원합니다. |
thread/archive | Thread log file을 archived directory로 이동하고 thread/archived를 emit합니다. |
thread/unarchive | Archived thread rollout을 active sessions directory로 복원합니다. |
thread/unsubscribe | 현재 connection의 thread event subscription을 제거합니다. 마지막 subscriber면 grace period 뒤 unload될 수 있습니다. |
thread/status/changed | Loaded thread runtime status가 바뀔 때 emit되는 notification입니다. |
thread/compact/start | Thread의 conversation history compaction을 trigger합니다. |
thread/shellCommand | Thread에 속한 user-initiated shell command를 실행합니다. Sandbox 밖 full access로 실행되며 thread sandbox policy를 상속하지 않습니다. |
thread/backgroundTerminals/clean | Thread의 실행 중인 background terminal을 모두 중지합니다. Experimental입니다. |
thread/rollback | 마지막 N개 turn을 in-memory context에서 제거하고 rollback marker를 persist합니다. |
thread/inject_items | Raw Responses API item을 loaded thread의 model-visible history에 추가합니다. |
thread/list는 cursor, limit, sortKey, modelProviders, sourceKinds, archived, cwd, searchTerm filter를 지원합니다. sourceKinds에는 cli, vscode, exec, appServer, subAgent, subAgentReview, subAgentCompact, subAgentThreadSpawn, subAgentOther, unknown이 포함됩니다.
Turn methods
| Method | 설명 |
|---|---|
turn/start | User input을 thread에 추가하고 Codex generation을 시작합니다. 초기 turn을 응답하고 event를 stream합니다. |
turn/steer | 진행 중인 active turn에 user input을 추가합니다. expectedTurnId가 active turn id와 일치해야 합니다. |
turn/interrupt | 진행 중인 turn cancellation을 요청합니다. 성공 시 {}를 반환하고 turn은 interrupted status로 끝납니다. |
turn/start의 input은 text, image, file, skill, app mention 같은 item list입니다. Per-turn override로 model, effort, personality, cwd, sandbox policy, summary를 지정할 수 있습니다. 이 값은 같은 thread의 이후 turn 기본값이 됩니다. outputSchema는 현재 turn에만 적용됩니다.
Sandbox read access는 readOnly와 workspaceWrite에서 명시할 수 있습니다. 기본은 full access이며, restricted root 목록으로 제한할 수 있습니다.
Skill을 명시적으로 호출하려면 text input에 $skill-name을 포함하고 함께 skill input item을 추가하는 방식을 권장합니다.
Review
review/start는 thread에 대해 Codex reviewer를 실행하고 review item을 stream합니다. Target:
uncommittedChangesbaseBranchcommitcustom
Detached review에는 "delivery": "detached"를 사용합니다. 이 경우 response shape는 같지만 reviewThreadId는 원래 threadId와 다른 새 review thread id입니다.
Command execution
| Method | 설명 |
|---|---|
command/exec | Thread/turn을 만들지 않고 server sandbox 아래 단일 command를 실행합니다. |
command/exec/write | 실행 중인 command/exec session에 stdin byte를 쓰거나 stdin을 닫습니다. |
command/exec/resize | PTY-backed command/exec session 크기를 조정합니다. |
command/exec/terminate | 실행 중인 command/exec session을 중지합니다. |
command/exec/outputDelta | Streaming session의 base64-encoded stdout/stderr chunk notification입니다. |
command/exec는 빈 command array를 거부합니다. sandboxPolicy는 turn/start와 같은 shape를 받습니다. tty: true는 PTY-backed session을 사용하며, streamStdoutStderr: true는 실행 중 outputDelta notification을 받게 합니다.
Models and experimental features
| Method | 설명 |
|---|---|
model/list | 사용 가능한 model과 capability를 나열합니다. includeHidden: true로 hidden entry도 포함할 수 있습니다. |
modelProvider/capabilities/read | Model/provider 조합의 capability bound를 읽습니다. Experimental입니다. |
experimentalFeature/list | Feature flag를 lifecycle stage metadata와 cursor pagination으로 나열합니다. |
experimentalFeature/enablement/set | apps, plugins 같은 supported feature key의 in-memory runtime enablement를 patch합니다. |
collaborationMode/list | Collaboration mode preset을 나열합니다. Experimental입니다. |
model/list result에는 supportedReasoningEfforts, defaultReasoningEffort, upgrade, upgradeInfo, hidden, inputModalities, supportsPersonality, isDefault 같은 field가 포함될 수 있습니다.
Configuration and admin requirements
| Method | 설명 |
|---|---|
config/read | 구성 layering을 해석한 뒤 disk의 effective configuration을 가져옵니다. |
config/value/write | User config.toml에 단일 key/value를 씁니다. |
config/batchWrite | User config.toml에 configuration edit를 atomically 적용합니다. |
configRequirements/read | requirements.toml과 MDM에서 로드한 effective admin requirements를 가져옵니다. |
config/mcpServer/reload | Disk에서 MCP server 구성을 reload하고 loaded thread refresh를 queue합니다. |
Windows sandbox setup
windowsSandbox/setupStart는 elevated 또는 unelevated mode의 Windows sandbox setup을 시작합니다. 빠르게 반환하고 나중에 windowsSandbox/setupCompleted를 emit합니다.
Filesystem
V2 filesystem API는 absolute path에서 동작합니다.
fs/readFilefs/writeFilefs/createDirectoryfs/getMetadatafs/readDirectoryfs/removefs/copyfs/watchfs/unwatchfs/changed
Client가 file 또는 directory 변경 후 UI state를 invalidate해야 하면 fs/watch를 사용합니다. File watch는 replace 또는 rename으로 전달된 update도 해당 file path의 fs/changed로 emit합니다.
Events
Event notification은 thread lifecycle, turn lifecycle, item에 대해 server가 시작하는 stream입니다. Thread를 시작하거나 resume한 뒤 활성 transport stream에서 다음 notification을 읽습니다.
- Thread:
thread/started,thread/archived,thread/unarchived,thread/closed,thread/status/changed - Turn:
turn/started,turn/completed,turn/failed,turn/interrupted등turn/* - Item:
item/started,item/completed,item/agentMessage/delta등item/* - Approval/tool:
serverRequest/resolved, command output, MCP startup status 등 - Filesystem:
fs/changed - Windows sandbox:
windowsSandbox/setupCompleted
Notification opt-out은 initialize.params.capabilities.optOutNotificationMethods로 설정합니다. Exact match만 지원합니다. 예를 들어 item/agentMessage/delta는 해당 method만 억제합니다.
Item은 user message, assistant message, command execution, file change, tool call, context compaction, review mode marker 등을 나타냅니다. Delta event는 agent message streaming이나 command output 같은 incremental update를 전달합니다.
Errors
JSON-RPC error는 code와 message를 포함합니다. Server overload, initialization 순서 오류, experimental API opt-in 누락, validation failure, permission failure 등이 error로 반환될 수 있습니다. WebSocket ingress가 꽉 차면 code -32001과 retry message를 반환합니다.
Approvals
App-server는 shell command, file change, user input request, dynamic tool call, MCP/app tool call에 대해 approval flow를 표면화할 수 있습니다.
Command execution approval
Command approval request는 sandbox escalation, network access, rule prompt, 위험한 operation 등에 대해 발생할 수 있습니다. Client는 request detail을 사용자에게 보여 주고 allow/deny 또는 session-scoped approval을 응답해야 합니다.
File change approval
File edit 또는 patch가 approval을 요구하면 server는 change summary와 target path를 포함한 request를 보냅니다. Client는 승인 전 diff를 표시하는 것이 좋습니다.
tool/requestUserInput
Experimental tool call이 사용자에게 1-3개의 짧은 질문을 표시하도록 요청할 수 있습니다. Question은 2-3개 mutually exclusive option을 가질 수 있으며 free-form Other option을 허용할 수 있습니다.
Dynamic tool call
Experimental dynamic tool은 thread/start 또는 turn/start에서 전달할 수 있습니다. Experimental API capability가 필요하며, persisted thread metadata에 저장되어 resume 시 복원될 수 있습니다.
MCP tool-call approval
App connector와 MCP tool call은 destructive 또는 side-effect hint가 있으면 approval을 요구할 수 있습니다. Client는 tool name, app/server identity, argument summary를 보여 주고 승인 결과를 반환합니다.
Skills
| Method | 설명 |
|---|---|
skills/list | 하나 이상의 cwd 값에 대해 skill 목록을 가져옵니다. forceReload와 optional extra user root를 지원합니다. |
skills/changed | Watch 중인 local skill file이 바뀌면 emit되는 notification입니다. |
skills/config/write | Path 기준으로 skill을 enable/disable합니다. |
Skill invocation은 text input에 $skill-name marker를 넣고 skill input item을 함께 보내는 방식을 권장합니다. skill item을 생략하면 model이 marker를 parse해 skill을 찾으려 하며 latency가 늘 수 있습니다.
Apps와 connectors
| Method | 설명 |
|---|---|
app/list | 사용 가능한 app connector를 pagination, accessibility, enabled metadata와 함께 나열합니다. |
plugin/list | Plugin marketplace와 plugin state를 나열합니다. Install/auth policy, load error, featured plugin, source metadata를 포함합니다. |
plugin/read | Marketplace path 또는 remote marketplace name과 plugin name으로 plugin 하나를 읽습니다. |
plugin/install | Marketplace에서 plugin을 설치합니다. |
plugin/uninstall | 설치된 plugin을 제거합니다. |
marketplace/add | Remote plugin marketplace를 추가하고 사용자 marketplace config에 저장합니다. |
marketplace/upgrade | 구성된 Git marketplace 하나 또는 전체를 refresh합니다. |
externalAgentConfig/detect | Migration 가능한 external-agent artifact를 detect합니다. |
externalAgentConfig/import | 선택한 external-agent migration item을 적용합니다. |
App invocation은 text input에 $app-slug를 넣고 app://id path를 가진 mention input item을 함께 보내는 방식을 권장합니다.
External agent config import는 config, skills, AGENTS.md, plugins, MCP server config, subagents, hooks, commands, sessions 같은 item type을 지원합니다. Plugin import가 완료되면 externalAgentConfig/import/completed notification이 emit될 수 있습니다.
MCP server operations
| Method | 설명 |
|---|---|
mcpServer/oauth/login | 구성된 MCP server의 OAuth login을 시작합니다. Authorization URL을 반환하고 완료 시 notification을 emit합니다. |
mcpServerStatus/list | MCP server, tool, resource, auth status를 cursor/limit pagination으로 나열합니다. |
mcpServer/resource/read | Initialized MCP server를 통해 단일 MCP resource를 읽습니다. |
mcpServer/tool/call | Thread에 구성된 MCP server의 tool을 호출합니다. |
mcpServer/startupStatus/updated | Loaded thread에서 MCP server startup status가 바뀔 때 emit됩니다. |
mcpServerStatus/list의 detail은 full 또는 toolsAndAuthOnly를 사용할 수 있습니다.
Auth endpoints
App-server는 client가 현재 authentication state를 확인하고 API key 또는 ChatGPT auth로 로그인하거나 logout하도록 RPC를 제공합니다.
Authentication mode
- API key auth: Platform API key를 저장하고 Codex request에 사용합니다.
- ChatGPT browser flow: Browser-based OAuth로 ChatGPT account에 로그인합니다.
- ChatGPT device-code flow: Browser를 열 수 없는 환경에서 device code로 로그인합니다.
- Externally managed ChatGPT tokens: Client가
chatgptAuthTokens를 제공해 token lifecycle을 직접 관리합니다.
API overview
| Method | 설명 |
|---|---|
account/status | 현재 auth state를 확인합니다. |
account/login/apiKey | API key로 로그인합니다. |
account/login/chatgpt/start | Browser flow ChatGPT login을 시작하고 auth URL을 반환합니다. |
account/login/chatgpt/device/start | Device-code flow ChatGPT login을 시작합니다. |
account/login/chatgpt/token | Externally managed ChatGPT token을 설정합니다. |
account/login/cancel | 진행 중인 ChatGPT login을 취소합니다. |
account/logout | 현재 account에서 logout합니다. |
account/rateLimits | ChatGPT rate limit 정보를 가져옵니다. |
account/limit/notifyWorkspaceOwner | Limit 관련 workspace owner notification을 요청합니다. |
ChatGPT login flow는 loginId로 추적됩니다. 완료되면 account/login/completed notification이 emit되며, 성공 여부와 error가 포함됩니다. Device-code flow도 같은 completion notification을 사용합니다.