Codex Pooler is a self-hosted gateway for running Codex-compatible agents, tools, and automation through stable Pool API keys. It works with one upstream Codex account for credential isolation, client normalization, metadata-only operations, and saved reset visibility; add more accounts when you want shared capacity and routing across eligible accounts.

Clients send familiar Codex backend or OpenAI-compatible requests; Codex Pooler selects an eligible account based on model support, quota evidence, limits, session continuity, routing policy, and health. The Pool key stays stable while upstream assignments, lifecycle state, reset policy, and capacity change behind it.

Operators get one place to manage Pools, accounts, API keys, saved resets, routing, request accounting, audit logs, and health without storing prompts, files, audio, images, bearer tokens, or raw Codex secrets. Instance owners keep the global administration surface, while instance admins work only with their assigned Pools.

Highlights

  • 🔑 Stable Pool API keys: give clients one Pool credential whether the Pool currently has one upstream account or several, without distributing raw Codex account material
  • 🎯 Eligibility-aware routing: route each request to an account with compatible model support, usable quota evidence, matching health, session state, and Pool policy
  • 🧩 Codex backend compatibility: point Codex-compatible clients at Codex Pooler and keep responses, compacting, usage, files, audio, images, and backend websocket flows working through assigned accounts
  • 🔌 OpenAI-compatible SDK surface: let /v1-only apps and agent tools use Codex capacity through the same Pool boundary, with supported requests translated and routed to help contain API spend
  • 🔁 Session-aware websockets: keep resumable Codex sessions and websocket reconnects attached to the right upstream account without translating backend websocket traffic through an HTTP compatibility layer
  • Prompt-cache locality: use a transient prompt_cache_key to prefer the same eligible upstream account for repeat stateless requests, improving provider-side cache locality without storing prompts or responses locally
  • 🗜️ Per-Pool request compression: optionally compress upstream-bound Responses tool outputs before dispatch on supported request routes. The option is disabled by default, request-side only, and records safe aggregate savings without storing raw outputs.
  • 🏦 Saved reset management: surface reported saved reset capacity on upstream accounts, show informational expirations when available, and let operators queue account-level recovery or opt into guarded auto-redemption policy
  • 🚨 Operator alerting: define Pool-aware rules for capacity, upstream health, saved reset events, and delivery failures, then notify operators through admin incidents, email, or webhooks without exposing raw request content
  • 🖥️ Operator dashboard: manage Pool-scoped accounts, API keys, invites, saved resets, usage, request logs, audit logs, MCP access, and the owner-only jobs, operators, and system settings surfaces
  • 🔭 Per-key Observatory: switch on read-only Observatory access for any Pool API key and its holder gets a live, self-service dashboard of just that key's usage, models, latency, cache, and spend — a monitor-friendly view to keep on a second screen, with no operator controls or other keys in reach
  • 🛡️ Privacy-minded observability: store request, routing, and audit metadata without storing prompts, file bodies, audio, images, bearer tokens, cookies, raw Codex account tokens, or raw API keys
  • ⚙️ Configurable without code changes: tune Pool policy, gateway defaults, diagnostics, model support, limits, and operational settings from the admin UI
  • 🐳 Built for self-hosting: run on Elixir/Erlang's fault-tolerant runtime, start locally with Docker Compose, or deploy the Helm chart with separate web, worker, scheduler, and migration roles for Kubernetes-friendly, multinode growth

Harness Configuration

Keep Pool API keys in environment variables when the harness supports secret expansion. The /mcp endpoint is an optional operator-only add-on for metadata inspection; Codex Pooler runtime clients do not need it. If a desktop harness persists remote MCP headers in its own private settings, use a dedicated operator-scoped MCP token. For a local instance, the URLs are:

Codex backend base URL:      http://localhost:4000/backend-api/codex
OpenAI SDK base URL:         http://localhost:4000/v1
Optional operator MCP URL:   http://localhost:4000/mcp

For a deployed instance, replace http://localhost:4000 with your deployed host, for example https://codex-pooler.example.com.

Codex Pooler OpenCode integration

OpenCode talks to Codex Pooler through the OpenAI-compatible /v1 surface. Keep the provider id as openai for this setup so OpenCode continues to use its OpenAI provider-family behavior. The provider uses the Pool API key, and the optional remote MCP entry uses an operator-owned MCP token. MCP is not required for OpenCode to use Codex Pooler; it only gives an operator MCP host read-only metadata tools. Its websocket support is the narrow Responses websocket route at GET /v1/responses, not OpenAI Realtime SDK compatibility.

{
  "$schema": "https://opencode.ai/config.json",
  "small_model": "openai/gpt-5.6-luna",
  "compaction": {
    "auto": true,
    "reserved": 20000
  },
  "provider": {
    "openai": {
      "npm": "@ai-sdk/openai",
      "name": "Codex Pooler",
      "options": {
        "baseURL": "http://localhost:4000/v1",
        "apiKey": "{env:CODEX_POOLER_API_KEY}"
      },
      "models": {
        "gpt-5.6-luna": {
          "id": "gpt-5.6-luna",
          "name": "GPT-5.6 Luna",
          "family": "gpt",
          "attachment": true,
          "reasoning": true,
          "tool_call": true,
          "temperature": false,
          "options": {
            "reasoningEffort": "high",
            "reasoningSummary": "auto",
            "textVerbosity": "medium",
            "include": ["reasoning.encrypted_content"],
            // Optional: priority processing may cost more than the default tier.
            // "serviceTier": "priority"
          },
          "modalities": {
            "input": ["text", "image"],
            "output": ["text"]
          },
          "limit": {
            "context": 258400,
            "input": 252560,
            "output": 64000
          }
        },
        "gpt-5.6-terra": {
          "id": "gpt-5.6-terra",
          "name": "GPT-5.6 Terra",
          "family": "gpt",
          "attachment": true,
          "reasoning": true,
          "tool_call": true,
          "temperature": false,
          "options": {
            "reasoningEffort": "high",
            "reasoningSummary": "auto",
            "textVerbosity": "medium",
            "include": ["reasoning.encrypted_content"],
            // Optional: priority processing may cost more than the default tier.
            // "serviceTier": "priority"
          },
          "modalities": {
            "input": ["text", "image"],
            "output": ["text"]
          },
          "limit": {
            "context": 258400,
            "input": 252560,
            "output": 64000
          }
        },
        "gpt-5.6-sol": {
          "id": "gpt-5.6-sol",
          "name": "GPT-5.6 Sol",
          "family": "gpt",
          "attachment": true,
          "reasoning": true,
          "tool_call": true,
          "temperature": false,
          "options": {
            "reasoningEffort": "high",
            "reasoningSummary": "auto",
            "textVerbosity": "medium",
            "include": ["reasoning.encrypted_content"],
            // Optional: priority processing may cost more than the default tier.
            // "serviceTier": "priority"
          },
          "modalities": {
            "input": ["text", "image"],
            "output": ["text"]
          },
          "limit": {
            "context": 258400,
            "input": 252560,
            "output": 64000
          }
        }
      }
    }
  },
  // Optional operator-only MCP metadata add-on. Omit for normal model/runtime use.
  "mcp": {
    "codex_pooler": {
      "type": "remote",
      "url": "http://localhost:4000/mcp",
      "oauth": false,
      "headers": {
        "Authorization": "Bearer {env:CODEX_POOLER_MCP_KEY}"
      },
      "enabled": true,
      "timeout": 30000
    }
  }
}

Define only models that your assigned Pool can serve. For deployed instances, change baseURL to https://codex-pooler.example.com/v1; if you keep the optional operator MCP entry, change its url to https://codex-pooler.example.com/mcp.

OpenCode uses small_model for background helpers such as automatic session titles. Without an explicit override, it may infer a nano model that Codex Pools do not serve. Point small_model at a lightweight model that is actually assigned to your Pool; the setting also remains effective when OMO is loaded.

Request-time OpenAI options belong under each model's options block. Keep only connection settings such as baseURL and apiKey in provider-level options. The commented serviceTier line shows how to opt into priority processing. Enable it only when your Pool and upstream offer it and you intentionally accept the potentially higher cost; leave it commented to use the default tier. Do not add store: Codex Pooler sets store: false on its upstream streaming request.

OpenCode subtracts its compaction reserve from limit.input before deciding a conversation is full. These examples set limit.input to 252560 and reserve 20000, so OpenCode starts compaction at 232560 tokens: the same automatic compaction boundary Codex publishes for GPT-5.6. limit.input is the local pre-compaction boundary, not a simultaneous input-plus-output envelope. OpenCode's request layer caps output at 32k by default; set OPENCODE_EXPERIMENTAL_OUTPUT_TOKEN_MAX=64000 only if you want OpenCode to request the full 64k cap.

Oh My OpenAgent (OMO)

If you use Oh My OpenAgent, keep the native openai provider configuration above and add agent/category overrides in ~/.config/opencode/oh-my-openagent.jsonc. A balanced three-tier routing map is:

Primary tier Agents and categories Fallback
gpt-5.6-luna librarian, explore, quick, unspecified-low gpt-5.6-terra with the same reasoning variant
gpt-5.6-terra sisyphus, multimodal-looker, atlas, sisyphus-junior, visual-engineering, unspecified-high, writing gpt-5.6-sol with the same reasoning variant
gpt-5.6-sol hephaestus, oracle, prometheus, metis, momus, ultrabrain, deep, artistry gpt-5.6-terra with the same reasoning variant

Explicit fallback_models keep OMO retries inside the model ids served by the assigned Pool instead of falling through to older built-in model chains. The OpenCode client guide contains the complete copyable OMO configuration and validation commands.

Codex Pooler integration for Codex CLI and Codex Desktop

Codex CLI and Codex Desktop should use the backend compatibility route, not the /v1 SDK route. They share the same Codex configuration layers and user-level CODEX_HOME/config.toml, so one Codex Pooler provider block can serve the terminal and desktop/IDE experience. Keep the provider id as codex-pooler-ws, but keep the provider name exactly OpenAI. 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.

Put provider and auth settings in the user-level config file. 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'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.

Use the websocket provider for normal Codex CLI and Codex Desktop backend behavior:

model_provider = "codex-pooler-ws"

[model_providers.codex-pooler-ws]
name = "OpenAI"
base_url = "http://localhost:4000/backend-api/codex"
env_key = "CODEX_POOLER_API_KEY"
wire_api = "responses"
supports_websockets = true
requires_openai_auth = true

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 = "http://localhost:4000/backend-api/codex"
env_key = "CODEX_POOLER_API_KEY"
wire_api = "responses"
supports_websockets = false
requires_openai_auth = true

For deployed instances, change base_url to https://codex-pooler.example.com/backend-api/codex.

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 does not need explicit client-side context overrides. If you must pin gpt-5.6-terra before Codex has refreshed backend metadata, use Codex's raw window fields: model_context_window = 272000 and model_auto_compact_token_limit = 232560. Codex computes an effective 95% turn budget, so the client-visible budget is 258400 tokens, and it does not send an OpenAI SDK-style output cap on normal /responses turns.

Optional operator-only MCP metadata add-on. Omit for normal Codex runtime use:

[mcp_servers.codex_pooler]
url = "http://localhost:4000/mcp"
bearer_token_env_var = "CODEX_POOLER_MCP_KEY"

For deployed instances, change the optional MCP url to https://codex-pooler.example.com/mcp.

Codex filters resumable conversations by model_provider. 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)

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' {} +; fi
for db in "$HOME"/.codex/state_*.sqlite(N); do sqlite3 "$db" "UPDATE threads SET model_provider = 'codex-pooler-ws' WHERE model_provider = 'openai';"; done

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' {} +; fi
for db in "$HOME"/.codex/state_*.sqlite; do [ -e "$db" ] || continue; sqlite3 "$db" "UPDATE threads SET model_provider = 'codex-pooler-ws' WHERE model_provider = 'openai';"; done

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

Codex Pooler OpenClaw integration

OpenClaw uses openai/* as the canonical OpenAI route. To keep that model name while sending agent turns to Codex Pooler's OpenAI-compatible /v1 surface, point the OpenAI provider at Codex Pooler and use the current OpenClaw runtime id.

{
  agents: {
    defaults: {
      model: {
        primary: "openai/gpt-5.6-terra",
        list: [
          {
            id: "background",
            model: "openai/gpt-5.6-luna",
          },
        ],
      },
      compaction: { reserveTokens: 128000 },
    },
  },
  models: {
    mode: "merge",
    providers: {
      openai: {
        baseUrl: "http://localhost:4000/v1",
        apiKey: "${CODEX_POOLER_API_KEY}",
        api: "openai-responses",
        agentRuntime: { id: "openclaw" },
        timeoutSeconds: 300,
        models: [
          {
            id: "gpt-5.6-luna",
            name: "GPT-5.6 Luna via Codex Pooler",
            reasoning: true,
            input: ["text", "image"],
            contextWindow: 272000,
            contextTokens: 258400,
            maxTokens: 128000,
          },
          {
            id: "gpt-5.6-terra",
            name: "GPT-5.6 Terra via Codex Pooler",
            reasoning: true,
            input: ["text", "image"],
            contextWindow: 272000,
            contextTokens: 258400,
            maxTokens: 128000,
          },
          {
            id: "gpt-5.6-sol",
            name: "GPT-5.6 Sol via Codex Pooler",
            reasoning: true,
            input: ["text", "image"],
            contextWindow: 272000,
            contextTokens: 258400,
            maxTokens: 128000,
          },
        ],
      },
    },
  },
  // Optional operator-only MCP metadata add-on. Omit for normal model/runtime use.
  mcp: {
    servers: {
      codex_pooler: {
        url: "http://localhost:4000/mcp",
        transport: "streamable-http",
        headers: {
          Authorization: "Bearer ${CODEX_POOLER_MCP_KEY}",
        },
      },
    },
  },
}

Define only models that your assigned Pool can serve. For deployed instances, change baseUrl to https://codex-pooler.example.com/v1; if you keep the optional operator MCP add-on, change its url to https://codex-pooler.example.com/mcp.

OpenClaw keeps contextWindow as the provider/native window and uses contextTokens as the effective runtime budget. Codex-served GPT-5.6 examples use the Codex raw 272k window, the 258400 effective budget, and a 128k output budget; the explicit compaction reserve keeps local prompt history under the remaining 130400-token budget before a long completion. Use gpt-5.6-luna for background routing, keep gpt-5.6-terra as the primary model, and switch a session to gpt-5.6-sol only for heavy reasoning.

If you prefer to keep Codex Pooler separate from OpenClaw's built-in OpenAI provider behavior, use a custom provider id such as codex-pooler/gpt-5.6-terra instead. That follows OpenClaw's generic custom-provider shape, but tools that look specifically for openai/gpt-* model refs will not see it as canonical OpenAI.

Codex Pooler Hermes Agent integration

Hermes works best through its openai-api provider with the Responses transport forced explicitly. This is the recommended Codex Pooler setup. Keep the Pool API key in ~/.hermes/.env and point the provider config at Codex Pooler's /v1 surface. Include Hermes' image_gen block when you want image generation or edits through the same OpenAI-compatible path. The mcp_servers block is an optional operator-only add-on for read-only metadata tools; Codex Pooler works without it.

OPENAI_API_KEY=<pool-api-key>
OPENAI_BASE_URL=http://localhost:4000/v1
# Optional operator-only MCP metadata add-on:
CODEX_POOLER_MCP_KEY=<operator-mcp-token>
model:
  default: gpt-5.6-terra
  provider: openai-api
  base_url: http://localhost:4000/v1
  api_mode: codex_responses
  context_length: 258400
  supports_vision: true

agent:
  image_input_mode: native

image_gen:
  provider: openai
  model: gpt-image-2-medium

auxiliary:
  compression:
    timeout: 900

# Optional operator-only MCP metadata add-on. Omit for model/runtime use.
mcp_servers:
  codex_pooler:
    url: http://localhost:4000/mcp
    headers:
      Authorization: "Bearer ${CODEX_POOLER_MCP_KEY}"
    enabled: true
    timeout: 120
    connect_timeout: 15

Image generation note: image_gen.provider: openai is the recommended image provider for this setup. Hermes exposes gpt-image-2-low, gpt-image-2-medium, and gpt-image-2-high as quality tiers; for example, gpt-image-2-medium sends gpt-image-2 to the API with quality: medium. This provider uses the OpenAI SDK environment, so OPENAI_API_KEY and OPENAI_BASE_URL must be visible to the running Hermes process, not only to the shell where you edited the config. model.base_url configures Hermes' text/model provider path; the OpenAI image provider still needs the SDK environment so image requests go through Codex Pooler's /v1 surface instead of OpenAI directly.

If text requests work but image generation fails with invalid_api_key, check the environment of the long-running Hermes process or gateway service first. It may not have loaded OPENAI_BASE_URL, so the OpenAI SDK image client may be using OpenAI's default endpoint instead of Codex Pooler.

Current Codex Pooler releases also expose an SDK-readable context_length value on /v1/models, derived from the effective Codex context_window metadata, so Hermes' automatic probes can resolve the Pooler window. For the GPT-5.6 examples here, use the Codex raw 272000 window and the 258400 effective advertised value. Keep context_length: 258400 in Hermes config as an explicit override when Hermes cannot read /v1/models first.

Hermes context compression uses its own auxiliary request timeout. Keep auxiliary.compression.timeout: 900 so large retained contexts can finish instead of cycling through the older 120-second compression budget. This is independent from the optional MCP server timeout.

Remote HTTP MCP servers require Hermes' mcp extra. If hermes mcp test codex_pooler reports mcp.client.streamable_http is not available, install MCP support into the Hermes environment, following the Hermes MCP Integration docs, and rerun the test.

Check the one-shot model path:

hermes -z 'Reply with exactly: hermes openai api ok' --ignore-rules

Hermes can also be made to use its openai-codex provider against Codex Pooler, but this alternate path is less direct because Hermes treats openai-codex as an OAuth provider by default; add a Pool API key credential ahead of any existing device-code credential and keep the entry's base_url on /v1. Use this only when you specifically need Hermes' openai-codex credential-pool behavior; the openai-api configuration above is the preferred setup. This variant stores the key in auth.json because Hermes credential pools live there.

HERMES_CODEX_BASE_URL=http://localhost:4000/v1
# Optional operator-only MCP metadata add-on:
CODEX_POOLER_MCP_KEY=<operator-mcp-token>
model:
  default: gpt-5.6-terra
  provider: openai-codex
  base_url: http://localhost:4000/v1
  context_length: 258400
  supports_vision: true

agent:
  image_input_mode: native

auxiliary:
  compression:
    timeout: 900

# Optional operator-only MCP metadata add-on. Omit for model/runtime use.
mcp_servers:
  codex_pooler:
    url: http://localhost:4000/mcp
    headers:
      Authorization: "Bearer ${CODEX_POOLER_MCP_KEY}"
    enabled: true
    timeout: 120
    connect_timeout: 15
{
  "active_provider": "openai-codex",
  "credential_pool": {
    "openai-codex": [
      {
        "label": "codex-pooler",
        "auth_type": "api_key",
        "priority": -10,
        "source": "manual",
        "access_token": "<pool-api-key>",
        "base_url": "http://localhost:4000/v1"
      }
    ]
  }
}

For deployed instances, change the model URLs to https://codex-pooler.example.com/v1; if you keep the optional operator MCP add-on, change the MCP url to https://codex-pooler.example.com/mcp.

Pi works best through a custom provider that uses Codex Pooler's narrow OpenAI-compatible /v1 Responses surface. Put custom providers and models in ~/.pi/agent/models.json; put global defaults in ~/.pi/agent/settings.json; use .pi/settings.json for project overrides; and keep saved trust decisions in ~/.pi/agent/trust.json. On Windows, use the same home-relative paths under the user profile, for example %USERPROFILE%\.pi\agent\models.json.

Install Pi from npm so you get the latest published CLI:

npm install -g --ignore-scripts @earendil-works/pi-coding-agent

Then add a provider to ~/.pi/agent/models.json:

{
  "providers": {
    "codex-pooler": {
      "name": "Codex Pooler",
      "baseUrl": "http://localhost:4000/v1",
      "api": "openai-responses",
      "apiKey": "$CODEX_POOLER_API_KEY",
      "authHeader": true,
      "models": [
        {
          "id": "gpt-5.6-luna",
          "name": "GPT-5.6 Luna via Codex Pooler",
          "reasoning": true,
          "thinkingLevelMap": {
            "xhigh": "xhigh"
          },
          "input": ["text", "image"],
          "contextWindow": 258400,
          "maxTokens": 128000
        },
        {
          "id": "gpt-5.6-terra",
          "name": "GPT-5.6 Terra via Codex Pooler",
          "reasoning": true,
          "thinkingLevelMap": {
            "xhigh": "xhigh"
          },
          "input": ["text", "image"],
          "contextWindow": 258400,
          "maxTokens": 128000
        },
        {
          "id": "gpt-5.6-sol",
          "name": "GPT-5.6 Sol via Codex Pooler",
          "reasoning": true,
          "thinkingLevelMap": {
            "xhigh": "xhigh"
          },
          "input": ["text", "image"],
          "contextWindow": 258400,
          "maxTokens": 128000
        }
      ]
    }
  }
}

authHeader: true makes Pi send the Pool API key as Authorization: Bearer .... Define only model ids your assigned Pool can serve. For deployed instances, change baseUrl to https://codex-pooler.example.com/v1.

Current Pi source still requires the explicit thinkingLevelMap entry for Pi to expose xhigh in the model picker and footer. Without it, Pi treats xhigh as unsupported for a custom model and clamps --thinking xhigh or defaultThinkingLevel: "xhigh" to high.

Pi accepts contextWindow and maxTokens for custom models; it has no contextTokens field. Use a 258.4k context window and 128k output budget for the GPT-5.6 custom entries so Pi's local context accounting matches Codex Pooler's advertised model metadata. The explicit compaction reserve makes Pi compact before a prompt plus a long completion can exceed that 258.4k window.

Optionally set Codex Pooler as the default Pi model in ~/.pi/agent/settings.json:

{
  "defaultProvider": "codex-pooler",
  "defaultModel": "gpt-5.6-terra",
  "defaultThinkingLevel": "xhigh",
  "enabledModels": [
    "codex-pooler/gpt-5.6-luna",
    "codex-pooler/gpt-5.6-terra",
    "codex-pooler/gpt-5.6-sol"
  ],
  "compaction": {
    "reserveTokens": 128000
  }
}

Check the non-interactive path from a repository:

export CODEX_POOLER_API_KEY=<pool-api-key>
pi --provider codex-pooler \
  --model gpt-5.6-terra \
  --no-session \
  --no-context-files \
  --tools bash \
  -p 'Reply with exactly: pi ok'

Pi does not ship built-in MCP support. Codex Pooler model use does not require MCP; if you need operator metadata, use a separate MCP-capable host with an operator MCP token.

Oh My Pi (OMP) is a Pi fork, but it should be treated as a separate Codex Pooler harness: it has its own package, omp binary, YAML config, and model role defaults. Install the current CLI through Bun:

bun install -g @oh-my-pi/pi-coding-agent

Then add a provider to ~/.omp/agent/models.yml:

providers:
  codex-pooler:
    baseUrl: http://localhost:4000/v1
    api: openai-responses
    apiKey: CODEX_POOLER_API_KEY
    authHeader: true
    remoteCompaction:
      enabled: true
      api: openai-codex-responses
      endpoint: http://localhost:4000/backend-api/codex/responses/compact
      v2StreamingEnabled: true
      v2Endpoint: http://localhost:4000/backend-api/codex/responses
    models:
      - id: gpt-5.6-terra
        name: GPT-5.6 Terra via Codex Pooler
        reasoning: true
        input:
          - text
          - image
        compat:
          streamIdleTimeoutMs: 300000
        contextWindow: 258400
        maxTokens: 128000
      - id: gpt-5.6-luna
        name: GPT-5.6 Luna via Codex Pooler
        reasoning: true
        input:
          - text
          - image
        compat:
          streamIdleTimeoutMs: 300000
        contextWindow: 258400
        maxTokens: 128000
      - id: gpt-5.6-sol
        name: GPT-5.6 Sol via Codex Pooler
        reasoning: true
        input:
          - text
          - image
        compat:
          streamIdleTimeoutMs: 300000
        contextWindow: 258400
        maxTokens: 128000

apiKey: CODEX_POOLER_API_KEY makes OMP resolve that environment variable at runtime. authHeader: true makes OMP send the Pool API key as Authorization: Bearer .... Define only model ids your assigned Pool can serve. For deployed instances, change baseUrl to https://codex-pooler.example.com/v1 and change remoteCompaction.endpoint to https://codex-pooler.example.com/backend-api/codex/responses/compact; change remoteCompaction.v2Endpoint to https://codex-pooler.example.com/backend-api/codex/responses.

Keep remoteCompaction under the codex-pooler provider so /compact remote can use Codex Pooler's backend compact route while normal OMP model traffic stays on the narrow OpenAI-compatible /v1 Responses route. Do not use compaction.remoteEndpoint for this path: OMP reserves that setting for generic summary services that accept {systemPrompt, prompt} JSON, not provider-native Responses compact payloads. In this setup, omp config get compaction.remoteEndpoint should remain (not set); remote capability comes from the provider-level remoteCompaction block in models.yml.

remoteCompaction.v2StreamingEnabled: true lets OMP use the Codex-style streaming compaction path. OMP sends a normal backend Responses request with a terminal compaction_trigger to remoteCompaction.v2Endpoint; Codex Pooler bridges that request to the backend compact route and returns Responses SSE. The V2 flag is not a global compaction setting: keep it inside remoteCompaction.

Current OMP source derives an effort thinking surface, including xhigh, for custom openai-responses models that set reasoning: true. You only need an explicit thinking block if you want to override the inferred effort list, wire mapping, or per-model default level.

OMP accepts contextWindow and maxTokens in models.yml; it does not accept contextTokens. The examples keep the GPT-5.6 tiered models on a 258.4k context window and 128k output budget: gpt-5.6-luna handles lightweight roles, gpt-5.6-terra handles daily agent work, and gpt-5.6-sol is reserved for slow, planning, and design escalation. compaction.reserveTokens: 128000 asks OMP to compact before a prompt plus a long completion can exceed that 258.4k window.

For long tool-heavy OMP sessions, keep mid-turn compaction enabled and persist handoff material to disk. Those settings reduce context-overflow risk, but they cannot repair an OMP client bug that skips its own mid-run compaction check. If an OMP plan appears to restart work after a very large turn, upgrade OMP when a newer release is available and restart or resume the session before treating it as a Codex Pooler routing issue.

compat.streamIdleTimeoutMs: 300000 keeps long OpenAI Responses reasoning turns from being aborted by OMP's semantic-progress idle watchdog while Codex Pooler and the upstream account are still working. Existing OMP sessions need to be restarted or resumed after this config change. As an environment-only override, set PI_OPENAI_STREAM_IDLE_TIMEOUT_MS=300000 before launching omp.

Optionally set Codex Pooler as the default OMP model roles in ~/.omp/agent/config.yml:

startup:
  setupWizard: false
defaultThinkingLevel: xhigh
enabledModels:
  - codex-pooler/gpt-5.6-luna
  - codex-pooler/gpt-5.6-terra
  - codex-pooler/gpt-5.6-sol
modelProviderOrder:
  - codex-pooler
modelRoles:
  default: codex-pooler/gpt-5.6-terra:xhigh
  smol: codex-pooler/gpt-5.6-luna:low
  tiny: codex-pooler/gpt-5.6-luna:minimal
  slow: codex-pooler/gpt-