Skip to content
Β 
Β 

Latest commit

Β 

History

1,026 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

codex-lb fork

codex-lb's ChatGPT account-balancing foundation, extended with external integrations and predictable model routing.

Fork of Soju06/codex-lb External integrations Cursor compatible

Upstream codex-lb is a β€œLoad balancer for ChatGPT accounts. Pool multiple accounts, track usage, manage API keys, view everything in a dashboard.”

This fork keeps that native Codex path and adds a model-resolution layer in front of it. Aliases can target native or external models; configured exact-model and prefix matches route selected requests to CLIProxyAPI, OpenRouter, OmniRoute, or Ollama Cloud. Requests without an external match continue through codex-lb's native account pool.

Build from this repository when you want the integration and routing additions described below. Official upstream packages, images, and charts track upstream codex-lb rather than this fork.

How Requests Flow

Clients still call codex-lb. The fork resolves aliases, checks configured integration matches, then either enters an external integration or falls through to the upstream-native Codex path.

flowchart TB
    Clients["Codex CLI Β· Cursor Β· OpenCode<br/>OpenClaw Β· OpenAI SDKs"]

    subgraph Foundation["codex-lb Β· upstream foundation"]
        direction TB
        Gateway["OpenAI-compatible gateway"]
        Core["Pool and load balance multiple ChatGPT accounts<br/>track usage Β· manage API keys Β· dashboard<br/>automatic model sync"]
        Gateway --> Core
    end

    subgraph Additions["Added by this fork"]
        direction TB
        Resolve["Cross-provider model routing<br/>aliases may target native or external models<br/>exact-model and prefix rules select external integrations"]
        Controls["External integration controls<br/>unified request, cost, and savings visibility<br/>Cursor compatibility Β· reasoning-effort overrides"]
        Resolve --- Controls
    end

    Clients --> Gateway
    Core --> Resolve

    subgraph Native["codex-lb Β· upstream foundation"]
        direction TB
        NativePath["Native Codex path"]
        NativeRouting["codex-lb account selection<br/>quota awareness Β· sticky sessions Β· failover"]
        NativeModels["ChatGPT / Codex account pool<br/>OpenAI Codex API"]
        NativePath --> NativeRouting --> NativeModels
    end

    CLI["CLIProxyAPI integration"]
    CLIRouting["CLIProxyAPI-owned provider management<br/>translation Β· OAuth Β· account rotation Β· proxying<br/>token refresh Β· routing Β· failover"]
    CLIModels["Claude Β· Gemini Β· Codex Β· Grok Β· Qwen<br/>and other CLIProxyAPI-supported providers"]
    CLI --> CLIRouting --> CLIModels

    OpenRouter["OpenRouter integration"]
    ORRouting["OpenRouter-owned catalog and provider routing<br/>automatic fallback Β· pass-through pricing<br/>single billing and usage surface"]
    ORModels["Hundreds of models across 70+ providers<br/>major labs Β· specialist inference providers<br/>open-model hosts"]
    OpenRouter --> ORRouting --> ORModels

    OmniRoute["OmniRoute integration"]
    OmniRouting["OmniRoute-owned Smart Combos and routing<br/>account and key cooling Β· layered fallback<br/>provider selection Β· optional token compression"]
    OmniModels["200+ providers Β· 90+ free tiers<br/>free-forever options Β· $0 start<br/>no paid provider API key or card required"]
    OmniRoute --> OmniRouting --> OmniModels

    Ollama["Ollama Cloud integration"]
    OllamaRouting["Ollama API and hosted model execution"]
    OllamaModels["Ollama-hosted cloud models"]
    Ollama --> OllamaRouting --> OllamaModels

    Resolve -->|"No external match<br/>or alias targets native Codex"| NativePath
    Resolve -->|"CLIProxyAPI match"| CLI
    Resolve -->|"OpenRouter match"| OpenRouter
    Resolve -->|"OmniRoute match"| OmniRoute
    Resolve -->|"Ollama Cloud match"| Ollama
Loading

The fork selects the path; it does not absorb the integrated projects' internal responsibilities:

Resolved path Who owns routing after the match What it reaches
Native Codex Upstream codex-lb: ChatGPT account pooling, quota-aware selection, sticky sessions, and failover ChatGPT/Codex accounts and the OpenAI Codex API
CLIProxyAPI Integration CLIProxyAPI: provider and account management, translation, OAuth, account rotation, proxying, token refresh, routing, and failover Claude, Gemini, Codex, Grok, Qwen, and other CLIProxyAPI-supported providers
OpenRouter Integration OpenRouter: large model catalog, provider selection, automatic fallback, pass-through inference pricing, and one billing/usage surface Hundreds of models across 70+ providers, including major labs, specialist inference providers, and open-model hosts
OmniRoute Integration OmniRoute: Smart Combos, account/key cooling, layered fallback, provider selection, and optional token compression 200+ providers, 90+ free tiers, and free-forever options; no paid provider API key or credit card required to start
Ollama Cloud Integration Ollama: hosted model execution through the Ollama API Ollama-hosted cloud models

What This Fork Adds

Upgrade What you get
Unified provider routing Exact model matches and configurable prefixes select CLIProxyAPI, OpenRouter, OmniRoute, or Ollama Cloud without changing client base URLs; unmatched models retain the native Codex path.
Prefix stripping controls Use ergonomic client-facing names like or-deepseek/deepseek-chat or ollama-gpt-oss:120b-cloud, then strip the prefix only on the upstream wire request.
Cursor image (vision) input Accepts the Anthropic-native image content parts Cursor sends and converts them to the shape CLIProxyAPI expects, so screenshots and pasted images work against Claude models without breaking tool calls.
User-configurable model aliases Map friendly client-facing names to concrete native or external models (for example custom_r1 β†’ cc/claude-opus-4-8) from the dashboard.
Per-provider reasoning effort Configure a true reasoning-effort override for CLIProxyAPI, OpenRouter, OmniRoute, or Ollama Cloud. The configured value replaces client-supplied effort; request logs retain requested and effective values.
External Integrations dashboard Configure CLIProxyAPI, OpenRouter, OmniRoute, and Ollama Cloud from one tabbed dashboard card with provider-specific labels, connection tests, discovered models, prefixes, and full-model rules.
OmniRoute integration Route selected OmniRoute models through codex-lb while retaining codex-lb API-key restrictions, request logs, cost tracking, and model discovery around OmniRoute-owned routing.
Cost and savings telemetry Track actual spend, paid-equivalent reference cost, and derived savings for free or discounted external models.
Cursor and Codex compatibility Preserve raw Codex control endpoints, compaction behavior, context-window metadata, model aliases, and sidecar tool/reasoning quirks that real clients depend on.
Integrated operator UI Synthetic provider accounts, normal request-log rows, provider-specific labels, and account-level controls for integrations that expose them.

The Routing Engine

The fork ships a shared resolver for all external integrations. The rules are simple and predictable:

  1. Full model exact match wins globally. If oc/big-pickle is configured as an OmniRoute full model, it routes to OmniRoute even if another provider owns a broader prefix.
  2. Longest prefix wins next. If one provider owns deepseek/ and another owns deepseek/deepseek-, the more specific prefix gets the request.
  3. Each prefix chooses whether to strip. or-deepseek/deepseek-chat can be logged and rate-limited as or-deepseek/deepseek-chat, while OpenRouter receives deepseek/deepseek-chat.
  4. Full model matches are never stripped. Exact model IDs are forwarded as the operator configured them.
  5. The client-facing model stays visible. API-key restrictions, request-limit reservations, request logs, and quota accounting use the effective model the client asked for.

That means one model list can safely mix official Codex models, external provider models, friendly aliases, and provider-prefixed names without moving native account selection into the fork's integration layer.

Routing Examples

Client model Configuration Upstream lane Wire model
gpt-5.4 no external match Native Codex account pool gpt-5.4
claude-sonnet-4-5 CLIProxyAPI prefix claude, strip off CLIProxyAPI claude-sonnet-4-5
or-deepseek/deepseek-chat OpenRouter prefix or-, strip on OpenRouter deepseek/deepseek-chat
oc/big-pickle OmniRoute full model oc/big-pickle OmniRoute oc/big-pickle
ollama-gpt-oss:120b-cloud Ollama prefix ollama-, strip on Ollama Cloud gpt-oss:120b-cloud

What You Can Do With It

  • Put Codex CLI, Cursor, OpenCode, OpenClaw, and OpenAI SDK clients behind one local or hosted endpoint.
  • Keep official Codex account pooling for GPT/Codex models while sending selected models to external providers.
  • Apply each API key's model allowlist, expiration, and token/cost limits across native and external request paths.
  • Test, enable, disable, and tune external integrations from the dashboard instead of editing client configs everywhere.
  • Compare free and discounted external model usage against paid-equivalent reference cost.
  • See native and external requests in one log stream with provider, model, transport, usage, errors, and savings.

External Integrations

Configure integrations in Settings -> External Integrations. Each provider gets its own tab, but the routing rules are shared.

Primary defaults:

# CLIProxyAPI Integration
CODEX_LB_CLAUDE_SIDECAR_ENABLED=false
CODEX_LB_CLAUDE_SIDECAR_BASE_URL=http://127.0.0.1:8317
CODEX_LB_CLAUDE_SIDECAR_MODEL_PREFIXES=claude

# OpenRouter Integration
CODEX_LB_OPENROUTER_SIDECAR_ENABLED=false
CODEX_LB_OPENROUTER_SIDECAR_BASE_URL=https://openrouter.ai/api/v1

# OmniRoute Integration
CODEX_LB_OMNIROUTE_SIDECAR_ENABLED=false
CODEX_LB_OMNIROUTE_SIDECAR_BASE_URL=http://127.0.0.1:20128/v1
CODEX_LB_OMNIROUTE_SIDECAR_SELECTED_MODELS=oc/big-pickle,oc/deepseek-v4-flash-free

# Ollama Cloud Integration
CODEX_LB_OLLAMA_SIDECAR_ENABLED=false
CODEX_LB_OLLAMA_SIDECAR_BASE_URL=https://ollama.com

The dashboard stores API keys encrypted at rest, runs connection tests, shows discovered models, and prevents duplicate full-model or prefix ownership across providers. OmniRoute owns its own provider cooling and dashboard; codex-lb routes to it and records the traffic, but does not manage the OmniRoute process lifecycle.

Cost, Reference Cost, And Savings

This fork separates actual spend from reference value:

  • cost_usd is what the request actually cost.
  • reference_cost_usd is the paid-equivalent price when codex-lb can resolve one.
  • savings_usd is reference_cost_usd - cost_usd, floored at zero.

Free models accessed through OpenRouter or OmniRoute, including curated opaque-free IDs, can show $0.00 actual spend while still reporting the paid-equivalent reference value. Unknown pricing stays null instead of pretending the request was free.

Cursor And Codex Compatibility

This fork includes practical compatibility work for Codex CLI, Cursor, and OpenAI-style clients:

  • Image (vision) input from Cursor works. Cursor sends vision content as Anthropic-native parts ({"type": "image", "source": {"type": "base64", "media_type": ..., "data": ...}}). The fork accepts these in request validation and converts them to the OpenAI image_url data-URL shape (data:<media_type>;base64,<data>) before forwarding to the Claude sidecar, so screenshots and pasted images reach Claude without disturbing the tool-call path. Both base64 and url sources are supported for any image media type.
  • Model aliasing. Map friendly client-facing model names to concrete native or external models (for example custom_r1 β†’ cc/claude-opus-4-8) so Cursor can target a stable name regardless of the underlying provider model.
  • Reasoning-effort overrides per provider. Each integration can force a configured effort over client-supplied values; logs record both the requested and effective effort.
  • Raw Codex control endpoints, including POST /backend-api/codex/memories/trace_summarize, pass through without model rewriting, reasoning injection, API-key model enforcement, or service-tier injection.
  • Compact response handling accepts the official Codex compact shape {"output": [...]}.
  • External model entries advertise context-window metadata so local-provider clients can make better compaction decisions.
  • Context-limit and terminal-compaction paths are tuned so clients can compact long conversations instead of misclassifying the event as an API-key or rate-limit failure.
  • DeepSeek V4 thinking-mode repair is handled server-side for the external chat-completions dispatch paths that need it.

Quick Start From This Fork

git clone https://github.com/vitalNohj/codex-lb.git
cd codex-lb

# Docker from this source checkout
docker build -t codex-lb-fork:local .
docker volume create codex-lb-data
docker network inspect codex-lb-net >/dev/null 2>&1 || docker network create codex-lb-net
docker run -d --name codex-lb \
  --network codex-lb-net \
  -p 2455:2455 -p 1455:1455 \
  -v codex-lb-data:/var/lib/codex-lb \
  codex-lb-fork:local

# or run from source
uv sync
cd frontend && bun install && bun run build && cd ..
uv run fastapi run app/main.py --host 127.0.0.1 --port 2455

Open localhost:2455 β†’ Add account β†’ Done.

If you install from upstream package or image names before this fork publishes its own artifacts, expect upstream behavior rather than the fork-only features listed above.

Remote Setup

When accessing the dashboard remotely for the first time, a bootstrap token is required to set the initial password.

Auto-generated (default): On first startup (no password configured), the server generates a one-time token and prints it to logs:

docker logs codex-lb
# ============================================
#   Dashboard bootstrap token (first-run):
#   <token>
# ============================================

Open the dashboard β†’ enter the token + new password β†’ done. The token is shared across replicas and remains valid until a password is set. In multi-replica setups, replicas must share the same encryption key (the Helm chart default) for restart recovery to work.

Manual token: To use a fixed token instead, set the env var before starting:

docker run -d --name codex-lb \
  -e CODEX_LB_DASHBOARD_BOOTSTRAP_TOKEN=your-secret-token \
  -p 2455:2455 -p 1455:1455 \
  -v codex-lb-data:/var/lib/codex-lb \
  codex-lb-fork:local

Local access (localhost) bypasses bootstrap entirely β€” no token needed.

Client Setup

Point any OpenAI-compatible client at codex-lb. If API key auth is enabled, pass a key from the dashboard as a Bearer token.

Model availability is discovered from the upstream Codex model catalog and can vary by account plan, workspace, rollout, and upstream deprecation state. Prefer the live GET /v1/models or GET /backend-api/codex/models response over a copied static table when configuring clients or API-key model allowlists.

Logo Client Endpoint Config
OpenAI Codex CLI http://127.0.0.1:2455/backend-api/codex ~/.codex/config.toml
OpenCode OpenCode http://127.0.0.1:2455/v1 ~/.config/opencode/opencode.json
OpenClaw OpenClaw http://127.0.0.1:2455/v1 ~/.openclaw/openclaw.json
Python OpenAI Python SDK http://127.0.0.1:2455/v1 Code
OpenAI Codex CLI / IDE Extension

~/.codex/config.toml:

model = "gpt-5.3-codex"
model_reasoning_effort = "xhigh"
model_provider = "codex-lb"

[model_providers.codex-lb]
name = "openai"  # required β€” enables remote /responses/compact. Lowercase since Codex 2026-05-23; older "OpenAI" stops resolving gpt-5.5
base_url = "http://127.0.0.1:2455/backend-api/codex"
wire_api = "responses"
supports_websockets = true
requires_openai_auth = true # required for codex app

Optional: enable native upstream WebSockets for Codex streaming while keeping codex-lb pooling:

export CODEX_LB_UPSTREAM_STREAM_TRANSPORT=websocket

auto is the default and uses native WebSockets for native Codex headers or models that prefer them. You can also switch this in the dashboard under Settings -> Routing -> Upstream stream transport.

Note: Codex itself does not currently expose a stable documented wire_api = "websocket" provider mode. If you want to experiment on the Codex side, the current CLI exposes under-development feature flags:

[features]
responses_websockets = true
# or
responses_websockets_v2 = true

These flags are experimental and do not replace wire_api = "responses".

Upstream websocket handshakes automatically honor standard proxy environment variables when they are present. wss:// handshakes check wss_proxy, socks_proxy, https_proxy, and all_proxy; plain ws:// handshakes also check ws_proxy and http_proxy. Set CODEX_LB_UPSTREAM_WEBSOCKET_TRUST_ENV=false only when websocket handshakes must bypass those environment proxies and connect directly.

With API key auth:

[model_providers.codex-lb]
name = "openai"
base_url = "http://127.0.0.1:2455/backend-api/codex"
wire_api = "responses"
env_key = "CODEX_LB_API_KEY"
supports_websockets = true
requires_openai_auth = true # required for codex app
export CODEX_LB_API_KEY="sk-clb-..."   # key from dashboard
codex

Verify WebSocket transport

Use a one-off debug run:

RUST_LOG=debug codex exec "Reply with OK only."

Healthy websocket signals:

  • CLI logs contain connecting to websocket and successfully connected to websocket
  • codex-lb logs show WebSocket /backend-api/codex/responses
  • codex-lb logs do not show fallback POST /backend-api/codex/responses for the same run

If you run codex-lb behind a reverse proxy, make sure it forwards WebSocket upgrades.

Migrating from direct OpenAI β€” codex resume filters by model_provider; old sessions won't appear until you re-tag them. Use the built-in retag command instead of editing Codex files by hand; see Codex session retagging for backups, Docker, WSL, and rollback details.

# Preview what will change first.
codex-lb codex-sessions retag --from openai --to codex-lb --dry-run

# Then close Codex/Codex CLI and apply the retag.
codex-lb codex-sessions retag --from openai --to codex-lb --yes
OpenCode OpenCode

Important: Use the built-in openai provider with baseURL override β€” not a custom provider with @ai-sdk/openai-compatible. Custom providers use the Chat Completions API which drops reasoning/thinking content. The built-in openai provider uses the Responses API, which properly preserves encrypted_content and multi-turn reasoning state.

Before starting, please ensure that all existing OpenAI credentials is cleared in ~/.local/share/opencode/auth.json You can clean the config by using this one-liner jq 'del(.openai)' ~/.local/share/opencode/auth.json > auth.json.tmp && mv auth.json.tmp ~/.local/share/opencode/auth.json

~/.config/opencode/opencode.json:

{
  "$schema": "https://opencode.ai/config.json",
  "provider": {
    "openai": {
      "options": {
        "baseURL": "http://127.0.0.1:2455/v1",
        "apiKey": "{env:CODEX_LB_API_KEY}"
      },
      "models": {
        "gpt-5.4": {
          "name": "GPT-5.4",
          "reasoning": true,
          "options": { "reasoningEffort": "high", "reasoningSummary": "detailed" },
          "limit": { "context": 1050000, "output": 128000 }
        },
        "gpt-5.3-codex": {
          "name": "GPT-5.3 Codex",
          "reasoning": true,
          "options": { "reasoningEffort": "high", "reasoningSummary": "detailed" },
          "limit": { "context": 272000, "output": 65536 }
        },
        "gpt-5.1-codex-mini": {
          "name": "GPT-5.1 Codex Mini",
          "reasoning": true,
          "options": { "reasoningEffort": "high", "reasoningSummary": "detailed" },
          "limit": { "context": 272000, "output": 65536 }
        },
        "gpt-5.3-codex-spark": {
          "name": "GPT-5.3 Codex Spark",
          "reasoning": true,
          "options": { "reasoningEffort": "xhigh", "reasoningSummary": "detailed" },
          "limit": { "context": 128000, "output": 65536 }
        }
      }
    }
  },
  "model": "openai/gpt-5.3-codex"
}

This overrides the built-in openai provider's endpoint to point at codex-lb while keeping the Responses API code path that handles reasoning properly.

export CODEX_LB_API_KEY="sk-clb-..."   # key from dashboard
opencode
OpenClaw OpenClaw

~/.openclaw/openclaw.json:

{
  "agents": {
    "defaults": {
      "model": { "primary": "codex-lb/gpt-5.4" },
      "models": {
        "codex-lb/gpt-5.4": { "params": { "cacheRetention": "short" } }
        "codex-lb/gpt-5.4-mini": { "params": { "cacheRetention": "short" } }
        "codex-lb/gpt-5.3-codex": { "params": { "cacheRetention": "short" } }
      }
    }
  },
  "models": {
    "mode": "merge",
    "providers": {
      "codex-lb": {
        "baseUrl": "http://127.0.0.1:2455/v1",
        "apiKey": "${CODEX_LB_API_KEY}",   // or "dummy" if API key auth is disabled
        "api": "openai-responses",
        "models": [
          {
            "id": "gpt-5.4",
            "name": "gpt-5.4 (codex-lb)",
            "contextWindow": 1050000,
            "contextTokens": 272000,
            "maxTokens": 4096,
            "input": ["text"],
            "reasoning": false
          },
          {
            "id": "gpt-5.4-mini",
            "name": "gpt-5.4-mini (codex-lb)",
            "contextWindow": 400000,
            "contextTokens": 272000,
            "maxTokens": 4096,
            "input": ["text"],
            "reasoning": false
          },
          {
            "id": "gpt-5.3-codex",
            "name": "gpt-5.3-codex (codex-lb)",
            "contextWindow": 400000,
            "contextTokens": 272000,
            "maxTokens": 4096,
            "input": ["text"],
            "reasoning": false
          }
        ]
      }
    }
  }
}

Set the env var or replace ${CODEX_LB_API_KEY} with a key from the dashboard. If API key auth is disabled, local requests can omit the key, but non-local requests are still rejected until proxy authentication is configured.

The /v1 route is the simplest OpenAI-compatible setup. If your OpenClaw build uses a Codex-native provider path such as openai-codex-responses and needs Codex-style usage/accounting behavior, point that provider at http://127.0.0.1:2455/backend-api/codex instead. For third-party Codex-compatible backends, the client must allow opaque bearer-token passthrough and should only send chatgpt-account-id when it actually decoded one from an official ChatGPT/Codex token.

Python OpenAI Python SDK
from openai import OpenAI

client = OpenAI(
    base_url="http://127.0.0.1:2455/v1",
    api_key="sk-clb-...",  # from dashboard, or any non-empty string if auth is disabled
)

response = client.chat.completions.create(
    model="gpt-5.3-codex",
    messages=[{"role": "user", "content": "Hello!"}],
)
print(response.choices[0].message.content)

API Key Authentication

API key auth is disabled by default. In that mode, only local requests to the protected proxy routes can proceed without a key; non-local requests are rejected until proxy authentication is configured. Enable it in Settings β†’ API Key Auth on the dashboard when clients connect remotely or through Docker, VM, or container networking that appears non-local to the service.

When enabled, clients must pass a valid API key as a Bearer token:

Authorization: Bearer sk-clb-...

The protected proxy routes covered by this setting are:

  • /v1/* (except /v1/usage, which always requires a valid key)
  • /backend-api/codex/*
  • /backend-api/transcribe

Creating keys: Dashboard β†’ API Keys β†’ Create. The full key is shown only once at creation. Keys support optional expiration, model restrictions, and rate limits (tokens / cost per day / week / month).

Configuration

Environment variables with CODEX_LB_ prefix or .env.local. See .env.example. SQLite is the default database backend; PostgreSQL is optional via CODEX_LB_DATABASE_URL (for example postgresql+asyncpg://...).

The Docker Compose postgres profile uses the Postgres 18 image and mounts the named data volume at /var/lib/postgresql, the parent of the image's versioned PGDATA directory.

Existing Postgres 16 compose volumes must be upgraded before the Postgres 18 container starts:

docker compose --profile postgres stop postgres
docker run --rm -v codex-lb-postgres-data:/var/lib/postgresql -v "$PWD:/backup" alpine \
  tar -C /var/lib/postgresql -czf /backup/codex-lb-postgres-data-before-pg18.tgz .
docker compose --profile postgres-upgrade run --rm postgres-upgrade
docker compose --profile postgres up -d postgres

The postgres-upgrade profile runs pg_upgrade in one-shot mode against the same named volume and exits after the data directory has been upgraded to the Postgres 18 layout. Because that helper mounts and rewrites the operator's database volume, Compose pins the helper image by digest; refresh and review the digest deliberately when changing the helper image tag. Keep the backup until the application has started and codex-lb-db check succeeds against the upgraded database.

The normal postgres service refuses to start when it detects the old root-level PG_VERSION file from a pre-18 Compose volume. If that guard fires, run the postgres-upgrade profile above before starting Postgres again. It also refuses nested /var/lib/postgresql/data directories that still report a pre-18 major version, because those layouts need an explicit pg_upgrade before the Postgres 18 container can safely open them.

Dashboard authentication modes

codex-lb supports three dashboard auth modes via environment variables:

  • CODEX_LB_DASHBOARD_AUTH_MODE=standard β€” built-in dashboard password with optional TOTP from the Settings page.
  • CODEX_LB_DASHBOARD_AUTH_MODE=trusted_header β€” trust a reverse-proxy auth header such as Authelia's Remote-User, but only from CODEX_LB_FIREWALL_TRUSTED_PROXY_CIDRS. Built-in password/TOTP remain available as an optional fallback, and password/TOTP management still requires a fallback password session.
  • CODEX_LB_DASHBOARD_AUTH_MODE=disabled β€” fully bypass dashboard auth. Use only behind network restrictions or external auth. Built-in password/TOTP management is disabled in this mode.

trusted_header mode also requires:

CODEX_LB_FIREWALL_TRUST_PROXY_HEADERS=true
CODEX_LB_FIREWALL_TRUSTED_PROXY_CIDRS=172.18.0.0/16
CODEX_LB_DASHBOARD_AUTH_PROXY_HEADER=Remote-User

If the trusted header is missing and no fallback password is configured, the dashboard fails closed and shows a reverse-proxy-required message instead of loading the UI.

Docker examples

Authelia / trusted header

docker run -d --name codex-lb \
  -p 2455:2455 -p 1455:1455 \
  -e CODEX_LB_DASHBOARD_AUTH_MODE=trusted_header \
  -e CODEX_LB_DASHBOARD_AUTH_PROXY_HEADER=Remote-User \
  -e CODEX_LB_FIREWALL_TRUST_PROXY_HEADERS=true \
  -e CODEX_LB_FIREWALL_TRUSTED_PROXY_CIDRS=172.18.0.0/16 \
  -v codex-lb-data:/var/lib/codex-lb \
  codex-lb-fork:local

Hard override / no app-level dashboard auth

docker run -d --name codex-lb \
  -p 2455:2455 -p 1455:1455 \
  -e CODEX_LB_DASHBOARD_AUTH_MODE=disabled \
  -v codex-lb-data:/var/lib/codex-lb \
  codex-lb-fork:local

For Helm, pass the same values through extraEnv.

Data

Environment Path
Local / source ~/.codex-lb/
Docker /var/lib/codex-lb/

Backup this directory to preserve your data.

Troubleshooting

Kubernetes

When testing fork-only features with Helm, override the image repository/tag to an image built from this fork. The upstream chart and image examples may not include these changes unless fork artifacts have been published.

helm install codex-lb oci://ghcr.io/soju06/charts/codex-lb \
  --set postgresql.auth.password=changeme \
  --set config.databaseMigrateOnStartup=true \
  --set migration.schemaGate.enabled=false
kubectl port-forward svc/codex-lb 2455:2455

Open localhost:2455 β†’ Add account β†’ Done.

The Helm chart auto-configures HTTP /responses owner handoff for multi-replica installs using a headless-service DNS name per pod. The default cluster domain is cluster.local; set Helm clusterDomain if your cluster uses a different suffix. Override config.sessionBridgeAdvertiseBaseUrl only if pods must be reached through a different internal address.

For external database, production config, ingress, observability, and more see the Helm chart README.

Fast Mode and service-tier behavior is documented in Responses API compatibility context.

Development

# Docker
docker compose watch

# Local
uv sync && cd frontend && bun install && cd ..
uv run fastapi run app/main.py --reload --no-proxy-headers  # backend :2455
cd frontend && bun run dev                     # frontend :5173

Contributors ✨

Thanks goes to these wonderful people (emoji key):

Soju06
Soju06

πŸ’» ⚠️ 🚧 πŸš‡
Jonas Kamsker
Jonas Kamsker

πŸ’» πŸ› 🚧
Quack
Quack

πŸ’» πŸ› 🚧 🎨
Jill Kok, San Mou
Jill Kok, San Mou

πŸ’» ⚠️ 🚧 πŸ›
PARK CHANYOUNG
PARK CHANYOUNG

πŸ“– πŸ’» ⚠️
Choi138
Choi138

πŸ’» πŸ› ⚠️
LYA⚚CAP⚚OCEAN
LYA⚚CAP⚚OCEAN

πŸ’» ⚠️
DiΓ³genes Castro
DiΓ³genes Castro

πŸ’» ⚠️
Eugene Korekin
Eugene Korekin

πŸ’» πŸ› ⚠️
jordan
jordan

πŸ’» πŸ› ⚠️
DOCaCola
DOCaCola

πŸ› ⚠️ πŸ“–
JoeBlack2k
JoeBlack2k

πŸ’» πŸ› ⚠️
Peter A.
Peter A.

πŸ“– πŸ’» πŸ›
Hannah Markfort
Hannah Markfort

πŸ’» ⚠️
mws-weekend-projects
mws-weekend-projects

πŸ’» ⚠️
Quang Do
Quang Do

πŸ’» ⚠️
Anand Aiyer
Anand Aiyer

πŸ› πŸ’» ⚠️
defin85
defin85

πŸ’» πŸ› ⚠️
Jacky Fong
Jacky Fong

πŸ’» πŸ› πŸ’¬ 🚧 ⚠️
flokosti96
flokosti96

πŸ’» ⚠️
Woonggi Min
Woonggi Min

πŸ’» ⚠️
Yigit Konur
Yigit Konur

πŸ› πŸ’»
Ruben
Ruben

πŸ’» ⚠️ πŸ›
Steve Santacroce
Steve Santacroce

πŸ’» ⚠️ πŸ›
Hugh Do
Hugh Do

πŸ’» ⚠️
Hubert Salwin
Hubert Salwin

πŸ’» ⚠️
Teemu Koskinen
Teemu Koskinen

πŸ“–
Yu Peng Zheng
Yu Peng Zheng

πŸ“– πŸ’»
embogomolov
embogomolov

πŸ’» ⚠️
Renat Sharipov
Renat Sharipov

πŸ’» ⚠️
Liu Rui
Liu Rui

πŸ“– πŸ’» ⚠️ πŸ›
OverHash
OverHash

πŸ’» ⚠️
Kazet
Kazet

πŸ’» ⚠️
Bala Kumar
Bala Kumar

πŸ’» ⚠️ πŸ€”
ihazgithub
ihazgithub

πŸ’» ⚠️
Temirkhan
Temirkhan

πŸ’» ⚠️ πŸ“– πŸ›
tobwen
tobwen

πŸ’» ⚠️ πŸ›
Rio
Rio

πŸ’» πŸ› ⚠️
Mika
Mika

πŸ’» πŸ“– ⚠️
Darafei Praliaskouski
Darafei Praliaskouski

πŸ’» πŸ“– ⚠️ πŸ›
Maxim Feofilov
Maxim Feofilov

πŸ’» ⚠️
JeffKandt
JeffKandt

⚠️ πŸ‘€
klaascommerce
klaascommerce

πŸ’» ⚠️
ozpool
ozpool

πŸ€” πŸ“– πŸ’» ⚠️
Manu
Manu

⚠️ πŸ‘€
Wojtek Majewski
Wojtek Majewski

⚠️
Andrew Noble
Andrew Noble

πŸ’» ⚠️
Josu Gorostegui
Josu Gorostegui

πŸ’» ⚠️
Linus Mixson
Linus Mixson

πŸ’» ⚠️
Lotfree
Lotfree

πŸ’» ⚠️ πŸ“– πŸ›
timefox
timefox

πŸ’» ⚠️
Nikhil
Nikhil

πŸ’» ⚠️
Miha Orazem
Miha Orazem

πŸ’» ⚠️
Steven (Minh) Dang
Steven (Minh) Dang

πŸ“–
onlysdesign-ui
onlysdesign-ui

πŸ’» ⚠️
Mahir Taha Γ–zdin
Mahir Taha Γ–zdin

πŸ€” πŸ’» ⚠️
hikki
hikki

πŸ’» 🎨
Nataprom
Nataprom

πŸ’» ⚠️
Iweisc
Iweisc

πŸ’» ⚠️
ram/haidar
ram/haidar

πŸ’»
Rudra Tiwari
Rudra Tiwari

πŸ’»
Wu Chao
Wu Chao

πŸ’»
zwd0313
zwd0313

πŸ’»
jhordanjw123
jhordanjw123

πŸ’» ⚠️
mastertyko
mastertyko

πŸ’» ⚠️
NeoClaw
NeoClaw

πŸ’»
abarsegov
abarsegov

πŸ’»
Akshay Kakatkar
Akshay Kakatkar

πŸ’» ⚠️
softkleenex
softkleenex

πŸ’» ⚠️
plastictaste
plastictaste

πŸ’» ⚠️ πŸ“–
n3crosis
n3crosis

πŸ’» ⚠️
copilot
copilot

πŸ’»
geoHeil
geoHeil

πŸ’» ⚠️
JonΓ‘Ε‘ Sivek
JonΓ‘Ε‘ Sivek

πŸ’» ⚠️
RubΓ©n PΓ©rez Bachiller
RubΓ©n PΓ©rez Bachiller

πŸ’» ⚠️ πŸ›
Guanwei Chen
Guanwei Chen

πŸ’» ⚠️
jawwadfirdousi
jawwadfirdousi

πŸ’» ⚠️
Quang Do
Quang Do

πŸ’» ⚠️
Abdullah Alzeiby
Abdullah Alzeiby

πŸ’» ⚠️
zvladru
zvladru

πŸ’» ⚠️
anime girl
anime girl

πŸ’» ⚠️
evaldass
evaldass

πŸ’» ⚠️
Claude
Claude

πŸ’»
Shawn
Shawn

πŸ’»
luawl
luawl

πŸ’» ⚠️
knightcn1983
knightcn1983

πŸ’» ⚠️
Hafiy
Hafiy

πŸ’» ⚠️ πŸ“–
Kevin van Zonneveld
Kevin van Zonneveld

πŸ’»
Choong Jun Jin
Choong Jun Jin

πŸ’» ⚠️
Roman Leventov
Roman Leventov

πŸ’»
AliReza Tofighi
AliReza Tofighi

πŸ“–
DOMANHDUC
DOMANHDUC

πŸ’»
Kwan Perry
Kwan Perry

πŸ’»
James
James

πŸ’» ⚠️
SSY
SSY

πŸ’» ⚠️ πŸ“–
Fatih Γ–zbek
Fatih Γ–zbek

πŸ’» ⚠️
Kushida
Kushida

πŸ’» ⚠️
Aidid Haiqal
Aidid Haiqal

πŸ’» ⚠️
yshishenya
yshishenya

πŸ’»
alchemistkiv
alchemistkiv

πŸ’» ⚠️

This project follows the all-contributors specification. Contributions of any kind welcome!

About

Codex/ChatGPT multiple account load balancer & proxy with usage tracking, dashboard, and OpenCode-compatible endpoints

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages