## OpenAI Codex and Barndoor LLM Gateway

OpenAI Codex (CLI and Desktop) talks to models over the **OpenAI Responses API** (`POST /v1/responses`), not Chat Completions. The Barndoor LLM Gateway speaks that wire format natively — configure Codex with a custom provider whose `base_url` is your gateway endpoint and whose `wire_api` is `responses`.

This guide covers the DIY `~/.codex/config.toml` setup. Copy your exact gateway base URL and a `bd-…` API key from **Settings → My Models** first — see the [LLM Gateway Quickstart](https://docs.barndoor.ai/how-tos/llm-gateway-quickstart) if you do not have those yet.

## Prerequisites
- Codex CLI installed, and/or the **Codex desktop app**.
- A Barndoor LLM Gateway endpoint and a `bd-…` API key from **Settings → My Models**.
- At least one **model route** (or enabled model) your key is allowed to call. Use the exact name shown under **Available Models**.

**Self-hosted and private-cloud deployments:** swap `app.barndoor.ai` for your organization’s portal hostname everywhere below. The path (`/api/llm-gateway/v1`) is the same.

## Why `/v1` matters

Codex appends `/responses` to the provider `base_url`. The gateway’s Responses endpoint is `/api/llm-gateway/v1/responses`.

| `base_url` you set | Codex actually calls | Result |
| --- | --- | --- |
| `https://app.barndoor.ai/api/llm-gateway/v1` | `…/llm-gateway/v1/responses` | Correct |
| `https://app.barndoor.ai/api/llm-gateway` | `…/llm-gateway/responses` | Wrong — often a `401` with `invalid JWT header: InvalidToken` |

Always keep the trailing `/v1` that **Settings → My Models** shows for OpenAI-compatible clients. (This is the opposite of Claude Code, which must _omit_`/v1` because it appends `/v1/messages` itself.)

## Configure Codex CLI

### 1. Add a Barndoor provider

Edit `~/.codex/config.toml` (create the file if it does not exist):

```
model_provider = "barndoor"
model = "gpt-4o-mini"   # replace with a route or model from Settings → My Models

[model_providers.barndoor]
name = "Barndoor"
base_url = "https://app.barndoor.ai/api/llm-gateway/v1"
wire_api = "responses"
env_key = "BARNDOOR_API_KEY"
```

- `wire_api = "responses"` selects the Responses wire format Codex requires.
- `env_key` is only the **name** of the environment variable Codex should read for the API key — it is not the secret itself.
- `model` must match a name your key can call (a bare route alias like `gpt-4o-mini`, or a provider-prefixed form if that is how the model is listed).

### 2. Export the gateway key

```
export BARNDOOR_API_KEY="bd-…"
```

`env_key` points Codex at this variable; the `export` supplies the value. Keeping the secret in the environment (not in `config.toml`) avoids committing it to git. Add the export to your shell profile if you want it available in every new terminal.

### 3. Run Codex

```
codex
```

Traffic goes to Barndoor on `POST /v1/responses`. Usage and governance follow the same rules as any other gateway client.

## Configure Codex Desktop

Codex Desktop uses the same provider configuration as the CLI. Custom providers are selected by `model_provider` / `model` in config — the in-app model picker may not list custom gateway models the way it lists built-in ones.

1. Put the same `model_provider`, `model`, and `[model_providers.barndoor]` block in `~/.codex/config.toml` (or in `$CODEX_HOME/config.toml` if you set `CODEX_HOME`).
2. Make `BARNDOOR_API_KEY` available to the Desktop process. Dock / Spotlight launches on macOS typically do **not** inherit exports from `.zshrc` or `.zprofile`. Prefer one of:
   - Start Desktop from a terminal after exporting the key (for example `export BARNDOOR_API_KEY="bd-…" && open -a "Codex"` — use the exact app name on your machine).
   - A small wrapper script that exports the key, then launches the app.
3. Fully quit and relaunch Desktop so it reloads `config.toml`. Routing follows the `model_provider` and `model` you set; you should not need to pick “Barndoor” from a provider menu.

If Desktop starts without `BARNDOOR_API_KEY` in its environment, requests fail auth even when the same key works in the CLI. Confirm the launch path actually exports the variable — a terminal-only `export` does not help a Dock-launched app.

## Smoke-test without Codex

Confirm the gateway accepts Responses traffic with your key before debugging Codex itself:

```
curl https://app.barndoor.ai/api/llm-gateway/v1/responses \
  -H "Authorization: Bearer bd-…" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-4o-mini",
    "input": "Reply with the single word pong."
  }'
```

A successful JSON response means the endpoint, key, and model name are fine — remaining issues are almost always Codex `base_url` / `wire_api` / env wiring.

## Troubleshooting

| Symptom | Likely cause | Fix |
| --- | --- | --- |
| `401` / `invalid JWT header: InvalidToken` | `base_url` missing `/v1` | Use `…/api/llm-gateway/v1` |
| `401` / invalid API key | Wrong or unset `BARNDOOR_API_KEY` | Confirm `env_key` matches the variable you exported; recreate the key under **Settings → My Models** if needed |
| Model not found / `404` | `model` is not an enabled route for your key | Copy an exact name from **Available Models** |
| Desktop ignores the key | GUI process lacks the env var | Launch Desktop from a shell/wrapper that exports `BARNDOOR_API_KEY` (Dock launches usually will not see `.zshrc` exports) |
| Works in `curl` but not in Codex | Wrong `wire_api` or provider block | Set `wire_api = "responses"` under `[model_providers.barndoor]` |
