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

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

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.

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-
No comments yet
Be the first to share your take.