한국어

Codex App Server

Codex App Server

Codex app-server는 Codex가 풍부한 기능을 갖춘 클라이언트(예: Codex VS Code 확장 프로그램)를 구동하는 데 사용하는 인터페이스입니다. 인증, 대화 기록, 승인, 스트리밍되는 에이전트 이벤트 등 자체 제품에 긴밀하게 통합하려는 경우 사용하세요. app-server 구현은 Codex GitHub 리포지토리(openai/codex/codex-rs/app-server)에 오픈 소스로 공개되어 있습니다. 오픈 소스 Codex 구성 요소의 전체 목록은 오픈 소스 페이지에서 확인하세요.

CLI 터미널 UI 연결

원격 터미널 UI 모드를 사용하면 한 머신에서 app-server를 실행하고 다른 머신에서 Codex CLI 터미널 인터페이스를 연결할 수 있습니다. WebSocket 리스너를 시작합니다.

codex app-server --listen ws://127.0.0.1:4500

그런 다음 터미널 UI를 연결합니다.

codex --remote ws://127.0.0.1:4500

로컬이 아닌 연결에서는 WebSocket 인증을 구성하고 연결을 TLS 뒤에 배치하세요. 베어러 토큰은 환경 변수에 저장하고 토큰을 명령줄에 직접 입력하는 대신 해당 변수 이름을 전달하세요.

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 엔드포인트를 허용합니다. 일반 WebSocket은 localhost 또는 SSH 포트 포워딩 연결에만 사용하세요.

원격 Code Mode 호스트 연결

기본적으로 app-server는 로컬 Code Mode 호스트를 시작합니다. 대신 원격 호스트를 사용하려면 보안 WebSocket URL을 전달하세요.

codex app-server --code-mode-host wss://code-mode.example.com/host

--code-mode-host는 app-server에서 Code Mode 호스트로 나가는 연결을 제어합니다. 클라이언트가 app-server에 연결하는 방식을 제어하는 --listen에는 영향을 주지 않습니다. 동일한 app-server 프로세스의 모든 스레드는 선택된 Code Mode 호스트 연결을 공유합니다.

원격 호스트에는 wss://을 사용하세요. ws://은 localhost 또는 SSH 포워딩 연결에만 사용하세요. app-server 명령과 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): 표준 HTTP Upgrade 핸드셰이크를 사용하여 Codex의 기본 app-server 제어 소켓 또는 사용자 지정 Unix 소켓 경로를 통한 WebSocket 연결.
  • off(--listen off): 로컬 전송 방식을 노출하지 않음.

--listen ws://IP:PORT로 실행하면 동일한 리스너가 기본적인 HTTP 상태 프로브도 제공합니다.

  • 리스너가 새 연결을 수락할 수 있게 되면 GET /readyz200 OK을 반환합니다.
  • 요청에 Origin 헤더가 없으면 GET /healthz200 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

서명된 베어러 토큰의 경우 --ws-issuer, --ws-audience--ws-max-clock-skew-seconds도 설정할 수 있습니다. 클라이언트는 WebSocket 핸드셰이크 중에 자격 증명을 Authorization: Bearer <token>로 제시하며, app-server는 JSON-RPC initialize 전에 인증을 적용합니다.

명령줄에 원시 베어러 토큰을 전달하는 대신 --ws-token-file을 사용하는 것이 좋습니다. 클라이언트가 원시 고엔트로피 토큰을 별도의 로컬 비밀 저장소에 보관하는 경우에만 --ws-token-sha256을 사용하세요. 해시는 검증자일 뿐이며 클라이언트에는 여전히 원본 토큰이 필요합니다.

WebSocket 모드에서 app-server는 크기가 제한된 큐를 사용합니다. 요청 수신 큐가 가득 차면 서버는 JSON-RPC 오류 코드 -32001과 메시지 "Server overloaded; retry later."로 새 요청을 거부합니다. 클라이언트는 지수적으로 증가하는 지연과 지터를 적용해 재시도해야 합니다.

메시지 스키마

요청에는 method, paramsid가 포함됩니다.

{ "method": "thread/start", "id": 10, "params": { "model": "gpt-5.6-terra" } }

응답은 result 또는 error와 함께 id을 그대로 반환합니다.

{ "id": 10, "result": { "thread": { "id": "thr_123" } } }
{ "id": 10, "error": { "code": 123, "message": "Something went wrong" } }

알림은 id을 생략하고 methodparams만 사용합니다.

{ "method": "turn/started", "params": { "turn": { "id": "turn_456" } } }

CLI에서 TypeScript 스키마 또는 JSON Schema 번들을 생성할 수 있습니다. 각 출력은 실행한 Codex 버전에만 해당하므로 생성된 아티팩트가 해당 버전과 정확히 일치합니다.

codex app-server generate-ts --out ./schemas
codex app-server generate-json-schema --out ./schemas

시작하기

  1. codex app-server(기본 stdio 전송), codex app-server --listen ws://127.0.0.1:4500(TCP WebSocket) 또는 codex app-server --listen unix://(기본 Unix 소켓)로 서버를 시작합니다.
  2. 선택한 전송 방식으로 클라이언트를 연결한 다음 initialize를 보내고 이어서 initialized 알림을 보냅니다.
  3. 스레드와 턴을 시작한 다음 활성 전송 스트림에서 알림을 계속 읽습니다.

예시(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.6-terra" } });

핵심 기본 요소

  • 스레드: 사용자와 Codex 에이전트 간의 대화입니다. 스레드에는 턴이 포함됩니다.
  • : 단일 사용자 요청과 그에 이어지는 에이전트 작업입니다. 턴에는 항목이 포함되며 증분 업데이트가 스트리밍됩니다.
  • 항목: 입력 또는 출력의 단위입니다(사용자 메시지, 에이전트 메시지, 명령 실행, 파일 변경, 도구 호출 등).

스레드 API를 사용해 대화를 생성하거나 나열하거나 보관하세요. 턴 API로 대화를 진행하고 턴 알림을 통해 진행 상황을 스트리밍하세요.

수명 주기 개요

  • 연결마다 한 번 초기화: 전송 연결을 연 직후 클라이언트 메타데이터와 함께 initialize 요청을 보낸 다음 initialized을 전송합니다. 서버는 이 핸드셰이크 전에 해당 연결에서 수신한 모든 요청을 거부합니다.
  • 스레드 시작(또는 재개): 새 대화에는 thread/start을, 기존 대화를 계속하려면 thread/resume을, 기록을 새 스레드 id로 분기하려면 thread/fork을 호출합니다.
  • 턴 시작: 대상 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가 반환됩니다.

서버는 업스트림 서비스에 제시할 사용자 에이전트 문자열과 런타임 대상을 설명하는 platformFamilyplatformOs 값을 반환합니다. 통합을 식별하도록 clientInfo을 설정하세요.

initialize.params.capabilities은 다음 클라이언트 기능도 지원합니다.

  • optOutNotificationMethods - 이 연결에서 억제할 정확한 알림 메서드 이름입니다. 정확히 일치해야 하며(와일드카드 또는 접두사 불가), 알 수 없는 이름은 허용되지만 무시됩니다.
  • requestAttestation - 서버가 시작하는 attestation/generate 요청을 사용하도록 설정합니다. 업스트림 증명을 제공하는 데스크톱 호스트는 불투명한 { "token": "..." } 값으로 응답합니다.
  • mcpServerOpenaiFormElicitation - 다운스트림 MCP 서버가 OpenAI 확장 형식의 mcpServer/elicitation/request 변형을 보낼 수 있도록 허용합니다.

중요: OpenAI Compliance Logs Platform에서 클라이언트를 식별하려면 clientInfo.name을 사용하세요. 엔터프라이즈용으로 사용할 새로운 Codex 통합을 개발하고 있다면 OpenAI에 문의하여 알려진 클라이언트 목록에 추가하세요. 자세한 내용은 Codex 로그 참조를 확인하세요.

예시(Codex VS Code 확장 프로그램에서 가져옴):

{
  "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 사용 설정

일부 app-server 메서드와 필드는 의도적으로 experimentalApi 기능 뒤에 제한되어 있습니다.

  • 안정적인 API 범위만 사용하려면 capabilities을 생략하거나 experimentalApifalse으로 설정하세요. 그러면 서버가 실험적 메서드와 필드를 거부합니다.
  • 실험적 메서드와 필드를 활성화하려면 capabilities.experimentalApitrue로 설정하세요.
{
  "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 개요

  • thread/start - 새 스레드를 생성합니다. thread/started를 내보내고 해당 스레드의 턴/항목 이벤트를 자동으로 구독합니다.
  • thread/resume - 나중의 turn/start 호출이 이어서 추가되도록 기존 스레드를 id로 다시 엽니다.
  • thread/fork - 저장된 기록을 복사하여 스레드를 새 스레드 id로 포크합니다. 해당 턴까지의 기록만 복사하고 이후 턴은 제외하려면 lastTurnId를 전달하고, 메모리 내 포크를 생성하려면 ephemeral: true를 전달합니다. 새 스레드에 대해 thread/started를 내보냅니다. 반환된 스레드에는 사용 가능한 경우 forkedFromId가 포함됩니다.
  • thread/read - 저장된 스레드를 재개하지 않고 id로 읽습니다. 전체 턴 기록을 반환하려면 includeTurns를 설정합니다. 반환된 thread 객체에는 런타임 status가 포함됩니다.
  • thread/list - 저장된 스레드 로그를 페이지 단위로 조회합니다. 커서 기반 페이지 매김과 함께 modelProviders, sourceKinds, archived, isPinned, cwd, useStateDbOnly, searchTerm 및 실험적 parentThreadId 또는 ancestorThreadId 필터를 지원합니다. 반환된 thread 객체에는 런타임 status가 포함됩니다.
  • thread/turns/list - 실험적 기능입니다. 저장된 스레드를 재개하지 않고 턴 기록을 페이지 단위로 조회합니다. itemsView는 턴 항목을 생략할지, 요약할지, 완전히 불러올지를 제어합니다.
  • thread/items/list - 실험적 기능입니다. 영구 저장된 스레드 항목을 페이지 단위로 조회하며, 선택적으로 하나의 turnId로 제한할 수 있습니다. 활성 스레드 저장소가 항목 페이지 매김을 지원해야 합니다.
  • thread/loaded/list - 현재 메모리에 로드된 스레드 id를 나열합니다.
  • thread/name/set - 로드된 스레드 또는 영구 저장된 롤아웃의 사용자 표시용 스레드 이름을 설정하거나 업데이트합니다. thread/name/updated을 내보냅니다.
  • thread/goal/set - 스레드의 목표를 설정합니다. thread/goal/updated을 내보냅니다.
  • thread/goal/get - 스레드의 현재 목표를 읽습니다.
  • thread/goal/clear - 스레드의 목표를 지웁니다. thread/goal/cleared을 내보냅니다.
  • thread/metadata/update - 영구 저장된 gitInfoisPinned을 포함하여 SQLite 기반으로 저장된 스레드 메타데이터를 패치합니다.
  • thread/archive - 스레드의 로그 파일을 보관 디렉터리로 이동하고, 아직 보관되지 않은 생성된 하위 스레드 로그도 보관하려고 시도합니다. 성공하면 {}을 반환하고 보관된 각 스레드에 대해 thread/archived을 내보냅니다.
  • thread/delete - 영구 저장된 활성 또는 보관 스레드와 생성된 모든 하위 스레드를 영구적으로 삭제합니다. 성공하면 {}을 반환하고 삭제된 각 스레드에 대해 thread/deleted을 내보냅니다.
  • thread/unsubscribe - 이 연결의 스레드 턴/항목 이벤트 구독을 취소합니다. 마지막 구독자였다면 서버는 구독자가 없는 비활성 유예 기간이 지난 후 스레드를 언로드하고 thread/closed을 내보냅니다.
  • thread/unarchive - 보관된 스레드 롤아웃을 활성 세션 디렉터리로 복원합니다. 복원된 thread을 반환하고 thread/unarchived을 내보냅니다.
  • thread/status/changed - 로드된 스레드의 런타임 status가 변경될 때 내보내는 알림입니다.
  • thread/compact/start - 스레드의 대화 기록 압축을 트리거합니다. 즉시 {}을 반환하며, 진행 상황은 turn/*item/* 알림을 통해 스트리밍됩니다.
  • thread/shellCommand - 스레드에서 사용자가 시작한 셸 명령을 실행합니다. 이 명령은 샌드박스 외부에서 전체 접근 권한으로 실행되며 스레드의 샌드박스 정책을 상속하지 않습니다.
  • thread/backgroundTerminals/clean - 스레드에서 실행 중인 모든 백그라운드 터미널을 중지합니다(실험적 기능, capabilities.experimentalApi 필요).
  • thread/backgroundTerminals/list - 로드된 스레드에서 실행 중인 백그라운드 터미널을 나열합니다(실험적 기능, capabilities.experimentalApi 필요).
  • thread/backgroundTerminals/terminate - app-server processId를 기준으로 실행 중인 백그라운드 터미널 하나를 종료합니다(실험적 기능, 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 리뷰어를 시작합니다. enteredReviewModeexitedReviewMode 항목을 내보냅니다.
  • command/exec - 스레드/턴을 시작하지 않고 서버 샌드박스에서 단일 명령을 실행합니다.
  • command/exec/write - 실행 중인 command/exec 세션에 stdin 바이트를 쓰거나 stdin를 닫습니다.
  • command/exec/resize - 실행 중인 PTY 기반 command/exec 세션의 크기를 조정합니다.
  • command/exec/terminate - 실행 중인 command/exec 세션을 중지합니다.
  • command/exec/outputDelta(알림) - 스트리밍 command/exec 세션에서 base64로 인코딩된 stdout/stderr 청크에 대해 내보냅니다.
  • process/spawn - Codex 샌드박스 외부에서 명시적 프로세스 세션을 시작합니다(실험적 기능, capabilities.experimentalApi 필요).
  • process/writeStdin - 실행 중인 process/spawn 세션에 stdin 바이트를 쓰거나 stdin을 닫습니다(실험적 기능).
  • process/resizePty - 실행 중인 PTY 기반 프로세스 세션의 크기를 조정합니다(실험적 기능).
  • process/kill - 실행 중인 프로세스 세션을 종료합니다(실험적 기능).
  • process/outputDeltaprocess/exited(알림) - 스트리밍 프로세스 출력 및 프로세스 종료 상태에 대해 내보냅니다(실험적 기능).
  • model/list - 추론 강도 옵션, 선택적 upgradeinputModalities와 함께 사용 가능한 모델을 나열합니다(hidden: true인 항목을 포함하려면 includeHidden: true 설정).
  • modelProvider/capabilities/read - 모델/제공자 조합의 제공자 기능 한도를 읽습니다.
  • experimentalFeature/list - 수명 주기 단계 메타데이터 및 커서 페이지 매김과 함께 기능 플래그를 나열합니다.
  • experimentalFeature/enablement/set - appsplugins 같은 지원되는 기능 키의 메모리 내 런타임 설정을 패치합니다.
  • environment/info - 실험적 기능입니다. 구성된 실행 환경에 연결하고 해당 셸과 기본 작업 디렉터리를 반환합니다.
  • permissionProfile/list - 베타 권한 프로필과 유효 요구 사항의 허용 여부를 커서 페이지 매김과 함께 나열합니다.
  • collaborationMode/list - 협업 모드 프리셋을 나열합니다(실험적 기능, 페이지 매김 없음).
  • skills/list - 하나 이상의 cwd 값에 대한 스킬을 나열합니다(forceReload 및 선택적 perCwdExtraUserRoots 지원).
  • skills/extraRoots/set - 독립 실행형 스킬을 검색하는 데 사용되는 프로세스 수준의 추가 루트를 영구 저장하지 않고 교체합니다.
  • skills/changed(알림) - 감시 중인 로컬 스킬 파일이 변경될 때 내보냅니다.
  • hooks/list - 하나 이상의 cwd 값에 대해 검색된 수명 주기 훅을 나열합니다.
  • marketplace/add - 원격 플러그인 마켓플레이스를 추가하고 사용자의 마켓플레이스 구성에 영구 저장합니다.
  • marketplace/remove - 구성된 마켓플레이스와 설치된 마켓플레이스 루트가 있으면 이를 제거합니다.
  • marketplace/upgrade - 구성된 Git 마켓플레이스를 새로 고치거나, 마켓플레이스 이름을 생략하면 구성된 모든 Git 마켓플레이스를 새로 고칩니다.
  • plugin/list - 개발 중인 기능입니다. 설치/인증 정책 메타데이터, 마켓플레이스 로드 오류, 추천 플러그인 id 및 로컬, Git, 패키지 레지스트리 또는 원격 플러그인 소스 메타데이터를 포함하여 검색된 플러그인 마켓플레이스와 플러그인 상태를 나열합니다. 요약에는 원격 version, 로컬 localVersion, 구조화된 라이트/다크 아이콘 및 현재 원격 행에서 null, WORKSPACE_SETTING 또는 IMPLICIT_CANONICAL_APP일 수 있는 installPolicySource이 포함될 수 있습니다. 아직 프로덕션 클라이언트에서 이 메서드를 호출하지 마세요.
  • plugin/read - 개발 중인 기능입니다. 마켓플레이스 경로 또는 원격 마켓플레이스 이름과 플러그인 이름으로 하나의 플러그인을 읽으며, 번들 스킬, 앱, MCP 서버 이름 및 원격 카탈로그에서 제공하는 경우 원격 플러그인 shareUrl을 포함합니다. 아직 프로덕션 클라이언트에서 이 메서드를 호출하지 마세요.
  • plugin/install - 개발 중인 기능입니다. 마켓플레이스 경로 또는 원격 마켓플레이스 이름에서 플러그인을 설치합니다. 아직 프로덕션 클라이언트에서 이 메서드를 호출하지 마세요.
  • plugin/uninstall - 개발 중인 기능입니다. 설치된 플러그인을 제거합니다. 아직 프로덕션 클라이언트에서 이 메서드를 호출하지 마세요.
  • plugin/skill/read - 원격 마켓플레이스, 플러그인 id 및 스킬 이름으로 원격 플러그인 스킬 Markdown을 필요할 때 읽습니다.
  • app/installed - 각 앱의 유효한 활성화 및 호출 가능 상태를 포함하여 설치된 앱의 런타임 상태를 읽습니다.
  • app/list - 사용 가능 여부/활성화 메타데이터 및 페이지 매김과 함께 사용 가능한 앱(커넥터)을 나열합니다.
  • app/read - 특정 앱 id의 메타데이터와 선택적인 표시 전용 도구 요약을 가져옵니다.
  • skills/config/write - 경로를 기준으로 스킬을 활성화하거나 비활성화합니다.
  • mcpServer/oauth/login - 구성된 MCP 서버의 OAuth 로그인을 시작합니다. 인증 URL을 반환하고 완료 시 mcpServer/oauthLogin/completed을 내보냅니다.
  • tool/requestUserInput - 도구 호출을 위해 사용자에게 1~3개의 짧은 질문을 표시합니다(실험적 기능). 질문은 자유 형식 옵션에 isOther을 설정할 수 있습니다.
  • mcpServer/elicitation/request(서버 요청) - MCP 서버가 요청한 구조화된 양식 입력 또는 URL 흐름 확인을 클라이언트에 요청합니다.
  • item/permissions/requestApproval(서버 요청) - 기본 제공 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(알림) - 로드된 스레드에 대해 구성된 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/progressexternalAgentConfig/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/unwatchfs/changed(알림) - app-server v2 파일 시스템 API를 통해 절대 파일 시스템 경로를 대상으로 작업합니다.

플러그인 요약에는 source 유니온이 포함됩니다. 로컬 플러그인은 { "type": "local", "path": ... }을, Git 기반 마켓플레이스 항목은 { "type": "git", "url": ..., "path": ..., "refName": ..., "sha": ... }을, 패키지 레지스트리 항목은 { "type": "npm", "package": ..., "version": ..., "registry": ... }을, 원격 카탈로그 항목은 { "type": "remote" }을 반환합니다. 원격 전용 카탈로그 항목에서 PluginMarketplaceEntry.pathnull일 수 있습니다. 이러한 플러그인을 읽거나 설치할 때는 marketplacePath 대신 remoteMarketplaceName을 전달하세요.

모델

모델 나열(model/list)

모델 또는 성격 선택기를 렌더링하기 전에 model/list을 호출하여 사용 가능한 모델과 기능을 확인하세요.

{ "method": "model/list", "id": 6, "params": { "limit": 20, "includeHidden": false } }
{ "id": 6, "result": {
  "data": [{
    "id": "gpt-5.6-sol",
    "model": "gpt-5.6-sol",
    "displayName": "GPT-5.6-Sol",
    "hidden": false,
    "defaultReasoningEffort": "low",
    "supportedReasoningEfforts": [{
      "reasoningEffort": "low",
      "description": "Fast responses with lighter reasoning"
    }],
    "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)

이 엔드포인트를 사용하여 메타데이터 및 수명 주기 단계와 함께 기능 플래그를 확인하세요.

{ "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
} }

stagebeta, underDevelopment, stable, deprecated 또는 removed일 수 있습니다. 베타가 아닌 플래그에서는 displayName, descriptionannouncementnull일 수 있습니다.

실행 환경 검사(실험적)

작업을 시작하기 전에 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"
} }

cwdnull일 수 있습니다. 값이 있으면 환경의 기본 경로 구문을 사용하는 정규 file: URI입니다. 알 수 없는 환경 ID와 연결 또는 프로토콜 실패는 요청 오류를 반환합니다.

스레드

  • thread/read은 저장된 스레드를 구독하지 않고 읽습니다. 턴을 포함하려면 includeTurns을 설정하세요.
  • thread/turns/list은 실험적이며 저장된 스레드를 재개하지 않고 턴 기록을 페이지 단위로 탐색합니다. 턴 항목을 생략할지, 요약할지, 완전히 불러올지는 itemsView으로 선택하세요.
  • thread/items/list은 실험적이며 유지된 스레드 항목을 페이지 단위로 탐색하고 선택적으로 하나의 턴으로 제한할 수 있습니다.
  • thread/list는 커서 페이지네이션과 modelProviders, sourceKinds, archived, isPinned, cwd, useStateDbOnly, searchTerm 및 실험적 parentThreadId 또는 ancestorThreadId 필터링을 지원합니다.
  • thread/loaded/list는 현재 메모리에 있는 스레드 ID를 반환합니다.
  • thread/archive은 스레드의 유지된 JSONL 로그를 보관 디렉터리로 이동하고 아직 보관되지 않은 생성된 하위 스레드 로그도 보관하려고 시도합니다.
  • thread/delete는 유지된 활성 또는 보관 스레드와 생성된 하위 스레드를 영구적으로 삭제합니다.
  • thread/metadata/update는 유지된 gitInfoisPinned를 비롯한 저장 스레드 메타데이터를 패치합니다.
  • thread/unsubscribe은 현재 연결의 로드된 스레드 구독을 취소하며 비활성 유예 기간 후 thread/closed을 트리거할 수 있습니다.
  • thread/unarchive은 보관된 스레드 롤아웃을 활성 세션 디렉터리로 복원합니다.
  • thread/compact/start은 압축을 시작하고 {}을 즉시 반환합니다.
  • thread/rollback은 지원 중단되었습니다. 메모리 내 컨텍스트에서 마지막 N개 턴을 제거하고 스레드의 유지된 JSONL 로그에 롤백 마커를 기록합니다.
  • thread/inject_items은 사용자 턴을 시작하지 않고 원시 Responses API 항목을 로드된 스레드에서 모델에 표시되는 기록에 추가합니다.

스레드 시작 또는 재개

새 Codex 대화가 필요하면 새로운 스레드를 시작하세요.

{ "method": "thread/start", "id": 10, "params": {
  "model": "gpt-5.6-terra",
  "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/resumethread/fork은 로드된 지침 파일 경로의 배열인 instructionSources을 반환합니다. 원격 환경의 경로를 포함하여 각 경로는 소스 환경의 기본 절대 경로 구문을 사용합니다.

실험적 클라이언트는 thread/starthistoryMode"legacy" (기본값) 또는 "paginated"으로 설정할 수 있습니다. 페이지네이션된 스레드 생성은 아직 지원되지 않으며 JSON-RPC 오류 -32601를 반환합니다. app-server는 기존 페이지네이션 레코드의 요약을 나열하고 읽을 수 있지만, 페이지네이션된 기록이 지원될 때까지 전체 기록 읽기, 턴 페이지네이션 및 재개는 안전을 위해 실패합니다.

capabilities.experimentalApi을 사용 설정한 베타 클라이언트는 기존 sandbox 필드 대신 permissions에 명명된 권한 프로필 id를 전달할 수 있습니다. permissionssandbox을 함께 보내지 마세요. 프로젝트 cwd과 함께 permissionProfile/list을 사용하여 사용 가능한 프로필 및 관리형 요구 사항에서 각 프로필을 허용하는지 확인하세요.

thread.sessionId는 현재 라이브 세션 트리 루트를 식별합니다. 루트 스레드는 자체 스레드 id를 세션 id로 사용하고, 포크된 스레드는 분기된 루트의 세션 id를 유지합니다. 클라이언트는 스레드 id에서 세션 id를 유도하지 말고 thread.sessionId에서 읽어야 합니다.

저장된 세션을 계속하려면 이전에 기록한 thread.id와 함께 thread/resume을 호출하세요. 응답 형태는 thread/start과 같습니다. personality처럼 thread/start에서 지원되는 것과 동일한 구성 재정의도 전달할 수 있습니다.

{ "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/startthread/resume가 실패합니다.

thread/startdynamicTools은 실험적 필드입니다(capabilities.experimentalApi = true 필요). Codex는 이러한 동적 도구를 스레드 롤아웃 메타데이터에 유지하며, 새 동적 도구를 제공하지 않으면 thread/resume 시 복원합니다.

롤아웃에 기록된 모델과 다른 모델로 재개하면 Codex가 경고를 전송하고 다음 턴에 일회성 모델 전환 지침을 적용합니다.

스레드 목표 관리

thread/goal/set, thread/goal/getthread/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을 거부합니다. 소스 스레드가 턴을 진행 중일 때 이 필드를 생략하면 포크는 표시되지 않은 부분 턴을 유지하는 대신 중단 마커를 기록합니다.

저장된 스레드 목록에 추가하지 않고 메모리 내 포크를 만들려면 ephemeral: true을 전달하세요.

{
  "method": "thread/fork",
  "id": 13,
  "params": {
    "threadId": "thr_123",
    "ephemeral": true
  }
}
{
  "id": 13,
  "result": {
    "thread": {
      "id": "thr_789",
      "sessionId": "thr_789",
      "forkedFromId": "thr_123",
      "ephemeral": true
    }
  }
}

페이지네이션된 스레드의 임시 포크에는 excludeTurns: true도 필요합니다. 이 필드는 실험적이며 capabilities.experimentalApi = true이 필요합니다.

사용자 표시 스레드 제목이 설정되면 app-server는 thread/list, thread/read, thread/resume, thread/unarchivethread/rollback 응답에서 thread.name을 채웁니다. 나중에 제목이 설정될 때까지 thread/startthread/forkname을 생략하거나 null을 반환할 수 있습니다.

저장된 스레드 읽기(재개하지 않음)

스레드를 재개하거나 이벤트를 구독하지 않고 저장된 스레드 데이터만 가져오려면 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을 전송하지 않습니다.

스레드 턴 나열

thread/turns/list은 실험적입니다. 저장된 스레드를 재개하지 않고 턴 기록을 페이지 단위로 탐색하는 데 사용하세요. 결과는 기본적으로 최신순이므로 클라이언트는 nextCursor을 사용해 이전 턴을 가져올 수 있습니다. 응답에는 backwardsCursor도 포함됩니다. 이전 페이지의 첫 항목보다 새로운 턴을 가져오려면 이를 sortDirection: "asc"과 함께 cursor로 전달하세요.

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를 전달하고, 스레드 전체에서 항목을 탐색하려면 생략하세요. 활성 스레드 저장소가 항목 페이지네이션을 지원해야 합니다. 지원하지 않으면 서버가 지원되지 않는 메서드 오류를 반환합니다.

스레드 나열(페이지네이션 및 필터 포함)

thread/list를 사용하면 기록 UI를 렌더링할 수 있습니다. 결과는 기본적으로 createdAt 기준 최신순입니다. 필터는 페이지네이션 전에 적용됩니다. 다음 항목을 원하는 조합으로 전달하세요.

  • cursor - 이전 응답에서 받은 불투명 문자열입니다. 첫 페이지에서는 생략합니다.
  • limit - 설정하지 않으면 서버가 적절한 페이지 크기를 기본값으로 사용합니다.
  • sortKey - created_at(기본값), updated_at 또는 recency_at.
  • sortDirection - desc(기본값) 또는 asc.
  • modelProviders - 결과를 특정 공급자로 제한합니다. 설정하지 않거나 null 또는 빈 배열이면 모든 공급자가 포함됩니다.
  • sourceKinds - 결과를 특정 스레드 소스로 제한합니다. 생략하거나 []이면 서버는 기본적으로 대화형 소스인 clivscode만 사용합니다.
  • archived - true이면 보관된 스레드만 나열합니다. false이거나 생략하면 보관되지 않은 스레드를 나열합니다(기본값).
  • isPinned - 제공하면 유지된 고정 상태가 일치하는 스레드만 반환합니다. 고정된 스레드와 고정되지 않은 스레드를 모두 반환하려면 생략하세요.
  • cwd - 결과를 세션의 현재 작업 디렉터리가 이 경로 또는 배열 내 경로 중 하나와 정확히 일치하는 스레드로 제한합니다. 상대 경로는 app-server 프로세스 작업 디렉터리를 기준으로 해석됩니다.
  • useStateDbOnly - true이면 메타데이터를 복구하기 위해 JSONL 스레드 로그를 검사하지 않고 상태 데이터베이스 결과를 반환합니다. 기본 검사 및 복구 동작을 사용하려면 생략하거나 false을 전달하세요.
  • searchTerm - 추출된 제목에 이 대소문자 구분 텍스트 조각이 포함된 스레드로 결과를 제한합니다.
  • parentThreadId - 지정된 상위 스레드의 직계 하위 스레드로 결과를 제한합니다. 이 필터는 실험적이며 capabilities.experimentalApi = true이 필요합니다.
  • ancestorThreadId - 지정된 스레드에서 생성된 모든 깊이의 하위 스레드로 결과를 제한합니다. 이 필터는 실험적이며 capabilities.experimentalApi = true이 필요합니다. parentThreadId와 함께 사용하지 마세요.

sourceKinds는 다음 값을 허용합니다.

  • cli
  • vscode
  • exec
  • appServer
  • subAgent
  • subAgentReview
  • subAgentCompact
  • subAgentThreadSpawn
  • subAgentOther
  • unknown

예시:

{ "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, "isPinned": true, "modelProvider": "openai", "createdAt": 1730831111, "updatedAt": 1730831111, "name": "TUI prototype", "status": { "type": "notLoaded" } },
    { "id": "thr_b", "preview": "Fix tests", "ephemeral": false, "isPinned": false, "modelProvider": "openai", "createdAt": 1730750000, "updatedAt": 1730750000, "status": { "type": "notLoaded" } }
  ],
  "nextCursor": "opaque-token-or-null"
} }

nextCursornull이면 마지막 페이지에 도달한 것입니다.

저장된 스레드 메타데이터 업데이트

스레드를 재개하지 않고 저장된 스레드 메타데이터를 패치하려면 thread/metadata/update을 사용하세요. 스레드를 고정하거나 고정 해제하려면 isPinned을 설정하고, 유지된 Git 메타데이터를 변경하려면 gitInfo을 업데이트하세요. 생략한 필드는 변경되지 않으며, 명시적 null은 저장된 Git 메타데이터 값을 지웁니다.

{ "method": "thread/metadata/update", "id": 21, "params": {
  "threadId": "thr_123",
  "isPinned": true,
  "gitInfo": { "branch": "feature/sidebar-pr" }
} }
{ "id": 21, "result": {
  "thread": {
    "id": "thr_123",
    "isPinned": true,
    "gitInfo": { "sha": null, "branch": "feature/sidebar-pr", "originUrl": null }
  }
} }

스레드 상태 변경 추적

로드된 스레드의 런타임 상태가 변경될 때마다 thread/status/changed가 전송됩니다. 페이로드에는 threadId 및 새 status가 포함됩니다.

{
  "method": "thread/status/changed",
  "params": {
    "threadId": "thr_123",
    "status": { "type": "active", "activeFlags": ["waitingOnApproval"] }
  }
}

로드된 스레드 나열

thread/loaded/list는 현재 메모리에 로드된 스레드 ID를 반환합니다.

{ "method": "thread/loaded/list", "id": 21 }
{ "id": 21, "result": { "data": ["thr_123", "thr_456"] } }

로드된 스레드 구독 취소

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" } }

스레드 보관

유지된 스레드 로그(디스크에 JSONL 파일로 저장됨)를 보관된 세션 디렉터리로 이동하려면 thread/archive을 사용하세요. 스레드를 보관하면 아직 보관되지 않은 생성된 하위 스레드도 보관하려고 시도합니다.

{ "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" } }

스레드 보관 해제

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" } }

스레드 압축 트리거

thread/compact/start을 사용하면 스레드의 기록을 수동으로 압축할 수 있습니다. 요청은 {}과 함께 즉시 반환됩니다.

App-server는 동일한 threadId에서 표준 turn/*item/* 알림으로 진행 상황을 내보냅니다. 여기에는 contextCompaction 항목 수명 주기(item/starteditem/completed)도 포함됩니다.

{ "method": "thread/compact/start", "id": 25, "params": { "threadId": "thr_b" } }
{ "id": 25, "result": {} }

스레드 셸 명령 실행

스레드에 속하는 사용자 시작 셸 명령에는 thread/shellCommand을 사용합니다. 요청은 {}과 함께 즉시 반환되며, 진행 상황은 표준 turn/*item/* 알림을 통해 스트리밍됩니다.

이 API는 샌드박스 외부에서 전체 액세스 권한으로 실행되며 스레드의 샌드박스 정책을 상속하지 않습니다. 클라이언트는 사용자가 명시적으로 시작한 명령에만 이 API를 노출해야 합니다.

스레드에 이미 활성 턴이 있으면 명령은 해당 턴의 보조 작업으로 실행되고, 형식이 지정된 출력이 턴의 메시지 스트림에 삽입됩니다. 스레드가 유휴 상태이면 app-server가 셸 명령을 위한 독립 실행형 턴을 시작합니다.

실행 시간을 밀리초 단위로 제한하려면 timeoutMs를 설정합니다. 생략하거나 null을 전달하면 기본값인 1시간을 사용합니다. 0은 즉시 시간 초과를 요청하며, 음수 값은 거부됩니다. 시간 초과 설정은 즉시 반환되는 RPC 확인 응답을 지연시키지 않습니다.

{ "method": "thread/shellCommand", "id": 26, "params": { "threadId": "thr_b", "command": "git status --short", "timeoutMs": 10000 } }
{ "id": 26, "result": {} }

백그라운드 터미널 정리

thread/backgroundTerminals/clean을 사용하면 스레드와 연결되어 실행 중인 모든 백그라운드 터미널을 중지할 수 있습니다. 이 메서드는 실험적이며 capabilities.experimentalApi = true이 필요합니다.

{ "method": "thread/backgroundTerminals/clean", "id": 27, "params": { "threadId": "thr_b" } }
{ "id": 27, "result": {} }

thread/backgroundTerminals/list을 사용하면 로드된 스레드에서 실행 중인 백그라운드 터미널을 검사할 수 있습니다. 요청은 표준 cursorlimit 페이지 매김을 지원하며, 반환되는 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 } }

최근 턴 롤백

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" }

턴별로 구성 설정(모델, 노력 수준, 성격, cwd, 샌드박스 정책, 요약)을 재정의할 수 있습니다. 지정한 설정은 같은 스레드의 이후 턴에서 기본값이 됩니다. outputSchema은 현재 턴에만 적용됩니다. sandboxPolicy.type = "externalSandbox"의 경우 networkAccessrestricted 또는 enabled으로 설정하며, workspaceWrite의 경우 networkAccess은 계속 부울 값입니다.

turn/start.collaborationMode에서 settings.developer_instructions: null은 모드 지침을 지우는 것이 아니라 "선택한 모드의 기본 제공 지침 사용"을 의미합니다.

샌드박스 읽기 액세스(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
}

턴 시작

{ "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.6-terra",
  "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 } } }

클라이언트에서 실행한 도구의 출력으로 턴을 시작하려면 비어 있지 않은 name, 선택적 namespace, 그리고 문자열 또는 콘텐츠 항목 배열인 output과 함께 toolOutput을 전달합니다. input을 빈 배열로 설정하세요. 비어 있지 않은 사용자 입력과 toolOutput을 함께 사용할 수 없습니다.

{
  "method": "turn/start",
  "id": 31,
  "params": {
    "threadId": "thr_123",
    "input": [],
    "toolOutput": {
      "name": "run_tests",
      "namespace": null,
      "output": "All 42 tests passed."
    }
  }
}

출력은 대화에서 도구 출력으로 유지되며 알림과 영구 저장된 기록에 functionCallOutput 항목으로 나타납니다. 일반 턴이 이미 활성 상태라면 Codex는 해당 턴에 사용할 수 있도록 출력을 대기열에 추가합니다.

스레드에 항목 삽입

thread/inject_items을 사용하면 사용자 턴을 시작하지 않고 미리 구성된 Responses API 항목을 로드된 스레드의 프롬프트 기록에 추가할 수 있습니다. 이 항목은 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/steer을 사용하면 진행 중인 활성 턴에 사용자 입력을 더 추가할 수 있습니다.

  • expectedTurnId을 포함해야 하며 활성 턴 ID와 일치해야 합니다.
  • 스레드에 활성 턴이 없으면 요청이 실패합니다.
  • turn/steer은 새 turn/started 알림을 내보내지 않습니다.
  • turn/steer은 턴 수준 재정의(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" } }

턴 시작(스킬 호출)

텍스트 입력에 $<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 } } }

턴 중단

{ "method": "turn/interrupt", "id": 31, "params": { "threadId": "thr_123", "turnId": "turn_456" } }
{ "id": 31, "result": {} }

성공하면 턴이 status: "interrupted" 상태로 종료됩니다.

리뷰

review/start은 스레드에 대해 Codex 리뷰어를 실행하고 리뷰 항목을 스트리밍합니다. 대상은 다음과 같습니다.

  • uncommittedChanges
  • baseBranch(브랜치와의 diff)
  • 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와 다름). 서버는 리뷰 턴을 스트리밍하기 전에 해당 새 스레드에 대한 thread/started 알림도 내보냅니다.

Codex는 일반적인 turn/started 알림을 스트리밍한 다음 enteredReviewMode 항목이 포함된 item/started을 스트리밍합니다.

{
  "method": "item/started",
  "params": {
    "item": {
      "type": "enteredReviewMode",
      "id": "turn_900",
      "review": "current changes"
    }
  }
}

리뷰어가 완료되면 서버는 최종 리뷰 텍스트가 담긴 exitedReviewMode 항목을 포함하는 item/starteditem/completed을 내보냅니다.

{
  "method": "item/completed",
  "params": {
    "item": {
      "type": "exitedReviewMode",
      "id": "turn_900",
      "review": "Looks solid overall..."
    }
  }
}

클라이언트에서 리뷰어 출력을 렌더링할 때 이 알림을 사용합니다.

프로세스 실행

process/*은 실험적인 명시적 프로세스 제어 API입니다. 이 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를 사용합니다. PTY 크기 조정 이벤트에는 process/resizePty을 사용하고 실행 중인 프로세스를 종료하려면 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"을 사용합니다. 외부 샌드박스 모드에서는 networkAccessrestricted(기본값) 또는 enabled로 설정합니다. readOnlyworkspaceWrite에는 위에 표시된 것과 동일한 선택적 access / readOnlyAccess 구조를 사용합니다.

참고:

  • 서버는 빈 command 배열을 거부합니다.
  • sandboxPolicyturn/start에서 사용하는 것과 같은 형식(예: dangerFullAccess, readOnly, workspaceWrite, externalSandbox)을 받습니다.
  • 생략하면 timeoutMs은 서버 기본값을 사용합니다.
  • PTY 기반 세션에는 tty: true을 설정하고, 이후 command/exec/write, command/exec/resize 또는 command/exec/terminate을 사용할 계획이면 processId을 사용합니다.
  • 명령 실행 중 command/exec/outputDelta 알림을 받으려면 streamStdoutStderr: true을 설정합니다.

관리자 요구 사항 읽기(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.requirementsnull입니다. 지원되는 키와 값에 관한 자세한 내용은 requirements.toml 문서를 참조하십시오.

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 알림을 받도록 활성 전송 스트림을 계속 읽으십시오.

알림 수신 거부

클라이언트는 initialize.params.capabilities.optOutNotificationMethods에 정확한 메서드 이름을 전송하여 연결별로 특정 알림을 억제할 수 있습니다.

  • 정확히 일치하는 경우에만 적용됩니다. item/agentMessage/delta은 해당 메서드만 억제합니다.
  • 알 수 없는 메서드 이름은 무시됩니다.
  • 현재 thread/*, turn/*, item/* 및 관련 v2 알림에 적용됩니다.
  • 요청, 응답 또는 오류에는 적용되지 않습니다.

퍼지 파일 검색 이벤트(실험적)

퍼지 파일 검색 세션 API는 쿼리별 알림을 내보냅니다.

  • fuzzyFileSearch/sessionUpdated - 활성 쿼리의 현재 일치 항목이 포함된 { sessionId, query, files }.
  • fuzzyFileSearch/sessionCompleted - 해당 쿼리의 인덱싱 및 일치 작업이 완료되면 { sessionId }.

경고 이벤트

  • configWarning - 복구 가능한 구성 또는 초기화 문제에 대한 { summary, details?, path?, range? }.
  • warning - 치명적이지 않은 런타임 경고에 대한 { threadId?, message }.

Windows 샌드박스 설정 이벤트

  • windowsSandbox/setupCompleted - windowsSandbox/setupStart 요청이 완료된 후 내보내지는 { mode, success, error }.

턴 이벤트

  • turn/started - 턴 ID, 빈 itemsstatus: "inProgress"이 포함된 { turn }.
  • turn/completed - turn.statuscompleted, interrupted 또는 failed{ turn }. 실패에는 { error: { message, codexErrorInfo?, additionalDetails? } }이 포함됩니다.
  • turn/diff/updated - 턴에서 변경된 모든 파일에 걸쳐 집계된 최신 통합 diff가 포함된 { threadId, turnId, diff }.
  • turn/plan/updated - 에이전트가 계획을 공유하거나 변경할 때마다 내보내지는 { turnId, explanation?, plan }. 각 plan 항목은 pending, inProgress 또는 completed 중 하나인 status을 포함하는 { step, status }입니다.
  • hook/startedhook/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/updatedturn/plan/updated에는 현재 항목 이벤트가 스트리밍되는 경우에도 빈 items 배열이 포함됩니다. 턴 항목의 기준 데이터로 item/* 알림을 사용하십시오.

항목

ThreadItem은 턴 응답 및 item/* 알림에 포함되는 태그된 유니온입니다. 일반적인 항목 유형은 다음과 같습니다.

  • userMessage - content가 사용자 입력(text, image 또는 localImage) 목록인 {id, content}입니다.
  • functionCallOutput - turn/start.toolOutput을 통해 제공된 독립 실행형 도구 출력의 {id, name, namespace, output}입니다. namespacenull일 수 있습니다.
  • agentMessage - 누적된 에이전트 응답을 포함하는 {id, text, phase?}입니다. phase가 있는 경우 Responses API 와이어 값(commentary, final_answer)을 사용합니다.
  • plan - 계획 모드에서 제안된 계획 텍스트를 포함하는 {id, text}입니다. item/completed의 최종 plan 항목을 최종 기준으로 간주합니다.
  • reasoning - summary에 스트리밍된 추론 요약이, content에 원시 추론 블록이 들어 있는 {id, 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 앱의 경우 appContextconnectorId, linkId, resourceUri, appName, templateId 및 안정적인 커넥터 actionName이 포함될 수 있습니다. 이전에 영구 저장된 항목에는 최신 메타데이터가 없을 수 있습니다. 더 이상 사용되지 않는 최상위 mcpAppResourceUri 대신 appContext.resourceUri을 사용하세요.
  • 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 - Codex가 대화 기록을 압축할 때 내보내는 {id}입니다.

webSearch.action에서 작업 typesearch(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을 사용하십시오.

오류

턴이 실패하면 서버는 { error: { message, codexErrorInfo?, additionalDetails? } }이 포함된 error 이벤트를 내보낸 다음 status: "failed" 상태로 턴을 종료합니다. 업스트림 HTTP 상태를 사용할 수 있으면 codexErrorInfo.httpStatusCode에 표시됩니다.

일반적인 codexErrorInfo 값은 다음과 같습니다.

  • ContextWindowExceeded
  • UsageLimitExceeded
  • HttpConnectionFailed(4xx/5xx 업스트림 오류)
  • ResponseStreamConnectionFailed
  • ResponseStreamDisconnected
  • ResponseTooManyFailedAttempts
  • BadRequest, Unauthorized, SandboxError, InternalServerError, Other

업스트림 HTTP 상태를 사용할 수 있으면 서버가 관련 codexErrorInfo 변형의 httpStatusCode에 전달합니다.

승인

사용자의 Codex 설정에 따라 명령 실행 및 파일 변경에 승인이 필요할 수 있습니다. App-server는 서버 시작 JSON-RPC 요청을 클라이언트에 전송하고 클라이언트는 결정 페이로드로 응답합니다.

  • 명령 실행 결정: accept, acceptForSession, decline, cancel 또는 { "acceptWithExecpolicyAmendment": { "execpolicy_amendment": ["cmd", "..."] } }.

  • 파일 변경 결정: accept, acceptForSession, decline, cancel.

  • 요청에는 threadIdturnId이 포함됩니다. 이를 사용하여 UI 상태의 범위를 활성 대화로 한정하십시오.

  • 서버는 작업을 재개하거나 거부하고 item/completed으로 항목을 종료합니다.

명령 실행 승인

메시지 순서:

  1. item/startedcommand, cwd 및 기타 필드가 포함된 보류 중인 commandExecution 항목이 표시됩니다.
  2. item/commandExecution/requestApproval에는 itemId, threadId, turnId, 선택적 reason, 선택적 command, 선택적 cwd, 선택적 commandActions, 선택적 proposedExecpolicyAmendment, 선택적 networkApprovalContext 및 선택적 availableDecisions이 포함됩니다. initialize.params.capabilities.experimentalApi = true인 경우 페이로드에 요청된 명령별 샌드박스 액세스를 설명하는 실험적 additionalPermissions도 포함될 수 있습니다. additionalPermissions 내의 모든 파일 시스템 경로는 와이어에서 절대 경로입니다.
  3. 클라이언트가 위의 명령 실행 승인 결정 중 하나로 응답합니다.
  4. serverRequest/resolved은 보류 중인 요청에 응답했거나 요청이 해제되었음을 확인합니다.
  5. item/completedstatus: completed | failed | declined이 포함된 최종 commandExecution 항목을 반환합니다.

networkApprovalContext이 있으면 프롬프트는 일반 셸 명령 승인이 아니라 관리형 네트워크 액세스에 관한 것입니다. 현재 v2 스키마는 대상 hostprotocol을 노출합니다. 클라이언트는 네트워크 전용 프롬프트를 렌더링해야 하며 command이 사용자에게 의미 있는 셸 명령 미리 보기라고 가정해서는 안 됩니다.

Codex는 동시 네트워크 승인 프롬프트를 대상(host, 프로토콜 및 포트)별로 그룹화합니다. 따라서 app-server는 같은 대상에 대기 중인 여러 요청을 차단 해제하는 하나의 프롬프트를 전송할 수 있지만, 같은 호스트의 서로 다른 포트는 별도로 처리됩니다.

파일 변경 승인

메시지 순서:

  1. item/started은 제안된 changesstatus: "inProgress"이 포함된 fileChange 항목을 내보냅니다.
  2. item/fileChange/requestApproval에는 itemId, threadId, turnId, 선택적 reason 및 선택적 grantRoot이 포함됩니다.
  3. 클라이언트가 위의 파일 변경 승인 결정 중 하나로 응답합니다.
  4. serverRequest/resolved은 보류 중인 요청에 응답했거나 요청이 해제되었음을 확인합니다.
  5. item/completedstatus: completed | failed | declined이 포함된 최종 fileChange 항목을 반환합니다.

tool/requestUserInput

클라이언트가 item/tool/requestUserInput에 응답하면 app-server는 { threadId, requestId }가 포함된 serverRequest/resolved을 내보냅니다. 클라이언트가 응답하기 전에 턴 시작, 턴 완료 또는 턴 중단으로 보류 중인 요청이 해제되면 서버는 해당 정리를 위해 동일한 알림을 내보냅니다.

요청 매개변수에는 정수 밀리초 제한 시간인 autoResolutionMs 또는 null이 포함됩니다. 이 값이 있으면 사용자가 응답하지 않을 때 호스트 클라이언트가 해당 시간이 지난 후 프롬프트를 자동으로 해결할 수 있습니다.

권한 요청

기본 제공 request_permissions 도구는 threadId, turnId, itemId, environmentId, cwd, 선택적 reason 및 요청된 네트워크 또는 파일 시스템 권한이 포함된 item/permissions/requestApproval을 전송합니다. 부여된 하위 집합만 포함하는 permissions으로 응답하십시오. 같은 세션의 이후 턴에도 권한 부여를 유지하려면 scope"session"으로 설정하고, 턴 범위 권한 부여에는 이를 생략하거나 "turn"를 사용합니다. 요청되지 않은 권한은 무시됩니다.

MCP 서버 정보 요청

MCP 서버는 mcpServer/elicitation/request으로 턴을 중단할 수 있습니다. 요청에는 threadId, 선택적 turnId, serverName 및 다음 요청 형식 중 하나가 포함됩니다.

  • mode: "form" 또는 mode: "openai/form", 그리고 messagerequestedSchema.
  • mode: "url", 그리고 message, urlelicitationId.

요청된 content과 함께 action: "accept"로 응답하거나, content: null과 함께 action: "decline" 또는 "cancel"로 응답합니다. 그러면 app-server가 serverRequest/resolved을 내보냅니다. openai/form 변형을 받으려면 initialize.params.capabilities.mcpServerOpenaiFormElicitation으로 옵트인하십시오.

동적 도구 호출(실험적)

thread/startdynamicTools 및 해당 item/tool/call 요청 또는 응답 흐름은 실험적 API입니다.

동적 도구 이름과 네임스페이스 이름은 Responses API 명명 제약 조건을 따라야 합니다. 기본 제공 Codex 도구에서 사용하는 예약된 네임스페이스 이름은 피하십시오.

턴 중 동적 도구가 호출되면 app-server는 다음을 내보냅니다.

  1. item.type = "dynamicToolCall", status = "inProgress", 그리고 toolarguments이 포함된 item/started.
  2. 서버가 클라이언트에 요청하는 item/tool/call.
  3. 반환된 콘텐츠 항목이 포함된 클라이언트 응답 페이로드.
  4. item.type = "dynamicToolCall", 최종 status 및 반환된 contentItems 또는 success 값이 포함된 item/completed.

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을 사용하면 사용 가능한 스킬을 가져올 수 있습니다(선택적으로 forceReload와 함께 cwds으로 범위 지정). 또한 perCwdExtraUserRoots을 포함하여 특정 cwd 값에 대해 추가 절대 경로를 user 범위로 검색할 수 있습니다. App-server는 cwdcwds에 없는 항목을 무시합니다. skills/listcwd별로 캐시된 결과를 재사용할 수 있습니다. 디스크에서 새로 고치려면 forceReload: true을 설정하십시오. SKILL.json이 있으면 서버는 여기에서 interfacedependencies을 읽습니다.

{ "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
  }
}

앱(커넥터)

app/installed을 사용하면 최근 커밋된 설치 앱 런타임 스냅샷을 읽을 수 있습니다. 각 결과에는 앱 id, runtimeName(또는 null), 유효 enabled 상태 및 callable 상태가 포함됩니다. 유효 구성이 앱을 활성화하고 모델에 표시되는 도구가 하나 이상 앱 및 도구 정책을 준수할 때만 앱을 호출할 수 있습니다.

{
  "method": "app/installed",
  "id": 49,
  "params": {
    "threadId": "thread-1",
    "forceRefresh": false
  }
}
{
  "id": 49,
  "result": {
    "apps": [
      {
        "id": "demo-app",
        "runtimeName": "Demo App",
        "enabled": true,
        "callable": true
      }
    ]
  }
}

로드된 스레드의 구성 대신 전역 구성을 사용하려면 threadId을 생략합니다. 읽기 전에 커넥터 런타임 스냅샷을 새로 고치려면 forceRefresh: true을 설정합니다. 전역 또는 워크스페이스 정책이 앱 액세스를 차단해도 관찰된 앱은 enabledcallablefalse으로 설정된 채 표시될 수 있습니다.

app/list을 사용하면 사용 가능한 앱을 가져올 수 있습니다. CLI/TUI에서 /apps은 사용자용 선택기이며, 사용자 지정 클라이언트에서는 app/list을 직접 호출합니다. 각 항목에는 isAccessible(사용자가 이용 가능)과 isEnabled(config.toml에서 활성화됨)이 모두 포함되므로 클라이언트는 설치/액세스와 로컬 활성화 상태를 구분할 수 있습니다. 앱 항목에는 선택적 branding, appMetadatalabels 필드도 포함될 수 있습니다.

{ "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)에서 해당 스레드의 구성 스냅샷을 사용합니다. 생략하면 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
      }
    ]
  }
}

앱 ID를 이미 알고 있고 설치된 런타임 상태가 아닌 앱 메타데이터가 필요할 때는 app/read을 사용합니다. 최대 100개의 appIds를 전달합니다. 서버는 반복된 각 ID의 첫 번째 항목만 유지하며 appsmissingAppIds 모두에서 해당 순서를 보존합니다. 알 수 없거나 액세스할 수 없는 앱은 전체 요청을 실패시키지 않고 missingAppIds에 반환됩니다.

{
  "method": "app/read",
  "id": 52,
  "params": {
    "appIds": ["demo-app", "missing-app"],
    "includeTools": true
  }
}
{
  "id": 52,
  "result": {
    "apps": [
      {
        "id": "demo-app",
        "name": "Demo App",
        "description": "Example connector for documentation.",
        "iconUrl": null,
        "iconUrlDark": null,
        "distributionChannel": null,
        "installUrl": null,
        "pluginDisplayNames": [],
        "toolSummaries": [
          {
            "name": "search",
            "title": "Search",
            "description": "Search the app.",
            "isEnabled": true,
            "disabledReason": null,
            "isReadOnly": true
          }
        ]
      }
    ],
    "missingAppIds": ["missing-app"]
  }
}

표시 전용 공개 도구 요약을 요청하려면 includeTools: true을 설정합니다. 메타데이터 응답에는 설치된 앱 런타임 상태가 포함되지 않으며 도구 호출을 승인하지도 않습니다. 유효 enabledcallable 상태를 확인하려면 app/installed을 사용하십시오.

텍스트 입력에 $<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 예시

config/read, config/value/writeconfig/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"
      }
    ]
  }
}

외부 에이전트 구성 감지 및 가져오기

externalAgentConfig/detect을 사용하여 마이그레이션할 수 있는 외부 에이전트 아티팩트를 찾은 다음 선택한 항목을 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 및 유형별 successesfailures가 포함된 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, COMMANDSSESSIONS입니다. PLUGINS 항목에서 details.plugins은 각 marketplaceName 및 Codex가 마이그레이션을 시도할 수 있는 pluginNames을 나열합니다. 감지는 아직 처리할 작업이 있는 항목만 반환합니다. 예를 들어 AGENTS.md이 이미 존재하고 비어 있지 않으면 Codex는 AGENTS 마이그레이션을 건너뛰며, 스킬 가져오기는 기존 스킬 디렉터리를 덮어쓰지 않습니다.

.claude/settings.json에서 플러그인을 감지할 때 Codex는 extraKnownMarketplaces에서 구성된 마켓플레이스 소스를 읽습니다. enabledPluginsclaude-plugins-official의 플러그인이 있지만 마켓플레이스 소스가 없으면 Codex는 anthropics/claude-plugins-official을 소스로 추론합니다.

인증 엔드포인트

JSON-RPC 인증/계정 표면은 요청/응답 메서드와 서버 시작 알림(id 없음)을 노출합니다. 이를 사용하여 인증 상태를 확인하고, 로그인을 시작하거나 취소하고, 로그아웃하고, ChatGPT 사용 한도를 확인하며, 크레딧 소진 또는 사용량 한도에 관해 워크스페이스 소유자에게 알릴 수 있습니다.

인증 모드

Codex는 다음 인증 모드를 지원합니다. account/updated.authMode은 활성 모드를 표시하고, 가능한 경우 현재 ChatGPT planType을 포함합니다. account/read은 계정 및 요금제 세부 정보도 보고합니다.

  • API key(apikey) - 호출자가 type: "apiKey"으로 OpenAI API key를 제공하며 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 key(credentialSource: "codexManaged")에서 오는지 외부 AWS 자격 증명 체인(credentialSource: "awsManaged")에서 오는지 나타냅니다. account/updated.authMode은 Codex 관리형 Bedrock API key에 bedrockApiKey을 사용합니다.

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 값을 사용해 획득한 사용 한도 초기화 1회를 사용합니다.
  • account/usage/read - ChatGPT 계정의 토큰 활동 요약 및 일별 버킷을 가져옵니다.
  • account/workspaceMessages/read - 가능한 경우 알림 제목을 포함하여 활성 워크스페이스 메시지를 가져옵니다.
  • mcpServer/oauthLogin/completed(알림) - mcpServer/oauth/login 흐름이 완료된 후 내보내지며 페이로드에는 { name, threadId, success, error? }이 포함됩니다. 앱 범위 또는 플러그인 OAuth 흐름에서는 threadIdnull일 수 있습니다.
  • mcpServer/startupStatus/updated(알림) - 구성된 MCP 서버의 시작 상태가 변경될 때 내보내지며 페이로드에는 { threadId, name, status, error, failureReason }이 포함됩니다. 앱 범위 시작의 경우 threadIdnull입니다. 시작에 실패했을 때 failureReason: "reauthenticationRequired"은 저장된 OAuth 자격 증명이 만료되었고 갱신할 수 없었음을 의미하므로 클라이언트는 서버 재연결 옵션을 제공해야 합니다.

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 계정에 이메일 주소가 없으면 emailnull입니다.
  • requiresOpenaiAuth은 활성 공급자를 반영합니다. false인 경우 Codex는 OpenAI 자격 증명 없이 실행할 수 있습니다.
  • Amazon Bedrock은 Codex에서 관리하는 Bedrock API key를 사용할 때 credentialSource: "codexManaged"을 보고합니다. 외부 AWS 자격 증명 경로에는 credentialSource: "awsManaged"을 보고합니다. 이는 선택한 자격 증명 소스를 식별할 뿐이며 AWS 자격 증명 체인에서 자격 증명을 확인할 수 있는지는 검증하지 않습니다.

2) API key로 로그인

  1. 전송:
   {
     "method": "account/login/start",
     "id": 2,
     "params": { "type": "apiKey", "apiKey": "sk-..." }
   }
  1. 예상 응답:
   { "id": 2, "result": { "type": "apiKey" } }
  1. 알림:
   {
     "method": "account/login/completed",
     "params": { "loginId": null, "success": true, "error": null }
   }
   {
     "method": "account/updated",
     "params": { "authMode": "apikey", "planType": null }
   }

3) ChatGPT로 로그인(브라우저 흐름)

  1. 시작:
   {
     "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"
     }
   }
  1. 브라우저에서 authUrl을 엽니다. app-server가 로컬 콜백을 호스팅합니다.
  2. 알림 대기:
   {
     "method": "account/login/completed",
     "params": { "loginId": "<uuid>", "success": true, "error": null }
   }
   {
     "method": "account/updated",
     "params": { "authMode": "chatgpt", "planType": "plus" }
   }

3b) ChatGPT로 로그인(기기 코드 흐름)

클라이언트가 로그인 절차를 관리하거나 브라우저 콜백이 불안정할 때 이 흐름을 사용합니다.

  1. 시작:
   {
     "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"
     }
   }
  1. 사용자에게 verificationUrluserCode을 표시합니다. 프런트엔드가 UX를 담당합니다.
  2. 알림 대기:
   {
     "method": "account/login/completed",
     "params": { "loginId": "<uuid>", "success": true, "error": null }
   }
   {
     "method": "account/updated",
     "params": { "authMode": "chatgpt", "planType": "plus" }
   }

3c) 외부에서 관리되는 ChatGPT 토큰으로 로그인(chatgptAuthTokens)

호스트 애플리케이션이 사용자의 ChatGPT 인증 수명 주기를 관리하고 토큰을 직접 제공할 때만 이 실험적 모드를 사용합니다. 이 로그인 유형을 사용하기 전에 클라이언트는 initialize 중에 capabilities.experimentalApi = true을 설정해야 합니다.

  1. 전송:
   {
     "method": "account/login/start",
     "id": 7,
     "params": {
       "type": "chatgptAuthTokens",
       "accessToken": "<jwt>",
       "chatgptAccountId": "org-123",
       "chatgptPlanType": "business"
     }
   }
  1. 예상 응답:
   { "id": 7, "result": { "type": "chatgptAuthTokens" } }
  1. 알림:
   {
     "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 로그인 취소

{ "method": "account/login/cancel", "id": 4, "params": { "loginId": "<uuid>" } }
{ "method": "account/login/completed", "params": { "loginId": "<uuid>", "success": false, "error": "..." } }

5) 로그아웃

{ "method": "account/logout", "id": 5 }
{ "id": 5, "result": {} }
{ "method": "account/updated", "params": { "authMode": null, "planType": null } }

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.creditsnull입니다. 빈 배열은 서비스가 세부 정보를 가져왔지만 사용 가능한 크레딧이 없었음을 의미합니다. 서비스가 세부 정보 행 수를 제한할 수 있으므로 availableCount을 기준으로 간주하십시오.
  • 각 세부 정보 행에는 불투명한 id, resetType, status, grantedAt, expiresAt(null일 수 있음), title(null일 수 있음) 및 description(null일 수 있음)이 포함됩니다.
  • 초기화를 사용한 후 account/rateLimits/read을 가져옵니다.

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일 수 있습니다.
  • dailyUsageBucketsnull일 수 있습니다. 값이 있으면 각 버킷에 startDatetokens이 포함됩니다.
  • 엔드포인트에는 Codex 서비스가 지원하는 인증이 필요합니다. ChatGPT, 외부 ChatGPT 토큰, 에이전트 ID 및 개인 액세스 토큰 인증은 사용할 수 있지만 API key 전용 및 Bedrock 인증은 사용할 수 없습니다.

8) 획득한 사용 한도 초기화(ChatGPT)

account/rateLimitResetCredit/consume을 사용하면 획득한 초기화 1회를 사용할 수 있습니다.

{ "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) 한도에 관해 워크스페이스 소유자에게 알리기

크레딧이 소진되었거나 사용량 한도에 도달했을 때 ChatGPT가 워크스페이스 소유자에게 이메일을 보내도록 요청하려면 account/sendAddCreditsNudgeEmail을 사용합니다.

{ "method": "account/sendAddCreditsNudgeEmail", "id": 9, "params": { "creditType": "credits" } }
{ "id": 9, "result": { "status": "sent" } }

워크스페이스 크레딧이 소진되었을 때는 creditType: "credits"을, 워크스페이스 사용량 한도에 도달했을 때는 creditType: "usage_limit"을 사용합니다. 소유자에게 최근에 이미 알림을 보냈다면 응답 상태는 cooldown_active입니다.

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 }
] } }