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.
  • Have Codex signed in with ChatGPT or an OpenAI API key. The provider below keeps requires_openai_auth = true, and without a local login Codex CLI opens its sign-in screen even when the Pool API key is set. With only a Pool API key, set requires_openai_auth = false instead; Troubleshooting explains what that turns off.

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. Add the settings below to your user config file, not a project’s .codex/config.toml.

If you set CODEX_HOME, use the config.toml inside that folder. Otherwise, use the default location for your operating system:

OS Default config file
macOS ~/.codex/config.toml
Linux ~/.codex/config.toml
Windows %USERPROFILE%\.codex\config.toml

On Windows, paste the %USERPROFILE% 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 in Codex CLI and Codex Desktop. Keep name = "OpenAI": Codex uses this exact name to enable native backend features. The provider id and URLs below point those requests at Codex Pooler.

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

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.

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.

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.

Use this alternative if your network cannot connect through websockets.

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

This uses the same Pool API key as the recommended setup and works in both Codex CLI and Desktop. Your Pool’s models and limits still apply.

Codex groups saved conversations by provider. To make conversations started with the built-in openai provider appear under codex-pooler-ws, update their local records with the commands below.

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

You can display the provider as Codex Pooler instead of OpenAI. The extra settings below keep automatic conversation compaction and web search available. Replace the websocket provider block with this configuration:

CODEX_HOME/config.toml
model_provider = "codex-pooler-ws"
[model_providers.codex-pooler-ws]
name = "Codex Pooler"
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
supports_standalone_web_search = true
[model_providers.codex-pooler-ws.capabilities]
remote_compaction = "v2"
external_web_access = true

For HTTP/SSE, use codex-pooler-http as the provider id and table name, and set supports_websockets = false. Keep the existing provider id when changing a saved setup so conversations continue to reference it.

Your Pool’s feature restrictions still apply. A custom name also disables some of Codex’s internal optimizations and advanced reasoning and compaction features; ordinary reasoning-effort selection still works. Keep the recommended OpenAI name for the widest compatibility.

Keep requires_openai_auth = true if you want Codex’s standalone image-generation tool. With a custom name, setting it to false hides that tool.

The model_catalog_url line in the configuration above lets Codex load your Pool’s model list automatically. No extra feature setting is needed.

If you change the Pooler address, update both base_url and model_catalog_url. Use the final catalog address supplied by your operator: Codex does not follow redirects when loading the list.

If the model list is empty, check the address and Pool API key, then run codex debug models to try loading it again. Codex does not replace a failed configured catalog with its built-in list. If it still fails, ask your Pool operator to check catalog troubleshooting.

Select a model from Codex’s model picker. A warning that the OpenAI address is overridden is expected with this setup; it does not stop you from selecting a Pool model.

Leave context and automatic compaction settings at their defaults. Codex reads the limits for each model from your Pool, so you do not need to copy token limits into config.toml. If you previously set manual limits, remove them to follow the Pool’s defaults.

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.

Codex CLI keeps its app server running in the background after you quit, with the environment and sign-in state it started with. After you change CODEX_POOLER_API_KEY or sign in, run codex app-server daemon restart from a terminal that has the new value, or codex app-server daemon stop to let the next codex start a fresh one; changes to the provider block in config.toml, such as base_url, apply to the next session without a restart.

When every account in the Pool has used up its quota, Codex CLI names the time the Pool resets in its usage-limit message. Codex Desktop shows Codex Pooler’s own message instead, for example The Pool's usage limit is reached. Try again at 01:28 UTC (in about 1 h 24 min)., because its built-in usage-limit screen reads the ChatGPT account and cannot know the Pool’s reset. See When every upstream account is exhausted.

If one account runs out of quota while your Pool still has capacity, Codex can reconnect and continue the conversation using another account.

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 does not appear signed in for that provider and account-dependent features, including mobile/app-server features, may be unavailable. With a custom provider name, gateway-only mode also hides Codex’s standalone image-generation tool; keep requires_openai_auth = true when you need it.

The bundled ImageGen Python script has a separate SDK connection: set OPENAI_BASE_URL to the Pooler’s /v1 URL and OPENAI_API_KEY to your Pool API key in the process that launches it. The chat provider’s base_url does not set those variables. See ImageGen script setup; no additional Pooler skill or JSON configuration is required.

This setup connects Codex’s model requests to Pooler. It does not proxy your ChatGPT account or every OpenAI feature. Leave chatgpt_base_url unchanged; see Runtime routes for the supported requests.

For Codex Mobile Remote behavior and the desktop-first workaround, see Codex Mobile on Codex Pooler.

Codex can interrupt a response to handle new input while the model is still generating. Pooler supports this, and the tokens generated before the interruption still count toward usage.

When Codex works with other agents, it can pause a reply to read their updates and then continue. This can explain some cancelled entries in the request log while the conversation keeps going.

The default is fine for normal use. If you prefer Codex to finish its current response before reading agent updates, you can try this experimental option. Add the setting to your existing [features] section, or use this block if you don’t have one:

CODEX_HOME/config.toml
[features]
defer_mailbox_preemption = true

The trade-offs are:

  • Results, corrections and blocker reports from other agents wait until the current response finishes. Coordination can be slower, especially during a long response.
  • Codex can continue with planned actions before reading that new information, so it may do unnecessary work and use extra tokens.

Updates are queued, not discarded. Start a new conversation to apply the setting. You can still stop a reply yourself. Remove the setting to return to the default.