Responses API to Chat Completions bridge for OpenAI Codex CLI
Project description
codex-proxy
Responses API to Chat Completions bridge for OpenAI Codex CLI.
Use Codex CLI with any Chat Completions-compatible provider -- Z.AI, Groq, Together AI, OpenRouter, Ollama, Fireworks, Anthropic, Gemini, DeepSeek, Mistral, Cohere, NVIDIA NIM, and more.
Why codex-proxy?
| codex-proxy | LiteLLM | |
|---|---|---|
| Install | pip install codex-proxy |
pip install litellm[proxy] |
| Dependencies | 4 (FastAPI, uvicorn, httpx, tomli) | 50+ |
| Config | Single TOML file | YAML + env vars + DB |
| Start time | <1s | 3-5s |
| Memory | ~30MB | ~200MB+ |
| Dashboard | Built-in TUI (terminal) | Separate Admin UI |
| Circuit Breaker | Per-key + global | Basic |
| Plugins | Built-in hook system | Callbacks only |
If you need 100+ providers and enterprise features, use LiteLLM. If you need a lightweight, reliable proxy with advanced resilience features and a live dashboard, codex-proxy is for you.
Architecture
codex-proxy v4.0.0
┌────────────┐ ┌──────────────────────────┐ ┌──────────────────┐
│ │ │ │ │ │
│ Codex CLI │─────>│ FastAPI server │─────>│ LLM Provider │
│ Cursor │ │ localhost:4242 │ │ (CC endpoint) │
│ Any IDE │ │ │ │ │
│ │<─────│ . Translator │<─────│ Z.AI / Groq / │
└────────────┘ │ . Response Store │ │ Ollama / etc. │
│ . Circuit Breaker │ └──────────────────┘
Responses API │ . Key Rotator │
protocol │ . Compaction Engine │ Chat Completions
│ . Plugin Registry │ protocol
│ . Rate Limiter │
│ . Provider Adapters │
└──────────────────────────┘
Features
Core
- Protocol translation -- Responses API to Chat Completions in real time
- Streaming SSE -- token-by-token delivery with full protocol mapping
- WebSocket support -- full Realtime API envelope handling
- Reasoning passthrough -- forwards thinking/reasoning tokens
- Tool calls -- full function calling support (definitions + results)
- Multi-turn --
previous_response_idvia in-memory response store - Auto-retry -- configurable retries on 5xx/transport errors
- Rate limiting -- per-client sliding window rate limiter
- Admin auth -- optional Bearer token on
/reloadand/statusendpoints - CORS support -- configurable allowed origins
- Request size limits -- configurable max body size (default 10MB)
Reliability
- Circuit breaker -- global fail-fast when upstream is down (configurable threshold + recovery)
- Multi-key rotation -- round-robin across API keys with per-key circuit breakers; auth/rate-limit errors (401/403/429) trip individual keys; 5xx handled by global breaker
- Context compaction -- auto-trims long conversations to stay within model limits
Observability
- Live TUI dashboard -- real-time metrics, circuit breaker state, key pool status, log tail, hotkeys (
rreload,cclear store,tcompact,qquit) - Plugin system -- hook-based middleware (
on_request,on_response,on_error,on_startup,on_shutdown) with built-inLoggingPlugin - Config hot-reload -- reload config without restart via TUI hotkey or
POST /reload
Ecosystem
- 12+ providers -- Z.AI, Groq, Together, OpenRouter, Ollama, Fireworks, Anthropic, Gemini, DeepSeek, Mistral, Cohere, NVIDIA NIM
- Provider adapters -- per-provider header/request normalization
- Docker-ready -- Dockerfile and Compose file included
- pip-installable --
pip install codex-proxy, run withcodex-proxyCLI - 217+ tests -- comprehensive test suite covering all modules
Quick Start
Install
pip install codex-proxy
For the TUI dashboard:
pip install "codex-proxy[tui]"
Configure
codex-proxy --init
# Edit ~/.codex-proxy/config.toml with your provider details
Run
# Standard mode
codex-proxy
# With live dashboard
codex-proxy --tui
Connect Codex CLI
Set the environment variable:
export OPENAI_BASE_URL=http://127.0.0.1:4242
Or edit ~/.codex/config.toml:
model = "glm-5.1"
And set your API key in ~/.codex/auth.json:
{
"auth_mode": "apikey",
"OPENAI_API_KEY": "your-provider-api-key"
}
Then run:
codex --model glm-5.1 "say hello"
TUI Dashboard
Launch with codex-proxy --tui to see a live dashboard:
Hotkeys: r reload config, c clear store, t show compaction info, q quit.
Provider Examples
Z.AI (GLM Models)
[provider]
name = "zai"
display_name = "Z.AI"
base_url = "https://api.z.ai/api/paas/v4"
api_key_env = "OPENAI_API_KEY"
models = ["glm-5.1", "glm-5", "glm-4.7"]
default_model = "glm-5.1"
Groq
[provider]
name = "groq"
display_name = "Groq"
base_url = "https://api.groq.com/openai/v1"
api_key_env = "GROQ_API_KEY"
models = ["llama-4-maverick-17b", "mixtral-8x7b-32768"]
default_model = "llama-4-maverick-17b"
Together AI
[provider]
name = "together"
display_name = "Together AI"
base_url = "https://api.together.xyz/v1"
api_key_env = "TOGETHER_API_KEY"
models = ["meta-llama/Llama-3.3-70B-Instruct-Turbo"]
default_model = "meta-llama/Llama-3.3-70B-Instruct-Turbo"
OpenRouter
[provider]
name = "openrouter"
display_name = "OpenRouter"
base_url = "https://openrouter.ai/api/v1"
api_key_env = "OPENROUTER_API_KEY"
models = ["deepseek/deepseek-chat-v3-0324"]
default_model = "deepseek/deepseek-chat-v3-0324"
Ollama (Local)
[provider]
name = "ollama"
display_name = "Ollama (local)"
base_url = "http://localhost:11434/v1"
api_key = "ollama"
models = ["qwen3:32b", "codellama:34b"]
default_model = "qwen3:32b"
Anthropic
[provider]
name = "anthropic"
display_name = "Anthropic"
base_url = "https://api.anthropic.com/v1"
api_key_env = "ANTHROPIC_API_KEY"
models = ["claude-sonnet-4-20250514"]
default_model = "claude-sonnet-4-20250514"
Google Gemini
[provider]
name = "gemini"
display_name = "Google Gemini"
base_url = "https://generativelanguage.googleapis.com/v1beta/openai"
api_key_env = "GEMINI_API_KEY"
models = ["gemini-2.5-flash"]
default_model = "gemini-2.5-flash"
DeepSeek
[provider]
name = "deepseek"
display_name = "DeepSeek"
base_url = "https://api.deepseek.com/v1"
api_key_env = "DEEPSEEK_API_KEY"
models = ["deepseek-chat", "deepseek-reasoner"]
default_model = "deepseek-chat"
Mistral AI
[provider]
name = "mistral"
display_name = "Mistral AI"
base_url = "https://api.mistral.ai/v1"
api_key_env = "MISTRAL_API_KEY"
models = ["mistral-large-latest"]
default_model = "mistral-large-latest"
Cohere
[provider]
name = "cohere"
display_name = "Cohere"
base_url = "https://api.cohere.com/compatibility/v1"
api_key_env = "CO_API_KEY"
models = ["command-a-03-2025"]
default_model = "command-a-03-2025"
NVIDIA NIM
[provider]
name = "nvidia"
display_name = "NVIDIA NIM"
base_url = "https://integrate.api.nvidia.com/v1"
api_key_env = "NVIDIA_API_KEY"
models = ["nvidia/llama-3.1-nemotron-ultra-253b-v1"]
default_model = "nvidia/llama-3.1-nemotron-ultra-253b-v1"
Fireworks AI
[provider]
name = "fireworks"
display_name = "Fireworks AI"
base_url = "https://api.fireworks.ai/inference/v1"
api_key_env = "FIREWORKS_API_KEY"
models = ["accounts/fireworks/models/llama4-maverick-instruct-basic"]
default_model = "accounts/fireworks/models/llama4-maverick-instruct-basic"
Multi-Key Rotation
Distribute load across multiple API keys with automatic failover:
[provider]
name = "zai"
base_url = "https://api.z.ai/api/paas/v4"
api_keys = ["sk-key1", "sk-key2", "sk-key3"]
# or load from env vars:
# api_keys_env = ["OPENAI_API_KEY_1", "OPENAI_API_KEY_2"]
models = ["glm-5.1"]
default_model = "glm-5.1"
Each key gets its own circuit breaker. Auth errors (401/403/429) trip the individual key; server errors (5xx) are handled by the global circuit breaker. When a key's circuit opens, it's skipped until recovery. If all keys are open, the first key is used as fallback.
Plugin System
Extend codex-proxy with custom middleware:
[plugins]
enabled = true
plugins = [
"codex_proxy.plugins_builtin.LoggingPlugin",
]
Plugins implement async hooks:
from codex_proxy.plugins import Plugin, PluginContext
class MyPlugin(Plugin):
async def on_request(self, ctx: PluginContext) -> None:
# Called before forwarding to provider
pass
async def on_response(self, ctx: PluginContext) -> None:
# Called after successful response
pass
async def on_error(self, ctx: PluginContext) -> None:
# Called on failure
pass
Broken plugins are isolated -- they cannot crash the proxy.
Configuration Reference
Config file: ~/.codex-proxy/config.toml
[server]
| Field | Type | Default | Description |
|---|---|---|---|
host |
string | "127.0.0.1" |
Bind address |
port |
int | 4242 |
Bind port |
log_level |
string | "warning" |
Log verbosity: debug, info, warning, error |
log_dir |
string | ~/.codex-proxy/logs |
Directory for debug log files |
max_retries |
int | 1 |
Retries on 5xx/transport errors |
retry_delay |
float | 0.5 |
Seconds between retries |
connect_timeout |
float | 10.0 |
Seconds to connect to upstream |
read_timeout |
float | 180.0 |
Seconds to wait for upstream response |
admin_token |
string | "" |
Bearer token for /reload and /status (empty = no auth) |
max_request_body_bytes |
int | 10485760 |
Max request body size (10MB) |
cors_origins |
list | [] |
Allowed CORS origins (empty = no CORS headers) |
[store]
| Field | Type | Default | Description |
|---|---|---|---|
ttl_seconds |
int | 600 |
Response cache TTL in seconds (10 min) |
max_entries |
int | 100 |
Maximum cached responses for previous_response_id |
[provider]
| Field | Type | Default | Description |
|---|---|---|---|
name |
string | "zai" |
Provider identifier (used for adapter selection) |
display_name |
string | "Z.AI" |
Human-readable provider name |
base_url |
string | "https://api.z.ai/api/paas/v4" |
Provider Chat Completions endpoint |
api_key |
string | "" |
API key (inline) |
api_key_env |
string | "" |
Environment variable name for the API key |
api_keys |
list | [] |
Multiple API keys for rotation |
api_keys_env |
list | [] |
Env var names for multiple API keys |
models |
list | ["glm-5.1", ...] |
Available model IDs |
default_model |
string | "glm-5.1" |
Default model when none specified |
stream |
bool | true |
Enable streaming by default |
extra_headers |
dict | {} |
Additional HTTP headers per request |
[circuit_breaker]
| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool | true |
Enable/disable circuit breaker |
failure_threshold |
int | 5 |
Consecutive failures before opening |
recovery_timeout |
float | 30.0 |
Seconds before half-open retry |
[compaction]
| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool | true |
Enable/disable context compaction |
max_messages |
int | 50 |
Message count threshold to trigger compaction |
keep_last |
int | 20 |
Number of recent messages to preserve |
[plugins]
| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool | false |
Enable/disable plugin system |
plugins |
list | [] |
Dotted paths to plugin classes |
[rate_limit]
| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool | false |
Enable/disable per-client rate limiting |
max_requests |
int | 60 |
Max requests per client per window |
window_seconds |
int | 60 |
Sliding window duration in seconds |
Environment Variables
| Variable | Description |
|---|---|
CODEX_PROXY_API_KEY |
API key for the provider (highest priority) |
CODEX_PROXY_BASE_URL |
Override provider base URL |
CODEX_PROXY_MODEL |
Override default model name |
OPENAI_API_KEY |
Fallback API key when no config file exists |
OPENAI_BASE_URL |
Point Codex CLI to the proxy (http://127.0.0.1:4242) |
Environment variables are used when ~/.codex-proxy/config.toml does not exist,
enabling zero-config deployment via env vars alone.
Docker
Build and Run
docker build -t codex-proxy .
docker run -d \
-p 4242:4242 \
-e CODEX_PROXY_API_KEY=your-key \
-e CODEX_PROXY_BASE_URL=https://api.z.ai/api/paas/v4 \
-e CODEX_PROXY_MODEL=glm-5.1 \
codex-proxy
Docker Compose
# Set your API key
export CODEX_PROXY_API_KEY=your-key
# Start the proxy
docker compose up -d
# Check health
curl http://localhost:4242/health
The Compose file includes a health check that polls /health every 30 seconds.
API Endpoints
| Endpoint | Method | Description |
|---|---|---|
/responses |
POST | Responses API (HTTP, streaming + non-streaming) |
/responses |
WS | Responses API (WebSocket, full envelope handling) |
/responses/{id} |
GET | Retrieve a stored response by ID |
/models |
GET | List available models |
/v1/models |
GET | List available models (v1 prefix alias) |
/health |
GET | Health check (?check_backend=true pings upstream) |
/status |
GET | Detailed server status (uptime, requests, provider info) |
/reload |
POST | Reload configuration from disk without restart |
CLI Options
codex-proxy Start the proxy server
codex-proxy --tui Start with live TUI dashboard
codex-proxy --port 8080 Override bind port
codex-proxy --host 0.0.0.0 Override bind address
codex-proxy --config PATH Use custom config file
codex-proxy --init Write example config and exit
codex-proxy --print-config Print resolved config and exit
Development
Setup
git clone https://github.com/ZiryaNoov/codex-proxy.git
cd codex-proxy
pip install -e ".[dev,tui]"
Testing
pytest tests/ -v # 217+ tests
Linting & Type Checking
ruff check src/ tests/
mypy src/
Pre-commit Hooks
pre-commit install
Contributing
Contributions are welcome! Please read the Contributing Guide and Code of Conduct.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
MIT -- ZakPro
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file codex_proxy-4.0.0.tar.gz.
File metadata
- Download URL: codex_proxy-4.0.0.tar.gz
- Upload date:
- Size: 638.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1215beb79c0807a838b140d1c8127ef8b98e6178e6f2e952295a7bff029f36a3
|
|
| MD5 |
cc589fb93fdf540d12efe91be30d185c
|
|
| BLAKE2b-256 |
f024e7d6353bcfb3a646cc5f8e67c746482d7491a8ac0438bfac750221b33462
|
File details
Details for the file codex_proxy-4.0.0-py3-none-any.whl.
File metadata
- Download URL: codex_proxy-4.0.0-py3-none-any.whl
- Upload date:
- Size: 34.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8fc37fa8fd49257bb7f5bcb3ea3187bbe6c23b0da386cc55a5af623c1dec041e
|
|
| MD5 |
3d030394e740a0311406f6db4152909e
|
|
| BLAKE2b-256 |
f8766945ed21da74ebf1be0ee45385d8d67e7ef072552f0f98b45030c3d1dc7d
|