codex-proxy-kit is a small toolkit for two common Codex CLI debugging/integration problems:
- running Codex against a non-standard OpenAI-compatible backend such as
vLLM - logging raw
/v1/responsestraffic and SSE streams from an official OpenAI-backed Codex session
The repo contains two independent tools plus lightweight wrappers:
scripts/codex_vllm_responses_proxy.py- compatibility proxy for
Codex CLI -> /v1/responses -> vLLM-compatible backend
- compatibility proxy for
scripts/codex_openai_log_proxy.py- transparent local logging proxy for official OpenAI traffic
scripts/codex-vllm- config-driven wrapper for the vLLM compatibility proxy
scripts/codex-switch- alias for
codex-vllm, intended for interactive multi-model use
- alias for
scripts/codex-openai-log- convenience wrapper for the OpenAI logging proxy
Tested directly with:
codex-cli 0.116.0
Validated assumptions for this version:
- Codex uses the
Responses API - tool execution is driven by
function_call/function_call_output - prefixed tool names such as
functions.exec_commandare rejected by the local dispatcher - Codex expects streamed
/v1/responsestraffic that can be represented as SSE events such asresponse.output_item.added
Older or newer versions may still work, but the vLLM compatibility proxy is intentionally tuned to the behavior of codex-cli 0.116.0.
- reads a JSON model-routing config
- exposes all configured models through one
/v1/modelsendpoint - lets Codex switch models from the interactive
/modelmenu - routes each request by
body.modelto the matching upstream API - launches interactive TUI when called without a prompt or subcommand
- treats plain trailing arguments as
codex execinput for non-interactive runs - normalizes multi-turn
inputitems forResponses API - converts tool names like
functions.exec_commandto bare names likeexec_command - rewrites tool-markup text into structured
function_callitems - can synthesize minimal SSE for streamed
/v1/responses
- logs request bodies sent to
/v1/responses - logs raw JSON responses and raw SSE event streams
- keeps Codex pointing at a local plain HTTP proxy while forwarding upstream to
https://api.openai.com - useful for debugging
web_search, tool calls, and stream event ordering
- Linux or WSL
- Python
3.10+ codexalready installedcodexalready authenticatedrequestsavailable for the OpenAI logging proxy
From inside the repo:
./install.shThat installs wrapper commands into ~/.local/bin:
codex-vllmcodex-switchcodex-openai-log
If ~/.local/bin is not already on your PATH, add:
export PATH="$HOME/.local/bin:$PATH"python3 -m pip install -r requirements.txt
chmod +x scripts/codex-vllm scripts/codex-switch scripts/codex-openai-log \
scripts/codex_vllm_responses_proxy.py scripts/codex_openai_log_proxy.pyThe repo ships with a ready-to-use login002 profile and uses it by default.
If you want your own variant, copy it and edit:
cp profiles/login002.json ~/.config/codex-proxy-kit/login002.jsonExample profile:
{
"default_model": "gpt-5.4",
"models": [
{
"name": "gpt-5.4",
"target_model": "kimi-k2.5",
"upstream_base": "http://gpuh201:8000",
"context_window": 262144,
"aliases": ["kimi-k2.5"]
},
{
"name": "gpt-5.2",
"target_model": "glm-5",
"upstream_base": "http://gpuh202:8000",
"context_window": 131072,
"aliases": ["glm-5"]
},
{
"name": "gpt-5.1-codex-max",
"target_model": "deepseek-v3.2",
"upstream_base": "http://gpuh203:8000",
"context_window": 163840,
"aliases": ["deepseek-v3.2"]
},
{
"name": "gpt-5.1-codex-mini",
"target_model": "minimax-m2.5",
"upstream_base": "http://gpuh204:8000",
"context_window": 196608,
"aliases": ["minimax-m2.5"]
}
]
}For codex-cli 0.116.0, this mapping is intentional:
gpt-5.4->kimi-k2.5gpt-5.2->glm-5gpt-5.1-codex-max->deepseek-v3.2gpt-5.1-codex-mini->minimax-m2.5
This is the most reliable way to make the built-in /model menu switch real non-OpenAI backends without patching Codex itself.
If you use a custom backend name such as kimi-k2.5 directly as the visible name, codex-cli 0.116.0 can emit a metadata fallback warning. The recommended pattern is:
- use a Codex-recognized display name in
name - route to the real backend through
target_model - carry backend-specific limits in fields such as
context_window
Each model entry controls:
- the model name shown inside Codex
/model - the actual upstream
target_model - the upstream API base URL
- optional metadata like
context_window
Start via wrapper:
codex-switchWrapper behavior:
- starts the compatibility proxy on
127.0.0.1:18011if needed - points Codex at that proxy with a temporary custom provider override
- starts on the profile's
default_model - exposes every configured model to Codex so you can switch later with
/model
Interactive examples:
codex-switch
codex-switch --config ./profiles/login002.jsonNon-interactive examples:
codex-switch "list files in the current directory"
codex-switch exec --skip-git-repo-check --dangerously-bypass-approvals-and-sandbox "fix failing tests"Default environment variables:
CODEX_VLLM_PROVIDER=localvllmCODEX_VLLM_MODELS_CONFIG=.../login002.jsonCODEX_VLLM_INITIAL_MODEL=gpt-5.4CODEX_VLLM_LISTEN_PORT=18011CODEX_VLLM_LOG_DIR=~/.local/share/codex-vllm-proxy/logs
Inside Codex, switch models interactively with:
/model
or directly:
/model gpt-5.1-codex-max
Run:
codex-openai-log exec --skip-git-repo-check --json "search the web for mimo"Wrapper behavior:
- starts the logging proxy on
127.0.0.1:18021if needed - points Codex at
http://127.0.0.1:18021/v1 - forwards upstream to
https://api.openai.com
Logs are written to:
~/.local/share/codex-openai-log-proxy/logs
Each request produces:
*.request.json*.response.log
codex-proxy-kit/
├── install.sh
├── profiles/
│ └── login002.example.json
├── requirements.txt
├── scripts/
│ ├── codex-vllm
│ ├── codex-switch
│ ├── codex-openai-log
│ ├── codex_vllm_responses_proxy.py
│ └── codex_openai_log_proxy.py
└── README.md
Inspect:
find ~/.codex/sessions -type f | tailThen look for function_call and function_call_output items inside the latest jsonl.
That is exactly what codex_vllm_responses_proxy.py is designed to normalize. Check:
~/.local/share/codex-vllm-proxy/logs/proxy.log
Check the config file passed with --config or CODEX_VLLM_MODELS_CONFIG. The proxy only exposes models defined there.
For codex-cli 0.116.0, stable /model behavior is best when the visible name values are Codex-recognized model ids and the real backend model is carried in target_model.
The wrapper performs a best-effort cleanup of stale ${TMPDIR:-/tmp}/codex-arg0* directories before launch. This is only meant to quiet abandoned temp-dir warnings from previous Codex runs.
Use codex-openai-log and inspect the generated *.request.json and *.response.log files.
python3 -m py_compile scripts/codex_vllm_responses_proxy.py
python3 -m py_compile scripts/codex_openai_log_proxy.py
scripts/codex-openai-log --versionMIT