Skip to content

Codex CLI / Desktop on Codex Pooler

Codex is OpenAI’s coding agent for exploring a codebase, making changes and running checks. Use it from the terminal or the desktop app, with Codex Pooler providing access to your Pool’s models through one API key. The configuration below is shared by both clients.

Codex Pooler integration for Codex CLI and Codex Desktop

  • Install Codex CLI or Codex Desktop using the official instructions for your operating system.
  • Have a Codex Pooler URL reachable from the client.
  • Create a Pool API key and choose a model available to that Pool.

Use the commands for the terminal that starts the client. Environment-variable assignments below apply to that terminal; desktop apps and services need the variables in their own launch environment.

Use /backend-api/codex for Codex CLI and Desktop. Put provider and auth settings in the user-level config file; project-local .codex/config.toml layers are trust-gated and do not override machine-local provider keys such as model_provider or model_providers.

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 ~/.codex/config.toml
Linux ~/.codex/config.toml
Windows %USERPROFILE%\.codex\config.toml

These are the default locations. On Windows, paste the %USERPROFILE%, %APPDATA% or %LOCALAPPDATA% path into File Explorer’s address bar. For a client installed inside WSL, use the Linux paths and commands inside WSL. Keep any custom configuration folder or profile you already use.

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/codex

For local setup and local connection checks, use:

http://localhost:4000/backend-api/codex

Keep your Pool API key in the environment that starts Codex. Don’t paste raw keys into CODEX_HOME/config.toml.

macOS / Linux / WSL

Terminal window
export CODEX_POOLER_API_KEY="<pool-api-key>"

Windows PowerShell

Terminal window
$env:CODEX_POOLER_API_KEY = "<pool-api-key>"

For Codex Desktop, make the same variable available to the app process; setting it in an unrelated terminal does not update an already-running app.

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.

CODEX_HOME/config.toml
model_provider = "codex-pooler-ws"
[model_providers.codex-pooler-ws]
name = "OpenAI"
base_url = "https://codex-pooler.example.com/backend-api/codex"
model_catalog_url = "https://codex-pooler.example.com/backend-api/codex/models"
env_key = "CODEX_POOLER_API_KEY"
wire_api = "responses"
supports_websockets = true
requires_openai_auth = true
[features]
api_key_model_discovery = true

With a local Codex Pooler instance, change base_url to http://localhost:4000/backend-api/codex and model_catalog_url to http://localhost:4000/backend-api/codex/models. If your config file already has a [features] table, add api_key_model_discovery = true to it instead of starting a second one.

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.

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.

model_catalog_url and api_key_model_discovery are what let Codex 0.156.0 and later read the Pool’s model catalog. Starting with 0.156.0 (first shipped in the 0.156.0-alpha.7 prerelease), Codex treats any provider with env_key as API-key authentication and, for a custom base_url, no longer requests <base_url>/models on its own. Without both settings it keeps the catalog bundled with the Codex release: models that only your Pool serves are missing from the model picker, and context window, automatic compaction, and reasoning defaults come from Codex’s built-in metadata instead of the Pool. Signing in with a ChatGPT account does not change this.

Earlier Codex releases ignore both settings and keep reading the Pool catalog from base_url while a ChatGPT account is signed in, so the same configuration works across the version boundary. Codex Desktop and the IDE extension run their own bundled Codex core and read the same CODEX_HOME/config.toml; they follow the same rule once that core reaches 0.156.0. The core version is the number after the client name in the user agent those apps send, which Codex Pooler request logs show.

When you set model_catalog_url:

  • Use the absolute URL of the Pool catalog, /backend-api/codex/models under the same host as base_url. Codex adds its client_version query parameter itself and authenticates with the same Pool API key.
  • Point it at the final URL. Codex refuses redirects on this request, so an http:// URL that the ingress redirects to https:// fails.
  • Codex refuses a catalog response larger than 1 MiB and then keeps its bundled catalog. The upstream catalog repeats each model’s instructions in a legacy base_instructions field for older Codex releases; Codex Pooler leaves that copy out for Codex 0.148.0 and later, which read the same text from model_messages, and keeps it for older releases and for any client whose User-Agent is not a Codex build’s. The release is read from the Codex User-Agent, the same header every Responses turn carries, so the catalog ETag a turn announces always matches the catalog that client fetched and Codex never refetches the catalog after each turn. For current releases that makes the catalog about a third smaller, and entries are typically 25 to 65 KB each (40 to 90 KB with the legacy copy), so a Pool that exposes many models can still reach the limit.
  • Codex discards the whole catalog when one entry fails to decode. For the Codex releases Codex Pooler has been verified against (0.154.0 through 0.158.0), an entry that release cannot decode is left out instead: that model is missing from the picker but still works when requested by name. Operators see a codex catalog entry left out warning; see Codex Catalog Entries Left Out.

api_key_model_discovery is marked as under development in Codex. Codex prints an under-development warning at startup while it is enabled; set suppress_unstable_features_warning = true at the top level of the config file to hide it. Because the feature is still under development, a later Codex release may rename or change it; recheck this page when you upgrade Codex.

Select a model available to your Pool in Codex’s model picker.

When Codex reads the Pool catalog (see Model catalog discovery), 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. Pooler preserves the selected upstream’s default context_window, supported max_context_window, and compaction metadata. A larger supported maximum does not activate that window, and pricing categories do not change any of these values. When the upstream leaves auto_compact_token_limit absent or null, Codex derives its compaction threshold from the active window.

Provider catalog rollout can be account-scoped: different accounts can report different defaults or maximums for the same model. Pooler selects one canonical source cohort for the Pool and exposes its raw default plus effective_context_window_percent; Codex applies the percentage once. With a 95% effective percentage, a default of 272000 and maximum of 872000 provides 258400 usable tokens automatically. An upstream default of 872000 provides 828400. The narrow /v1/models surface publishes the selected default’s effective value directly as context_length for SDK-style clients. Existing explicit operator context overrides still take precedence; they are not needed for automatic sizing.

Start a new Codex CLI or Desktop conversation with codex-pooler-ws selected and send a short request. Confirm that it completes, then check the request time, API key, model, and final status in Codex Pooler’s request logs.

To check catalog discovery without sending a model request, run codex debug models with the same configuration. It prints the catalog Codex will use, which should list your Pool’s models rather than only the models bundled with Codex.

In a disposable project, also try a small file edit and a follow-up request to check tool use and continuation. Existing conversations may retain their original provider; use the migration instructions below only when you need to move them.

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.

CODEX_HOME/config.toml
model_provider = "codex-pooler-http"
[model_providers.codex-pooler-http]
name = "OpenAI"
base_url = "https://codex-pooler.example.com/backend-api/codex"
model_catalog_url = "https://codex-pooler.example.com/backend-api/codex/models"
env_key = "CODEX_POOLER_API_KEY"
wire_api = "responses"
supports_websockets = false
requires_openai_auth = true

api_key_model_discovery = true under [features], shown with the websocket provider above, applies to every provider in the file; keep one [features] table even when both providers are configured.

Both 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.

Codex Pooler preserves accepted tool-output text on Codex backend Responses, compatible aliases, native compact and supported websocket requests. No client or Pool compression switch is required. Existing Full/Lite normalization and provider or client compaction remain unchanged.

Raw tool outputs are not stored in request logs, and compression savings are not displayed. During an upgrade, old nodes retain their old behavior until replaced; changing the serialized upstream prefix can also change prompt-cache reuse.

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.

Run these two zsh one-liners:

Terminal window
if [ -d "${CODEX_HOME:-$HOME/.codex}/sessions" ]; then find "${CODEX_HOME:-$HOME/.codex}/sessions" -type f -name '*.jsonl' -exec perl -0pi -e 's/("model_provider"\s*:\s*)"openai"/$1"codex-pooler-ws"/g' {} +; fi
Terminal window
for db in "${CODEX_HOME:-$HOME/.codex}"/state_*.sqlite(N); do sqlite3 "$db" "UPDATE threads SET model_provider = 'codex-pooler-ws' WHERE model_provider = 'openai';"; done

Run these two bash one-liners:

Terminal window
if [ -d "${CODEX_HOME:-$HOME/.codex}/sessions" ]; then find "${CODEX_HOME:-$HOME/.codex}/sessions" -type f -name '*.jsonl' -exec perl -0pi -e 's/("model_provider"\s*:\s*)"openai"/$1"codex-pooler-ws"/g' {} +; fi
Terminal window
for db in "${CODEX_HOME:-$HOME/.codex}"/state_*.sqlite; do [ -e "$db" ] || continue; sqlite3 "$db" "UPDATE threads SET model_provider = 'codex-pooler-ws' WHERE model_provider = 'openai';"; done

Run the same migration from PowerShell. This expects sqlite3 to be available on PATH.

Terminal window
$ErrorActionPreference = "Stop"
$FromProvider = "openai"
$ToProvider = "codex-pooler-ws"
$CodexHome = if ($env:CODEX_HOME) { $env:CODEX_HOME } else { 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';"
}

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.

CODEX_HOME/config.toml
[mcp_servers.codex_pooler]
url = "https://codex-pooler.example.com/mcp"
bearer_token_env_var = "CODEX_POOLER_MCP_KEY"

Set the token separately:

macOS / Linux / WSL

Terminal window
export CODEX_POOLER_MCP_KEY="<operator-mcp-token>"

Windows PowerShell

Terminal window
$env:CODEX_POOLER_MCP_KEY = "<operator-mcp-token>"

Use http://localhost:4000/mcp only for local setup.

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.

/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.