Codex CLI and Codex Desktop

Codex Pooler supports both Codex CLI and Codex Desktop through the Codex backend compatibility route. Both Codex surfaces share the same configuration layers and user-level CODEX_HOME/config.toml, so one provider block can serve the terminal and desktop/IDE experience.
Use /backend-api/codex, not the OpenAI-compatible /v1 SDK surface. Put provider and auth settings in the user-level config file; Codex’s project-local .codex/config.toml layers are trust-gated and do not override machine-local provider keys such as model_provider or model_providers.
Config file path
Section titled “Config file path”Codex resolves CODEX_HOME first. If CODEX_HOME is unset, current Codex sources default it to $HOME/.codex on every OS, so the user config file is CODEX_HOME/config.toml.
| OS | Default config file |
|---|---|
| macOS | $HOME/.codex/config.toml |
| Linux | $HOME/.codex/config.toml |
| Windows | $HOME\.codex\config.toml, normally %USERPROFILE%\.codex\config.toml |
Codex Desktop and the IDE extension open the same file from Codex Settings > Open config.toml.
For a deployed instance, the Codex backend base URL is:
https://codex-pooler.example.com/backend-api/codexFor local setup and local connection checks, use:
http://localhost:4000/backend-api/codexKeep your Pool API key in an environment variable. Don’t paste raw keys into CODEX_HOME/config.toml.
Websocket provider for Codex CLI and Desktop
Section titled “Websocket provider for Codex CLI and Desktop”Use the websocket-capable provider for normal Codex backend behavior in Codex CLI and Codex Desktop. Keep the provider id as codex-pooler-ws, but keep name = "OpenAI" exactly. In current Codex sources, name is not just a display label: exact OpenAI matching enables OpenAI-family behavior such as remote compaction, web search/image availability, and Codex backend request-body compression.
model_provider = "codex-pooler-ws"
[model_providers.codex-pooler-ws]name = "OpenAI"base_url = "https://codex-pooler.example.com/backend-api/codex"env_key = "CODEX_POOLER_API_KEY"wire_api = "responses"supports_websockets = truerequires_openai_auth = trueWith a local Codex Pooler instance, change base_url to http://localhost:4000/backend-api/codex.
When an interrupted Codex websocket turn reconnects, Pooler uses the current Codex turn identity to distinguish an exact retry from an edited replacement. An exact retry reconnects to the existing turn; an edited replacement waits only for a bounded safe cancellation handoff before it starts, rather than sitting until the client’s idle watchdog expires.
HTTP/SSE provider
Section titled “HTTP/SSE provider”Keep an HTTP/SSE provider when you need to force non-websocket behavior for a client check or when a Codex runtime cannot open backend websocket streams.
model_provider = "codex-pooler-http"
[model_providers.codex-pooler-http]name = "OpenAI"base_url = "https://codex-pooler.example.com/backend-api/codex"env_key = "CODEX_POOLER_API_KEY"wire_api = "responses"supports_websockets = falserequires_openai_auth = trueBoth providers use the same Pool API key and the same Codex backend compatibility route in Codex CLI and Codex Desktop. Codex Pooler routes each request through Pool policy, account eligibility, limits, session continuity, and request accounting.
Leave requires_openai_auth = true unless you are deliberately running Codex Pooler as a gateway-only provider. With true, Codex still shows the local OpenAI/ChatGPT account as signed in, which keeps Codex Desktop and app-server features that depend on account state available. The Pool API key in env_key still authenticates requests to Codex Pooler.
If Codex repeatedly enters a broken login/account state with a Pooler provider, advanced users can change the provider to requires_openai_auth = false. That makes Codex treat the provider as gateway-only and use only env_key for runtime auth, but Codex will no longer appear signed in for that provider and account-dependent features, including mobile/app-server features, may be unavailable.
When Codex Pooler serves current model metadata, Codex CLI and Codex Desktop derive their effective context window and automatic compaction boundary from that metadata. Leave context sizing automatic so the client follows per-model catalog changes without stale local overrides. Provider catalog rollout can be account-scoped: one upstream can still report a 272000-token maximum while another reports the newer 872000-token ceiling for the same model. Pooler selects one canonical source cohort for the Pool and exposes that cohort’s raw window plus effective_context_window_percent; Codex applies the percentage once. A 272000-token profile therefore resolves to 258400 usable tokens, while a selected 872000-token long profile resolves to 828400. The narrow /v1/models surface publishes that selected effective value directly as context_length for SDK-style clients.
Request compression behavior
Section titled “Request compression behavior”Codex CLI and Codex Desktop do not need a client-side switch for Codex Pooler’s per-Pool request compression. When an operator enables request_compression_enabled, eligible backend Responses, backend compact, backend /v1/responses aliases, translated backend chat, and websocket response.create requests may have upstream-bound Responses tool-output payloads compressed before dispatch.
The feature is request-side only. Codex Pooler does not store raw outputs, does not store upstream response bodies, and does not implement CCR/retrieval. Request logs may show safe aggregate payload_compression savings, preferring saved token count and token savings percent when token counts are available and falling back to byte savings when they are not.
Optional operator MCP endpoint
Section titled “Optional operator MCP endpoint”Codex Pooler also exposes an operator MCP endpoint at /mcp. This is an optional operator-only metadata add-on. Omit it for normal Codex runtime use. MCP uses an operator-owned MCP token, not a Pool API key.
[mcp_servers.codex_pooler]url = "https://codex-pooler.example.com/mcp"bearer_token_env_var = "CODEX_POOLER_MCP_KEY"Set the token separately:
export CODEX_POOLER_MCP_KEY="<operator-mcp-token>"Use http://localhost:4000/mcp only for local setup.
Existing session migration
Section titled “Existing session migration”Codex filters resumable conversations by model_provider in local Codex state. If you already have Codex CLI or Codex Desktop sessions created with the built-in openai provider and want them to appear under codex-pooler-ws, re-tag both the JSONL transcripts and the newer SQLite state database.
Close Codex first; these commands edit local Codex state in place. If you made the HTTP provider your default, replace only the destination value codex-pooler-ws with codex-pooler-http before copying.
macOS (zsh)
Section titled “macOS (zsh)”Run these two zsh one-liners:
if [ -d "$HOME/.codex/sessions" ]; then find "$HOME/.codex/sessions" -type f -name '*.jsonl' -exec perl -0pi -e 's/("model_provider"\s*:\s*)"openai"/$1"codex-pooler-ws"/g' {} +; fifor db in "$HOME"/.codex/state_*.sqlite(N); do sqlite3 "$db" "UPDATE threads SET model_provider = 'codex-pooler-ws' WHERE model_provider = 'openai';"; doneLinux (bash)
Section titled “Linux (bash)”Run these two bash one-liners:
if [ -d "$HOME/.codex/sessions" ]; then find "$HOME/.codex/sessions" -type f -name '*.jsonl' -exec perl -0pi -e 's/("model_provider"\s*:\s*)"openai"/$1"codex-pooler-ws"/g' {} +; fifor db in "$HOME"/.codex/state_*.sqlite; do [ -e "$db" ] || continue; sqlite3 "$db" "UPDATE threads SET model_provider = 'codex-pooler-ws' WHERE model_provider = 'openai';"; doneWindows (PowerShell)
Section titled “Windows (PowerShell)”Run the same migration from PowerShell. This expects sqlite3 to be available on PATH.
$ErrorActionPreference = "Stop"
$FromProvider = "openai"$ToProvider = "codex-pooler-ws"$CodexHome = Join-Path $HOME ".codex"
$FromJson = '"model_provider":"' + $FromProvider + '"'$ToJson = '"model_provider":"' + $ToProvider + '"'
Get-ChildItem -Path (Join-Path $CodexHome "sessions") -Recurse -Filter "*.jsonl" | ForEach-Object { $Path = $_.FullName $TempPath = "$Path.tmp" $Reader = [System.IO.StreamReader]::new($Path) $Writer = [System.IO.StreamWriter]::new( $TempPath, $false, [System.Text.UTF8Encoding]::new($false) )
try { while (($Line = $Reader.ReadLine()) -ne $null) { $Writer.WriteLine($Line.Replace($FromJson, $ToJson)) } } finally { $Reader.Dispose() $Writer.Dispose() }
Move-Item -Force $TempPath $Path }
Get-ChildItem -Path $CodexHome -Filter "state_*.sqlite" | ForEach-Object { sqlite3 $_.FullName ` "UPDATE threads SET model_provider = '$ToProvider' WHERE model_provider = '$FromProvider';" }Route boundaries
Section titled “Route boundaries”/backend-api/codex/* is an authenticated Codex backend compatibility surface for Codex CLI and Codex Desktop. It is not a wildcard proxy and it is not the OpenAI-compatible /v1 SDK surface.
The backend route family includes GET /backend-api/codex/models, POST /backend-api/codex/responses, backend websocket response-stream compatibility on GET /backend-api/codex/responses, and POST /backend-api/codex/responses/compact. The public POST /v1/responses/compact route remains unsupported.
Codex Pooler supports Codex model-provider traffic only. Do not point chatgpt_base_url at Codex Pooler for account, realtime, identity, or other app-server helper calls.