---
title: "How to run a Codex subscription in Claude Code and Conductor"
description: "A simple CLIProxyAPI setup for using Codex-backed models from Claude Code and Conductor."
date: "2026-06-10"
slug: "codex-subscription-claude-code-conductor"
ogImage: "/images/conductor-claude-code-cliproxyapi-og.png"
tags:
  - "ai"
  - "claude-code"
  - "codex"
  - "conductor"
  - "cliproxyapi"
  - "developer-tools"
  - "worktrees"
  - "local-development"
  - "proxy"
  - "openai"
  - "anthropic"
faqs:
  - question: "Why use CLIProxyAPI with Conductor?"
    answer: "Conductor can run Codex directly too. This setup is specifically for its Claude Code runner, which expects Anthropic-style configuration. CLIProxyAPI can expose a local Anthropic-compatible endpoint backed by Codex/OpenAI OAuth, so that Claude Code path can route to Codex-backed models."
  - question: "Does this require a separate Anthropic API key?"
    answer: "No. The point of this setup is to expose an Anthropic-compatible local endpoint through CLIProxyAPI, while the actual model requests route to Codex/OpenAI OAuth-backed models."
  - question: "Why did Conductor still send claude-opus model names?"
    answer: "Conductor may keep model choices in its own session state and still ask Claude Code for Claude model IDs. The practical fix is to configure CLIProxyAPI aliases so those Claude-looking model IDs resolve to Codex-backed GPT models."
  - question: "Where should the Claude Code environment variables live?"
    answer: "For Conductor, put them in ~/.claude/settings.json under the env key, and optionally mirror them in Conductor's Environment settings. New Conductor windows or sessions are needed for changes to take effect."
---

![How to run a Codex subscription in Claude Code and Conductor](https://saybackend.com/images/conductor-claude-code-cliproxyapi-og.png)

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:

[Interactive element: Codex subscription routing chain](https://saybackend.com/blog/codex-subscription-claude-code-conductor/)

This post is the version that finally worked.

**Note:**
  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:

```bash
brew install cliproxyapi
brew services start cliproxyapi
```

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

```bash
cliproxyapi -codex-login
```

CLIProxyAPI stores auth files under:

```text
~/.cli-proxy-api/
```

The proxy config is usually:

```text
/opt/homebrew/etc/cliproxyapi.conf
```

The local API server listens on:

```text
http://localhost:8317
```

Check that it is alive:

```bash
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:

```bash
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:

```text
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:

```text
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:

```text
~/.claude/settings.json
```

Use this shape:

```json
{
  "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:

```bash
chmod 600 ~/.claude/settings.json
```

Then test Claude Code without relying on your shell environment:

```bash
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:

```text
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:

```text
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:

```text
~/.conductor/settings.toml
```

Mine ended up like this:

```toml
"$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:

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

CLIProxyAPI then did the reasonable thing:

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

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

```text
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:

```text
/opt/homebrew/etc/cliproxyapi.conf
```

Add:

```yaml
# 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:

```bash
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:

```bash
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:

```text
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?

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

### 2. Does the local key work?

```bash
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`?

```bash
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:

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

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

```text
"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

```bash
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:

[Interactive element: Working Conductor routing chain](https://saybackend.com/blog/codex-subscription-claude-code-conductor/)

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