Skip to content

pitzcarraldo/codex-workers-ai-proxy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

codex-workers-ai-proxy

Local TypeScript proxy that lets Codex CLI talk to Cloudflare Workers AI models through an OpenAI-compatible Responses API surface.

Table of Contents

Quick Start

git clone https://github.com/pitzcarraldo/codex-workers-ai-proxy.git
cd codex-workers-ai-proxy
cp .env.example .env
# Edit .env with your Cloudflare credentials:
#   CLOUDFLARE_ACCOUNT_ID=<your-account-id>
#   CLOUDFLARE_API_TOKEN=<your-api-token>
npm start

Then, in another terminal:

curl -fsS http://127.0.0.1:4319/codex/model-catalog.json -o /tmp/codex-model-catalog.json

codex \
  -m @cf/moonshotai/kimi-k2.5 \
  -c 'model_provider="cloudflare_proxy"' \
  -c 'model_catalog_json="/tmp/codex-model-catalog.json"' \
  -c 'model_providers.cloudflare_proxy.name="Cloudflare Proxy"' \
  -c 'model_providers.cloudflare_proxy.base_url="http://127.0.0.1:4319/v1"' \
  -c 'model_providers.cloudflare_proxy.wire_api="responses"' \
  -c 'model_providers.cloudflare_proxy.supports_websockets=false'

That's it. For a more ergonomic setup, see Usage with Codex.

Prerequisites

  • Node.js (runs .ts entrypoints directly, no transpilation needed) or Bun
  • Cloudflare account with Workers AI enabled

Getting Cloudflare Credentials

  1. Go to Cloudflare Dashboard
  2. Account ID -- found in the zone dashboard sidebar
  3. API Token -- create one with Workers AI:Edit, Workers AI:Read permissions

Installation

git clone https://github.com/pitzcarraldo/codex-workers-ai-proxy.git
cd codex-workers-ai-proxy
cp .env.example .env

Edit .env with your credentials:

CLOUDFLARE_ACCOUNT_ID=<your-account-id>
CLOUDFLARE_API_TOKEN=<your-api-token>

Start the server:

npm start          # Node.js
npm run start:bun  # Bun

Default address: http://127.0.0.1:4319

Usage with Codex

1. Shell wrapper (Recommended)

Add both functions to ~/.bashrc or ~/.zshrc:

codexcf_start() {
  local proxy_dir="${1:-$(pwd)}"
  local proxy_port="${CODEXCF_PROXY_PORT:-4319}"
  local proxy_log="${CODEXCF_PROXY_LOG:-$HOME/.codex-workers-ai-proxy.log}"
  local proxy_pid_file="${CODEXCF_PROXY_PID_FILE:-$HOME/.codex-workers-ai-proxy.pid}"

  if command -v lsof >/dev/null 2>&1 && lsof -nP -iTCP:"$proxy_port" -sTCP:LISTEN >/dev/null 2>&1; then
    echo "Proxy already running on port $proxy_port"
    return 0
  fi

  (
    cd "$proxy_dir" || exit 1
    nohup npm start >> "$proxy_log" 2>&1 &
    echo $! > "$proxy_pid_file"
  )

  echo "Proxy started. Log: $proxy_log"
}

codexcf() {
  local proxy_port="${CODEXCF_PROXY_PORT:-4319}"
  local default_model="${CODEXCF_MODEL:-@cf/moonshotai/kimi-k2.5}"
  local proxy_dir="${CODEXCF_PROXY_DIR:-$HOME/codex-workers-ai-proxy}"
  local catalog_path="${CODEXCF_MODEL_CATALOG_PATH:-${TMPDIR:-/tmp}/codexcf-model-catalog.json}"

  codexcf_start "$proxy_dir"

  curl -fsS "http://127.0.0.1:${proxy_port}/codex/model-catalog.json" -o "$catalog_path" 2>/dev/null

  codex \
    -m "$default_model" \
    -c 'model_provider="cloudflare_proxy"' \
    -c "model_catalog_json=\"$catalog_path\"" \
    -c 'model_providers.cloudflare_proxy.name="Cloudflare Proxy"' \
    -c "model_providers.cloudflare_proxy.base_url=\"http://127.0.0.1:${proxy_port}/v1\"" \
    -c 'model_providers.cloudflare_proxy.wire_api="responses"' \
    -c 'model_providers.cloudflare_proxy.supports_websockets=false' \
    "$@"
}

Then:

source ~/.zshrc
codexcf "Hello, how are you?"
codexcf -m @cf/openai/gpt-oss-120b "Explain quantum computing"

2. config.toml profile

Add to ~/.codex/config.toml:

[model_providers.cloudflare_proxy]
name = "Cloudflare Workers AI Proxy"
base_url = "http://127.0.0.1:4319/v1"
wire_api = "responses"
supports_websockets = false

[profiles.kimi]
model_provider = "cloudflare_proxy"
model = "@cf/moonshotai/kimi-k2.5"
model_catalog_json = "/tmp/codex-model-catalog.json"

Prepare and run:

curl -fsS http://127.0.0.1:4319/codex/model-catalog.json -o /tmp/codex-model-catalog.json
codex -p kimi

3. Inline override

curl -fsS http://127.0.0.1:4319/codex/model-catalog.json -o /tmp/codex-model-catalog.json

codex \
  -m @cf/moonshotai/kimi-k2.5 \
  -c 'model_provider="cloudflare_proxy"' \
  -c 'model_catalog_json="/tmp/codex-model-catalog.json"' \
  -c 'model_providers.cloudflare_proxy.name="Cloudflare Proxy"' \
  -c 'model_providers.cloudflare_proxy.base_url="http://127.0.0.1:4319/v1"' \
  -c 'model_providers.cloudflare_proxy.wire_api="responses"' \
  -c 'model_providers.cloudflare_proxy.supports_websockets=false'

Recommended Models

Cloudflare Workers AI text generation models ranked by LiveCodeBench performance (as of April 2026):

Cloudflare Workers AI text generation models ranked by LiveCodeBench performance (as of April 2026):

Model LiveCodeBench AA Index Context Comparable Claude Comparable GPT Cost (Sonnet 4.5=100%)
kimi-k2.5 ~85% 47 256k Claude Sonnet 4.5 GPT-5.2 20%
gemma-4-26b-a4b-it ~77% ~33 256k Claude Sonnet 4 GPT-5 mini 2.5%
gpt-oss-120b ~70% ~37 131k Claude Sonnet 3.7 o4-mini 7.5%
glm-4.7-flash ~65% 30 200k Claude 3.5 Sonnet GPT-4.1 2.5%

Running as a Daemon

Manual background start

cd /path/to/codex-workers-ai-proxy
nohup npm start >> ~/.codex-workers-ai-proxy.log 2>&1 &
echo $! > ~/.codex-workers-ai-proxy.pid

Stop the daemon

# Using PID file
kill "$(cat ~/.codex-workers-ai-proxy.pid)" 2>/dev/null && rm ~/.codex-workers-ai-proxy.pid

# Or kill by port
kill "$(lsof -t -i:4319)" 2>/dev/null

View logs

tail -f ~/.codex-workers-ai-proxy.log           # Real-time
tail -n 100 ~/.codex-workers-ai-proxy.log       # Recent lines
grep "ERROR" ~/.codex-workers-ai-proxy.log      # Search errors

Tip: If using the Shell wrapper, the daemon management is handled automatically by codexcf_start.

API Endpoints

Method Path Description
POST /v1/responses Create a response (Responses API)
GET /v1/responses/:id Retrieve a response
POST /v1/chat/completions Chat completion (OpenAI compat)
GET /v1/models List available models
GET /codex/model-catalog.json Model catalog for Codex CLI
GET /health Health check

Testing the API

BASE_URL="http://127.0.0.1:4319"

# Health check
curl -s $BASE_URL/health

# List models
curl -s $BASE_URL/v1/models | jq '.data[].id'

# Chat completion
curl -X POST $BASE_URL/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "@cf/moonshotai/kimi-k2.5",
    "messages": [{"role": "user", "content": "Hello!"}]
  }' | jq .

Prompt Caching

The proxy forwards a stable x-session-affinity value derived from (in priority order):

  1. Incoming x-session-affinity header
  2. Incoming session_id
  3. prompt_cache_key
  4. x-client-request-id
  5. previous_response_id

Troubleshooting

Symptom Solution
EADDRINUSE Port 4319 in use. lsof -i:4319 to check
401 Unauthorized Verify CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN
403 Forbidden Token needs Workers AI:Read permission
Empty model catalog Enable Workers AI in Cloudflare Dashboard
Connection refused Start proxy: npm start

Debug mode

npm start                    # Foreground with full output
node --inspect src/index.ts  # With Node.js debugger

Attach debugger via Chrome DevTools (chrome://inspect) or VS Code "Attach to Process".

Check if proxy is running

# macOS
lsof -nP -iTCP:4319 -sTCP:LISTEN

# Linux
ss -tlnp | grep 4319

# Quick health check
curl -s http://127.0.0.1:4319/health && echo "OK" || echo "Not responding"

Development

npm run check    # Type checking
npm test         # Run tests
npm run dev      # Dev mode (Node)
npm run dev:bun  # Dev mode (Bun)

Limitations

  • Only exposes Workers AI text generation models.
  • web_search tools are only translated when external_web_access=true.
  • Responses API streaming is translated from Workers AI chat-completions SSE in real time.
  • Kimi thinking turns keep reasoning_content in proxy-side history for the next turn and stream live reasoning deltas to Codex when available.

About

Local TypeScript proxy that lets Codex CLI talk to Cloudflare Workers AI models through an OpenAI-compatible Responses API surface

Resources

Stars

Watchers

Forks

Contributors