How It Works
Codex speaks the OpenAI Responses API. opencodex accepts POST /v1/responses over HTTP with
Server-Sent Events, plus an opt-in WebSocket upgrade on the same path. It translates the request to
your provider’s wire format and the answer back into Responses events — so Codex never knows it
isn’t talking to OpenAI.
┌──────────────────────────── opencodex ────────────────────────────┐ │ │ Codex ──▶ │ parser ──▶ router ──▶ [vision] ──▶ adapter ──▶ provider │ ──▶ Codex (/v1/ │ │ │ │ │ │ │ (SSE / WS) responses)│ OcxParsed provider describe buildRequest parseStream │ │ Request +adapter images + fetch AdapterEvent[] │ │ │ │ │ │ [web-search loop] bridge ─▶ SSE │ └─────────────────────────────────────────────────────────────────────┘Codex auth account selection
Section titled “Codex auth account selection”When the selected provider is the ChatGPT/Codex passthrough, opencodex can choose a stored pool account before the request is forwarded upstream. The rule is intentionally split:
- Existing thread ids keep affinity. A thread is bound to the account generation that started it, so a long SSH, tmux, or mobile-attached Codex session keeps using one account instead of being rebalanced mid-conversation.
- New sessions can rebalance. For a new thread, opencodex compares known quota usage across 5h, weekly, and 30d windows, skips accounts that need reauthentication or are in cooldown, and can switch to a lower-usage eligible account when the active account crosses the configured threshold.
- Quota and failure signals feed routing. The dashboard can force a quota refresh with
GET /api/codex-auth/accounts?refresh=1; successful upstream responses capture quota headers, 429 puts an account in cooldown, and 401/403 marks it for reauthentication.
Sub-agent model selection
Section titled “Sub-agent model selection”On a fresh install, subagentModels features gpt-5.5, the GPT-5.6 Sol/Terra/Luna trio, and
gpt-5.4-mini in Codex’s sub-agent picker. The dashboard can reorder or replace up to five entries
with native or routed models. For v1 collaboration requests, optional injectionModel and
injectionEffort settings add developer guidance that tells spawn_agent which model and reasoning
effort to use; v2 requests keep Codex’s native multi-agent guidance.
The lifecycle
Section titled “The lifecycle”-
Parse —
responses/parser.tsvalidates the request with a Zod schema (responses/schema.ts) and lowers it into an internalOcxParsedRequest: system prompt, a normalized message list (text, images, tool calls, tool results), the tool definitions, generation options, and feature flags such as_webSearch(hosted web search requested) and_structuredOutput(a JSON schema / JSON-objecttext.formatwas set). Images are preserved as real content parts — never inlined as base64 text. -
Route —
router.tsmaps the requested model id to a configured provider using a fixed precedence: explicitprovider/model→ a provider’sdefaultModel→ built-in prefix patterns (claude-,gpt-,o1-/o3-/o4-,llama-/mixtral-/gemma-) → a provider’smodels[]→ thedefaultProviderfallback. See Model Routing. -
Authenticate — for an
oauthprovider, opencodex swaps in a fresh, auto-refreshed access token as the bearer key, so the existing adapters authenticate unchanged. For ChatGPT/Codex pool accounts,codex/auth-context.tsresolves the account first and the passthrough adapter refuses to continue if the required pool credential is unavailable. -
Vision sidecar (optional) — if the routed model is listed in
provider.noVisionModelsand the request carries an image, opencodex describes each image with the configured ChatGPT vision sidecar and replaces it with text, so a text-only model can still reason about it. See Sidecars. -
Passthrough fast path — if the adapter is a Responses passthrough (
openai-responsesorazure-openai), opencodex keeps the Responses body, applies targeted routing and compatibility rewrites, then relays the provider’s response without converting it throughAdapterEvents. -
Web-search sidecar (optional) — if Codex enabled hosted
web_searchbut the routed model is non-OpenAI, opencodex exposes a syntheticweb_searchfunction tool and runs the model in a small agentic loop, executing real searches throughgpt-5.6-lunaby default over your ChatGPT login and injecting the results back as tool results. -
Compact (when requested) — Codex v1 calls
POST /v1/responses/compact; v2 adds acompaction_triggerto a Responses turn. Native passthrough routes compaction upstream, while a routed model runs as a tool-free summarizer and returns the replacement history shape Codex expects. -
Adapt — otherwise the chosen adapter’s
buildRequest()produces the upstream HTTP request (URL, headers, body) in the provider’s native format, and opencodexfetches it. -
Bridge — the adapter’s
parseStream()(orparseResponse()) yields internalAdapterEvents (text, reasoning, tool-call start/delta/end, done, error).bridge.tsconverts that stream back into Responses SSE events —response.output_text.delta,response.reasoning_summary_text.delta,response.function_call_arguments.delta,response.completed, and so on. The optional WebSocket transport sends the same event payloads as text frames.
Why a proxy and not a Codex fork?
Section titled “Why a proxy and not a Codex fork?”Codex hard-codes the Responses API. By translating at the protocol boundary, opencodex works with the
Codex CLI, App, and SDK unchanged, survives Codex updates, and lets you switch providers per
request without touching Codex itself. The translation is bidirectional and streaming-faithful:
reasoning summaries, MCP tool namespaces, freeform (apply_patch) tools, and tool_search discovery
all round-trip correctly. See the Architecture reference for the
event-by-event mapping.

