Local OpenAI-compatible gateway for authenticated Codex CLI and Claude Code sessions.
This is an MVP focused on personal local use. It exposes a small OpenAI-compatible HTTP API and forwards requests to local CLI tools.
GET /healthGET /v1/modelsPOST /v1/chat/completions- Streaming chat completions via Server-Sent Events
- Optional Bearer API key auth
- Claude Code adapter via
claude --print - Codex CLI adapter via
codex exec --skip-git-repo-check - Local-only default bind address:
127.0.0.1:8765 - Request timeout and optional fixed working directory
- Concurrent request limiting with configurable worker pool
Tool calling, /v1/responses, and session persistence are intentionally not included in the first MVP.
- Go 1.26+
- Authenticated
claudeCLI if using the Claude model - Authenticated
codexCLI if using the Codex model
cp .env.example .env
go run ./cmd/serverThe server listens on:
http://127.0.0.1:8765
Build and start the gateway:
cp .env.example .env
mkdir -p workspace
docker compose up --buildThe compose service publishes the gateway on the host at:
http://127.0.0.1:8765
Other services in the same Compose project can call it at:
http://agent-gateway:8765/v1
Example environment for another service:
environment:
OPENAI_BASE_URL: http://agent-gateway:8765/v1
OPENAI_API_KEY: ${AGENT_GATEWAY_API_KEY}The default compose.yaml mounts:
./workspaceto/workspace${HOME}/.claudeto/home/app/.claude${HOME}/.codexto/home/app/.codex
Those mounts allow the containerized CLI tools to reuse local login/session state. If your Claude or Codex CLI stores auth elsewhere, update the volume paths accordingly.
The Docker image installs these npm packages by default:
@anthropic-ai/claude-code@openai/codex
You can override package names at build time if needed:
docker compose build \
--build-arg CLAUDE_CODE_PACKAGE=@anthropic-ai/claude-code \
--build-arg CODEX_CLI_PACKAGE=@openai/codexConfiguration is read from environment variables.
| Variable | Default | Description |
|---|---|---|
AGENT_GATEWAY_HOST |
127.0.0.1 |
Server bind host |
AGENT_GATEWAY_PORT |
8765 |
Server port |
AGENT_GATEWAY_API_KEY |
empty | Optional Bearer auth key |
AGENT_GATEWAY_TIMEOUT_SECONDS |
300 |
CLI request timeout |
AGENT_GATEWAY_MAX_WORKERS |
8 |
Max concurrent CLI requests |
AGENT_GATEWAY_WORKDIR |
empty | Optional fixed subprocess working directory |
CLAUDE_BIN |
claude |
Claude CLI binary |
CLAUDE_ARGS |
--print |
Base Claude CLI args |
CLAUDE_MODEL |
sonnet |
Model passed to Claude adapter |
CODEX_BIN |
codex |
Codex CLI binary |
CODEX_ARGS |
exec --skip-git-repo-check |
Base Codex CLI args |
CODEX_MODELS |
gpt-5.5 |
Comma-separated list of Codex model IDs to expose |
CODEX_MODEL |
gpt-5.5 |
Fallback when CODEX_MODELS is not set |
By default the gateway exposes:
claude-sonnet— routed to Claude CLIgpt-5.5— routed to Codex CLI
To expose multiple Codex models, set CODEX_MODELS as a comma-separated list:
CODEX_MODELS=gpt-5.5,gpt-5.4,gpt-5.4-mini
Each entry becomes a separate model ID in the API. Use the exact model ID in your request.
Check available models:
curl http://127.0.0.1:8765/v1/models \
-H "Authorization: Bearer local-secret"curl http://127.0.0.1:8765/v1/chat/completions \
-H "Authorization: Bearer local-secret" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet",
"messages": [
{"role": "user", "content": "Explain this repository structure briefly."}
]
}'Codex example:
curl http://127.0.0.1:8765/v1/chat/completions \
-H "Authorization: Bearer local-secret" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5.5",
"messages": [
{"role": "user", "content": "Write a small Go hello world program."}
]
}'curl -N http://127.0.0.1:8765/v1/chat/completions \
-H "Authorization: Bearer local-secret" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet",
"stream": true,
"messages": [
{"role": "user", "content": "Write a short greeting."}
]
}'The gateway returns OpenAI-compatible Server-Sent Events with chat.completion.chunk payloads and a final data: [DONE] event.
- This gateway shells out to local CLI tools and returns stdout as the assistant message.
- Streaming forwards CLI stdout as it is emitted. Some CLI tools may buffer output and only emit near the end.
usagevalues are approximate token estimates.- Keep
AGENT_GATEWAY_HOST=127.0.0.1unless you deliberately want network access. - The exact Codex CLI flags can vary by version. Adjust
CODEX_ARGSif your installed CLI expects a different non-interactive command.