selan.ai

Docs · Codex

Run Codex on your company's accounts

One command instead of codex, and every argument passes through. Same keys, same limits, same Usage and Logs as everything else. For how the pieces fit together, start at the docs.

Get started

Before you start

Codex is a prerequisite. Selan launches it; it does not bundle it. Without it on your PATH you get:

codex not found on PATH; install Codex CLI from https://developers.openai.com/codex

You also need the selan binary and a session. If you have neither yet, both are two commands: see Install and Sign in. Nothing about signing in is Codex-specific — one session serves every client.

A ChatGPT subscription is not required to run Codex through Selan. It is required for one thing only: the model picker. Codex only asks for a model list while it is signed in to ChatGPT.

Run it

selan codex

That is the whole change: selan codex instead of codex. Every argument passes through verbatim, so anything you ran before still runs — flags, subcommands, codex exec, all of it.

Codex then talks to your company's gateway rather than your own ChatGPT account. Your requests spend against whatever provider keys an owner connected, show up as you in Usage, and appear in Logs with the model that served them.

What Selan writes to your config

The first time you run it, Selan adds a provider block to ~/.codex/config.toml and tells you it did:

note: wrote selan's provider block to /Users/you/.codex/config.toml

Said once, and only when something changed — not on every launch. This is what lands:

# >>> selan managed — do not edit, `selan codex` rewrites this block >>>
[model_providers.selan]
name = "Selan"
base_url = "https://cxgw.selan.ai/v1"
wire_api = "responses"
request_max_retries = 1
stream_max_retries = 2
env_http_headers = { "x-selan-model" = "SELAN_MODEL", "x-selan-repo" = "SELAN_REPO" }
env_key = "SELAN_CODEX_TOKEN"
env_key_instructions = "Run `selan codex` — it exports this for the session."
# <<< selan managed <<<
  • Only the block between the markers is ours. The rest of your config is left alone: your own providers, profiles and settings stay exactly as you wrote them.
  • Do not edit inside the markers. selan codex rewrites the block whenever it changes — a new gateway URL, say — and your edit goes with it.
  • The credential is not in the file. env_key names a variable, and selan codex exports it for that launch and no longer.
  • A bare codex fails closed. Run Codex by hand and the variable is not set, so it stops rather than quietly spending your company's account. That is deliberate, and it is why the block names a variable instead of a command.

On the dev channel the block is [model_providers.selan-dev] and sits beside the production one. Both can live in the same file.

Choosing a model

Your company's models in the picker

Type /model in Codex and your company's own models are in the list, in place of the built-in one. Pick one the way you pick any other, with no flag to pass.

Select model
Switch between models. Your pick becomes the default for new sessions.
>1.GPT-5.6 Sol
2.GPT-5.6 Terra
3.Kimi K3 · From gateway
4.DeepSeek V4 Flash · From gateway
↑/↓ to move · enter to select
Every row is a model your company can actually lease, named as an owner named it. Rows 3 and 4 run on a provider that is not OpenAI and say so; rows 1 and 2 are OpenAI's own and carry no marking. Up to twelve rows.

A pick means the model, not one provider's copy of it. If your company has the same model on more than one account, choosing it here leases them in the order an owner set, so a provider that is out of quota falls through to the next instead of failing the request.

While Codex is signed in to ChatGPT, selan codex also starts on the first model in that list rather than leaving the choice to each request.

Codex only asks for this list while it is signed in to ChatGPT. Using Selan alone, it never asks, and you keep its built-in list — the models are still there and still leased the same way, you just pick them with --model instead. The picker itself is not a setting any more — but models are still switched on one at a time, so a model an owner has not turned on is in neither list.

If a model you expected is not there

  • Quit and relaunch first. The list is fetched at startup and cached for five minutes, so a model switched on while you were working shows up on the next start, not when you reopen /model.
  • Check it can reach Codex at all. Some models your company has switched on cannot appear here, whatever anyone toggles. See which models can appear.
  • Then ask an owner to switch it on. Models are off until someone turns them on, one at a time. Connecting a provider key does not put anything in anyone's picker by itself.

Want a model your company has not curated, or one the picker cannot carry? Name it directly — see naming a model.

Which models can appear

Codex speaks one protocol, the one named on the wire_api line in the block above. A model reaches Codex only if the provider serving it speaks that protocol too — so a model can be switched on, be perfectly usable in Claude Code, and still never appear here.

ProviderIn Codex
OpenAI — subscription or API key Yes. Shown unmarked, since these are Codex's own models.
OpenRouter Yes, marked From gateway.
nexos.ai Yes for most of its catalogue — but not its Claude models, which it serves on the other protocol.
Ollama No. Everything it serves is on the other protocol.
Vertex AI No, and not in Claude Code's picker either. A Vertex key still works on the paths that name no model.

Every one of these but Vertex reaches Claude Code, which is why a list that looks short here is usually this rule rather than a missing switch. Nothing is silently degraded: a model that cannot serve Codex is left out of the list instead of being offered and then refused.

Naming a model directly

You do not need the picker to choose. Name a model on the command line and Codex starts on it:

selan codex --model openrouter:moonshotai/kimi-k3

The shape of the name decides how far Selan will go to serve it:

  • With a provider in frontopenrouter:moonshotai/kimi-k3 — it runs on that provider and no other. If that account is out of quota, the request fails rather than moving.
  • Without onegpt-5.6-sol — it means the model itself, and Selan leases your company's accounts for it in the order an owner set, falling through on failure. This is what a pick in the picker does.

Either way the model has to be one your company connected. This path skips the curated list, not the provider keys.

Going further

Running without approval prompts

seland is the same binary under a second name, and it launches Codex with its approval prompts off after one enter to confirm:

seland codex
The sandbox stays on. This turns off the prompts, not the isolation — Codex still cannot reach outside its workspace. To drop that too, pass Codex's own --dangerously-bypass-approvals-and-sandbox, which is its flag and its consequences, not ours.

For the same thing in Claude Code, and for the cases where running unattended is the point — CI, containers, cron — see seland and Running unattended. The token and environment variables described there work the same for Codex.

What differs from Claude Code

Most of the main docs applies to both. These are the parts that do not:

  • No statusline. The spend and headroom line Selan installs is Claude Code's. Run selan usage for the same numbers.
  • No context limit, and no --autocompact. The window your company sets is applied by Claude Code when it compacts a conversation. Codex manages its own context and Selan does not touch it.
  • No 1M-context variant. Claude Code's picker offers some models twice, at 200k and at 1M. Codex gets each model once, at the window its provider reports.

Everything else carries across: the same session, the same spend limits, the same secret scanning before a request leaves your machine, the same Logs, and repository attribution when you run inside a git checkout.

If it did not work

  • codex not found on PATH — Codex itself is not installed. Install it, then run selan codex again.
  • The picker shows OpenAI's built-in list. Codex is not signed in to ChatGPT, so it never asked for one. See the note above — naming a model still works.
  • A model is missing from the list. Relaunch first, then check it can reach Codex at all, then ask an owner to switch it on.
  • Codex starts on the wrong model. While Codex is signed in to ChatGPT, an unnamed launch starts on the first row of the list. Name one with --model to override it for that session.
  • A bare codex refuses to start. That is the design — the credential only exists for the length of a selan codex launch. Run it through Selan.
  • Something else. The error messages are collected in Reference, and you can always ask us.