How to run a Codex subscription in Claude Code and Conductor

/ Kamran Tahir / 7 min read READ
How to run a Codex subscription in Claude Code and Conductor

Claude Code expects Anthropic-style configuration. Conductor can run Codex directly, but if you want to use Conductor’s Claude Code runner with a Codex subscription, CLIProxyAPI can sit in the middle and expose a local Anthropic-compatible endpoint while routing requests to Codex-backed OpenAI models.

The setup is:

  • Claude Code points at CLIProxyAPI
  • Conductor’s Claude Code runner uses that Claude Code config
  • CLIProxyAPI maps Claude-looking model names to Codex-backed models

So the chain becomes:

Conductor Claude Code runnerClaude CodeCLIProxyAPICodex-backed models

This post is the version that finally worked.

The annoying part was not Claude Code itself. The standalone Claude CLI worked quickly. The annoying part was Conductor continuing to send Claude-looking model IDs even after the UI/config said GPT. The proxy had to handle that. Conductor wasn’t respecting the ANTHROPIC_DEFAULT_OPUS_MODEL type envs.

Install and log in to CLIProxyAPI

On macOS:

brew install cliproxyapi
brew services start cliproxyapi

Then log in with the Codex/OpenAI account you want to use:

cliproxyapi -codex-login

CLIProxyAPI stores auth files under:

~/.cli-proxy-api/

The proxy config is usually:

/opt/homebrew/etc/cliproxyapi.conf

The local API server listens on:

http://localhost:8317

Check that it is alive:

brew services info cliproxyapi
lsof -nP -iTCP:8317 -sTCP:LISTEN

Confirm the proxy model list

Do not copy random model names from old docs. Query your local proxy.

Get one of your local proxy API keys from cliproxyapi.conf, then:

curl -sS \
  -H "Authorization: Bearer YOUR_LOCAL_PROXY_KEY" \
  http://localhost:8317/v1/models | jq -r '.data[]?.id'

In my case, the useful Codex-backed models included:

gpt-5.5
gpt-5.4
gpt-5.4-mini

The older gpt-5-codex(...) examples were stale for this setup.

Configure Claude Code directly

Conductor exposes this in its UI as:

Claude Code executable path
Claude settings
~/.claude/settings.json

So the most reliable place to configure the Anthropic-compatible proxy is Claude Code’s own settings file.

Edit:

~/.claude/settings.json

Use this shape:

{
  "theme": "dark",
  "model": "gpt-5.5",
  "env": {
    "ANTHROPIC_AUTH_TOKEN": "YOUR_LOCAL_PROXY_KEY",
    "ANTHROPIC_BASE_URL": "http://localhost:8317",
    "API_TIMEOUT_MS": "3000000",
    "ANTHROPIC_DEFAULT_OPUS_MODEL": "gpt-5.5",
    "ANTHROPIC_DEFAULT_SONNET_MODEL": "gpt-5.5",
    "ANTHROPIC_DEFAULT_HAIKU_MODEL": "gpt-5.4",
    "ANTHROPIC_MODEL": "gpt-5.5",
    "ANTHROPIC_SMALL_FAST_MODEL": "gpt-5.4"
  }
}

Because this file contains a key, lock it down:

chmod 600 ~/.claude/settings.json

Then test Claude Code without relying on your shell environment:

env \
  -u ANTHROPIC_AUTH_TOKEN \
  -u ANTHROPIC_API_KEY \
  -u ANTHROPIC_BASE_URL \
  -u ANTHROPIC_MODEL \
  -u ANTHROPIC_SMALL_FAST_MODEL \
  -u ANTHROPIC_DEFAULT_OPUS_MODEL \
  -u ANTHROPIC_DEFAULT_SONNET_MODEL \
  -u ANTHROPIC_DEFAULT_HAIKU_MODEL \
  claude -p "Reply exactly: ok" \
  --output-format text \
  --no-session-persistence

Expected:

ok

If that works, Claude Code itself is fine.

Mirror the env in Conductor if needed

Conductor also has Environment settings. In my case, putting the values only in ~/.claude/settings.json was not enough for every Conductor run, so I mirrored the provider env values into Conductor’s local environment store.

From the UI, add local/shared env vars equivalent to:

ANTHROPIC_BASE_URL=http://localhost:8317
ANTHROPIC_AUTH_TOKEN=YOUR_LOCAL_PROXY_KEY
ANTHROPIC_API_KEY=YOUR_LOCAL_PROXY_KEY
API_TIMEOUT_MS=3000000
ANTHROPIC_DEFAULT_OPUS_MODEL=gpt-5.5
ANTHROPIC_DEFAULT_SONNET_MODEL=gpt-5.5
ANTHROPIC_DEFAULT_HAIKU_MODEL=gpt-5.4
ANTHROPIC_MODEL=gpt-5.5
ANTHROPIC_SMALL_FAST_MODEL=gpt-5.4

I kept the model names plain here. Reasoning/effort can be controlled by Conductor or CLIProxyAPI, but the first goal is to make routing boring.

Configure Conductor’s defaults

Conductor’s settings file lives at:

~/.conductor/settings.toml

Mine ended up like this:

"$schema" = "https://conductor.build/schemas/settings.schema.json"
claude_provider = "anthropic"
codex_provider = "default"

[git]
branch_prefix_type = "github_username"

[models]
default = "gpt-5.5"
review = "gpt-5.5"

[models.claude_code]
default_effort_level = "medium"
review_effort_level = "xhigh"

[models.codex]
default_thinking_level = "high"
review_thinking_level = "high"

This handles the Conductor side of the UI. But it was not the final fix.

The real gotcha: Conductor still sent Claude model IDs

Even after changing the settings above, Conductor kept sending requests like:

{
  "model": "claude-opus-4-8"
}

CLIProxyAPI then did the reasonable thing:

providers=claude, model=claude-opus-4-8

But I had only logged in with Codex/OpenAI, not Claude. So CLIProxyAPI returned:

503 auth_unavailable: no auth available

This is the point where the architecture becomes clearer:

  • Conductor may keep insisting on Claude-looking model IDs.
  • Claude Code may accept those IDs.
  • CLIProxyAPI routes by model name.
  • If the model name starts with claude-*, CLIProxyAPI tries Claude auth unless told otherwise.

So the proxy itself needs to translate those Claude-looking names into Codex-backed models.

Add CLIProxyAPI aliases for Conductor

Edit:

/opt/homebrew/etc/cliproxyapi.conf

Add:

# Route Claude Code / Conductor Claude model IDs to Codex OAuth models.
# Conductor may still send claude-* IDs even when configured for GPT models.
oauth-model-alias:
  codex:
    - name: "gpt-5.5"
      alias: "claude-opus-4-8"
      fork: true
    - name: "gpt-5.5"
      alias: "claude-opus-4-8-1m"
      fork: true
    - name: "gpt-5.5"
      alias: "claude-opus-4-7"
      fork: true
    - name: "gpt-5.5"
      alias: "claude-opus-4-7-1m"
      fork: true
    - name: "gpt-5.5"
      alias: "claude-opus-4-6"
      fork: true
    - name: "gpt-5.5"
      alias: "claude-opus-4-6-1m"
      fork: true
    - name: "gpt-5.5"
      alias: "claude-sonnet-4-6"
      fork: true
    - name: "gpt-5.5"
      alias: "claude-sonnet-4-6-1m"
      fork: true
    - name: "gpt-5.4"
      alias: "claude-haiku-4-5-20251001"
      fork: true

oauth-excluded-models:
  claude:
    - "claude-*"

Then restart the proxy:

brew services restart cliproxyapi

If Homebrew gets stuck stopping the service, run the restart outside a sandboxed shell or restart the LaunchAgent from your normal terminal.

Test the exact model Conductor sends

This was the important test:

curl -sS \
  -H "Authorization: Bearer YOUR_LOCAL_PROXY_KEY" \
  -H "Content-Type: application/json" \
  -H "anthropic-version: 2023-06-01" \
  http://localhost:8317/v1/messages \
  -d '{
    "model": "claude-opus-4-8",
    "max_tokens": 24,
    "messages": [
      {
        "role": "user",
        "content": "reply ok"
      }
    ]
  }'

Once this returned 200, Conductor worked.

I also tested the other names Conductor might send:

claude-opus-4-8
claude-opus-4-8-1m
claude-sonnet-4-6
claude-sonnet-4-6-1m
claude-haiku-4-5-20251001

All returned 200 after the alias config.

Keep your shell clean

I initially put the Anthropic env vars in ~/.zshrc. That worked for a normal terminal, but it is cleaner to keep this setup in ~/.claude/settings.json and Conductor’s own environment settings.

That way shell startup does not secretly override unrelated tools.

Debug checklist

If this setup fails, check in this order.

1. Does CLIProxyAPI run?

brew services info cliproxyapi
lsof -nP -iTCP:8317 -sTCP:LISTEN

2. Does the local key work?

curl -sS \
  -H "Authorization: Bearer YOUR_LOCAL_PROXY_KEY" \
  http://localhost:8317/v1/models

You should get 200.

3. Does Claude Code read ~/.claude/settings.json?

env \
  -u ANTHROPIC_AUTH_TOKEN \
  -u ANTHROPIC_API_KEY \
  -u ANTHROPIC_BASE_URL \
  claude -p "Reply exactly: ok" \
  --output-format text \
  --no-session-persistence

4. What model is Conductor actually sending?

Look at CLIProxyAPI logs:

ls -lt ~/.cli-proxy-api/logs | head

Open the newest error-v1-messages-*.log and search for:

"model":

If you see claude-opus-4-8, your Conductor settings are not the deciding layer. Add a proxy alias.

5. Test that exact model directly

curl -sS \
  -H "Authorization: Bearer YOUR_LOCAL_PROXY_KEY" \
  -H "Content-Type: application/json" \
  -H "anthropic-version: 2023-06-01" \
  http://localhost:8317/v1/messages \
  -d '{"model":"claude-opus-4-8","max_tokens":24,"messages":[{"role":"user","content":"reply ok"}]}'

If this returns 200, the proxy side is fixed.

Final shape

Once the aliases are in place, the Claude Code runner path in Conductor can use the same local proxy path:

Conductor Claude Code runnerClaude CodeCLIProxyAPICodex-backed models

The main trick is not the Claude Code env. It is making sure the proxy translates the Claude model IDs that Conductor actually sends.