@abenvenuto/codex-openai-proxy
v1.3.0
Published
Use local Codex auth.json to expose an OpenAI-compatible proxy server
Maintainers
Readme
codex-openai-proxy
Maintained fork of thkdog/codex-openai-proxy, originally created by shenyi (thkdog). This fork preserves the original work and adds updated Codex backend compatibility and OpenAI-compatible behavior.
A local OpenAI-compatible proxy that reuses local Codex / ChatGPT auth state and forwards requests to https://chatgpt.com/backend-api/codex/*.
It exposes OpenAI-style endpoints so existing OpenAI SDK integrations and tools can work with minimal changes.
Currently supported:
GET /healthGET /v1/modelsPOST /v1/responsesPOST /v1/chat/completions
Codex compatibility
Version 1.2.0 tracks the Codex CLI 0.144.1 backend protocol. It uses the current authenticated
WebSocket transport, request headers, model catalog, and model-specific base instructions. The
default model is gpt-5.6-sol; use GET /v1/models to see the models available to your account.
Supported Responses features
- streaming and non-streaming Responses;
reasoning.effortvalidated against the selected model catalog;input_text, PDFinput_file, andinput_imagecontent parts;text.verbosity;- strict
text.format.type=json_schemaStructured Outputs; - OpenAI-style error envelopes and HTTP status codes before streaming starts;
- structured SSE errors for failures after streaming starts.
Structured responses are buffered until their JSON Schema is validated. This intentionally delays
their SSE deltas: invalid JSON is returned as json_schema_validation_failed, never as a successful
partial response. The dependency-free validator supports the schema subset used by this proxy:
type, properties, required, additionalProperties, items, enum, description, and
title. Unsupported keywords fail with unsupported_json_schema instead of being ignored.
Quick Start
1. Prerequisites
- Node.js 18+
- You are already signed in to Codex / ChatGPT on this machine
- Default auth file path:
~/.codex/auth.json
You can verify the auth file exists:
ls ~/.codex/auth.json2. Run with npx
npx @abenvenuto/codex-openai-proxyDefault listen address:
http://127.0.0.1:8787If you are developing inside this repository, you can also run:
npm install
npm run devOn startup, the server prints:
- service URL
- active auth file path
- health check URL
- models URL
- OpenAI SDK
baseURL - copy-paste
curlcommands for verification
CLI Options
This project uses command-line arguments only and does not read environment variables.
Show help:
npx @abenvenuto/codex-openai-proxy --helpAvailable options:
-H, --host <host>: listen host, default127.0.0.1-p, --port <port>: listen port, default8787-a, --auth-file <path>: auth file path, default~/.codex/auth.json--body-limit-mb <mb>: maximum JSON request body size, default75MiB
The larger default body limit is required for Base64 file inputs. OpenAI accepts up to 50 MB of
files per request, while Base64 expands the binary data by roughly one third. Fastify's original
1 MiB default is therefore too small for ordinary PDF evidence. Because request bodies are parsed
in memory, keep the listener on 127.0.0.1 and reduce this limit when large file inputs are not
needed.
Examples:
npx @abenvenuto/codex-openai-proxy --port 9000npx @abenvenuto/codex-openai-proxy --body-limit-mb 75npx @abenvenuto/codex-openai-proxy --host 0.0.0.0 --port 9000npx @abenvenuto/codex-openai-proxy --auth-file ~/.codex/auth.jsonnpx @abenvenuto/codex-openai-proxy --host 0.0.0.0 --port 9000 --auth-file ~/.codex/auth.jsonYou can also install it globally:
npm install -g @abenvenuto/codex-openai-proxy
codex-openai-proxy --port 9000Verify
Health check:
curl http://127.0.0.1:8787/healthList models:
curl http://127.0.0.1:8787/v1/modelsRoot info page:
curl http://127.0.0.1:8787/curl Examples
Non-streaming chat/completions:
curl http://127.0.0.1:8787/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{
"model": "gpt-5.6-sol",
"messages": [
{ "role": "user", "content": "Reply with exactly ok" }
]
}'Streaming chat/completions:
curl -N http://127.0.0.1:8787/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{
"model": "gpt-5.6-sol",
"stream": true,
"messages": [
{ "role": "user", "content": "Reply with exactly ok" }
]
}'Non-streaming responses:
curl http://127.0.0.1:8787/v1/responses \
-H 'Content-Type: application/json' \
-d '{
"model": "gpt-5.6-sol",
"input": [
{
"type": "message",
"role": "user",
"content": [
{ "type": "input_text", "text": "Reply with exactly ok" }
]
}
]
}'Structured responses:
curl http://127.0.0.1:8787/v1/responses \
-H 'Content-Type: application/json' \
-d '{
"model": "gpt-5.6-luna",
"input": "Return a valid result object.",
"text": {
"format": {
"type": "json_schema",
"name": "result",
"strict": true,
"schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"status": { "type": "string", "enum": ["completed"] }
},
"required": ["status"]
}
}
}
}'PDF input uses the standard data URL shape:
{
"type": "input_file",
"filename": "evidence.pdf",
"file_data": "data:application/pdf;base64,..."
}OpenAI SDK Example
Install the official SDK first:
npm install openaichat/completions example:
import OpenAI from "openai";
const client = new OpenAI({
apiKey: "dummy",
baseURL: "http://127.0.0.1:8787/v1",
});
const result = await client.chat.completions.create({
model: "gpt-5.6-sol",
messages: [
{ role: "user", content: "Reply with exactly ok" },
],
});
console.log(result.choices[0]?.message?.content);responses example:
import OpenAI from "openai";
const client = new OpenAI({
apiKey: "dummy",
baseURL: "http://127.0.0.1:8787/v1",
});
const result = await client.responses.create({
model: "gpt-5.6-sol",
input: "Reply with exactly ok",
});
console.log(result.output_text);Reasoning effort
Use the standard Responses API reasoning.effort field:
const result = await client.responses.create({
model: "gpt-5.6-luna",
reasoning: { effort: "xhigh" },
input: "Solve this difficult problem.",
});For Chat Completions, use reasoning_effort:
const result = await client.chat.completions.create({
model: "gpt-5.6-luna",
reasoning_effort: "high",
messages: [{ role: "user", content: "Solve this difficult problem." }],
});Codex 0.144.1 exposes low, medium, high, xhigh, and max for
gpt-5.6-luna. A fully non-reasoning mode is not available; use low for the lightest reasoning.
iGovTI evidence evaluation
The iGovTI provider can use this proxy without an API key:
export OPENAI_BASE_URL=http://127.0.0.1:8787/v1Recommended evaluator route:
{
"provider": "openai",
"model": "gpt-5.6-luna",
"model_key": "gpt-5.6-luna",
"reasoning": "high",
"pdf2md": false,
"docx2html": false
}The proxy preserves the nested JSON Schema used by manager-comments temporal reassessments and validates the completed output before releasing it to the client.
Error behavior
Errors use the OpenAI-compatible envelope:
{
"error": {
"message": "...",
"type": "rate_limit_error",
"code": "rate_limit_exceeded"
}
}Invalid models and reasoning levels return HTTP 400. Authentication failures return 401, rate
limits return 429 when known before streaming, upstream timeouts return 504, and invalid structured
model output returns 502. Once SSE headers have been sent, the same status is included in a
structured type=error event.
The service logs request metadata through Fastify but must not log access tokens, account IDs, auth file contents, full prompts, data URLs, or attachment contents.
Troubleshooting
Auth file not found:
- the default path is not
~/.codex/auth.json - pass
--auth-fileexplicitly --auth-file ~/.codex/auth.jsonis supported and~will be expanded automatically
Invalid auth file:
- the file is not valid JSON
- or it is missing
tokens.access_token - or it is missing
tokens.account_id
Port issues:
--portmust be an integer between1and65535- or the port is already in use
Expired Codex auth state:
/healthworks but/v1/modelsfails- in that case you usually need to sign in to Codex / ChatGPT again so the local auth file is refreshed
