Skip to content

CLIProxyAPI codex lane (cc-codex) — per-host bring-up checksheet

The cc-codex lane runs Claude Code against the codex subscription through a local CLIProxyAPI Anthropic-compatible proxy (scripts/claude-codex, tooling-catalog). This sheet stands the proxy up on a host.

Where it runs (read this first)

The proxy is a HOST process on 127.0.0.1:8317. One instance per host serves every client on that machine: the bash launcher (scripts/claude-codex) and its cc-codex shell shim.

So: install/run it once on each host, never per-launcher. On an N-host fleet you run N proxies.

The script

scripts/setup/cli-proxy-lane.sh (bash, run on the host) installs the pinned release, writes a loopback-bound config.yaml and guards every bounce. Run it with no flag for a status report that names the next command:

Terminal window
bash scripts/setup/cli-proxy-lane.sh
FlagDoes
--installdownload the pinned CLIProxyAPI binary + write ~/.cli-proxy-api/config.yaml (loopback-bound) if missing
--loginone-time codex OAuth via device-code flow (no local browser needed — works over SSH)
--startstart the proxy in the foreground (Ctrl-C to stop) — for debugging
--registerregister a systemctl --user unit (cli-proxy-api.service, Restart=on-failure) + loginctl enable-linger, and start it now — so the proxy is up immediately and restarts at each boot/login
--stop / --restartbounce-safe: refuses while a client is actively connected on port 8317 (ss ESTABLISHED check) unless --force
--verify / --statusone-line / multi-line reachability + readiness report

What to run, per host (assumes CLIPROXY_API_KEY is set in .env):

Terminal window
bash scripts/setup/cli-proxy-lane.sh --install
bash scripts/setup/cli-proxy-lane.sh --login # device-code OAuth, one time
bash scripts/setup/cli-proxy-lane.sh --register # starts it now + persists across reboots
bash scripts/setup/cli-proxy-lane.sh --verify

A fresh host runs the four commands in order; --roll replaces the manual stop/install/restart sequence on a host that already has a proxy.

Verify the lane end-to-end

Terminal window
# host:
bash scripts/claude-codex -p "reply OK"

Re-login when the codex token is invalidated

When the gateway’s codex token goes stale, the lane fails with the proxy error log showing authentication_error: Your authentication token has been invalidated. Please try signing in again. This is a self-service re-login, not a blocking outage. Re-auth with the DEVICE flow (-codex-login plain OAuth needs a localhost callback; the device flow does not):

Terminal window
cd ~/.cli-proxy-api && (umask 077; ./cli-proxy-api -config ./config.yaml -codex-device-login)

Run every -*-login under umask 077: upstream’s Claude login creates claude-<id>.json with os.Create (0644 under the usual umask 022), while its refresh path rewrites at 0600. --login and the --register unit already set it.

After ~2–4 seconds it prints Codex device URL: https://auth.openai.com/codex/device plus a 9-character device code, then polls until authorized. Leave it running in the FOREGROUND of a dedicated terminal until authorization completes, and do NOT kill it early (the URL + code only print after that short delay). Authorize from a logged-in browser or a second terminal. Treat the device URL + code as sensitive authorization material: surface them to the operator directly and nowhere else, never into shared logs, chat channels, screenshots, or CI output (anyone holding the active code can authorize the login). On authorize the process writes ~/.cli-proxy-api/codex-<email>.json (“Codex authentication successful”) and exits 0; re-verify the lane end-to-end (section above).

Detection caveat: the gateway’s /v1/models endpoint is registry-backed and keeps returning 200 during an OAuth gap. Probe a real completion (/v1/messages) to detect an auth gap, never /v1/models.

Transient 5xx: bounded retry and a second credential (HIMMEL-5391)

An upstream codex 502 ends a claudex worker’s turn, and the 503 auth_unavailable that follows is the proxy cooling down the only codex credential. --install (and --roll) write two keys to config.yaml, and only when they are missing, so an operator-set value is kept and a re-run changes nothing:

KeyWrittenMeaning (CLIProxyAPI config.example.yaml, v7.3.15)
request-retry3extra credential retry rounds on 403/408/429/500/502/503/504
max-retry-interval30longest wait, in seconds, for a cooldown between rounds

An existing install picks them up by re-running --install, then --restart (the proxy reads config.yaml at start).

A second codex credential (optional) gives the cooldown another credential to fall back to. CLIProxyAPI loads every codex-*.json in auth-dir, so add one by logging a second account in with the same device flow (--login, authorizing as the second account); it lands as its own codex-<email>.json. Logging the same account in again replaces its file, it does not add one. Two accounts mean two subscriptions’ usage on one proxy.

Notes

  • config.yaml pins host: "127.0.0.1" on purpose: the CLIProxyAPI default (empty host) binds all interfaces, LAN-exposing the OAuth-wrapped subscription endpoint. Always start via the script / -config.
  • CLIPROXY_API_KEY in .env must match the api-keys entry (himmel-local-claudex).
  • This re-exposes a subscription via OAuth; the ToS posture is operator-accepted.
  • The lane script is Linux-only; macOS has no lane script yet.