---
title: Codex provider (OpenAI CLI-backed sessions) (part 2)
---

# Codex provider (OpenAI CLI-backed sessions) (part 2)

## What it is

This is part 2 of the [Codex provider (OpenAI CLI-backed sessions)](codex-provider.md) page. It covers the Codex sign-ins Omniscio keeps for you, the choice of a default engine for a whole project, and the model and reasoning-effort chips a new Codex session carries.

## Where to find it

Codex sign-ins live in **Settings → Accounts**, on the **Codex** tab beside the Claude accounts, and the account pill at the lower-left of the window shows the same rows in a condensed form. A project's default engine is set from that project's three-dot menu under **Edit → Default provider**, and the model and reasoning-effort chips appear on a brand-new session next to the provider picker, before you send your first message.

## How it behaves

### Managed Codex accounts

> **What this is, in one paragraph (for an outside reader with no repo access):** Omniscio can hold **several ChatGPT-backed Codex logins at once** and let you choose which one runs each session — the same way it already manages multiple Claude accounts. Each "account" is a separate, self-contained login that Omniscio owns; they do **not** share one global sign-in, and Omniscio never touches your personal `~/.codex` folder. You manage them in **Settings → Accounts → Codex**, see them mirrored in the lower-left account popover, and (optionally) pick a specific one for a brand-new Codex session before you send its first message. This first version is **manual only** — there is no automatic load-balancing or spillover between Codex accounts (Claude has that; Codex in v1 does not).

> **Shipped/public build — one account, no switching.** In a public build the multi-account management described here is **capped to a single account**: you sign into **one** ChatGPT/Codex account, and the **"Add a Codex account"** button is hidden once you have one — so there is no second account and no per-session switching. The full multi-account experience (several logins, a per-session pick, switching) is available in owner/dev builds.

#### Why this exists

Before this, Omniscio treated Codex as **one shared login** with a single global usage rollup — fine for "how many tokens did Codex burn," but it couldn't show a real list of separate accounts, separate identities, or per-account usage the way the Claude accounts page does. If you had two ChatGPT plans you wanted to rotate between, Omniscio couldn't represent them honestly. Managed Codex accounts fix that: each login is a real, independent row.

#### How Omniscio keeps the logins separate (isolated CODEX_HOME)

Codex normally stores its sign-in in one place (often the OS keychain), so a second `codex login` just overwrites the first — every login collapses into one. Omniscio avoids that by giving **each managed account its own private `CODEX_HOME` directory** under Omniscio's app-data folder (`<userData>/codex-accounts/<account-id>/`). Inside each one, Omniscio writes a small `config.toml` that sets `cli_auth_credentials_store = "file"`, which forces Codex to save that login's tokens to a file **inside that folder** (`auth.json`) instead of the shared keychain. The upshot: each account is genuinely self-contained — its credentials, config, and session state live in its own directory and can't clobber another account's. **Your personal `~/.codex` is never read or modified** — Omniscio-managed accounts are a parallel, Omniscio-owned world.

**How the slot's folder reaches `codex login` differs by platform**, and getting this wrong is what made macOS sign-ins land in the wrong place. On Windows the terminal Omniscio opens is a child of the process it spawned, so it simply inherits `CODEX_HOME`. On macOS it is not: Omniscio asks Terminal.app to run the command, and Terminal.app is a separate application with its own environment, so anything set on the spawning process is discarded before `codex login` ever starts. macOS therefore carries the variable **inside the command text**, via `/usr/bin/env CODEX_HOME=… codex login`. `/usr/bin/env` is used rather than a bare `CODEX_HOME=… codex login` prefix because that prefix is shell syntax that does not exist in the csh/tcsh family, and Terminal runs whichever shell your profile specifies — `env` behaves identically in all of them. The same mechanism carries `GROK_HOME` for managed Grok accounts.

#### The Settings → Accounts surface (Claude | Codex tabs)

**Settings → Accounts** is now a two-tab surface: a **Claude** tab (the existing Claude accounts) and a **Codex** tab. The internal tabs live inside the same "Accounts" section — this is not a new top-level Settings section. The Codex tab is the primary place to manage Codex logins. Each managed account row shows:

- the account **email**
- a **plan label** (e.g. the ChatGPT plan type)
- **remaining-usage bars** for the ~5-hour and weekly windows **when that data is available** (the same `MiniUsageBar` the Claude rows use)
- **`Active`** (if it's the current default) or a **`Switch`** button to make it the default
- a **`Remove`** button (confirm-gated — removing an account can't be undone)
- honest **degraded / "Signing in…" / stale** states when an auth or quota read hasn't completed or has failed (Omniscio never fabricates an email or usage bar it doesn't have)
- a working account whose email Omniscio hasn't learned yet reads **"Signed in to Codex"** — never "Not signed in yet", which is reserved for a row that genuinely has no working sign-in

**How the email and plan get filled in.** A browser sign-in saves the account's email and plan the moment it finishes, read from the sign-in itself, so the new row names the account straight away. Opening the Codex accounts list (the Settings tab or the popover's Codex tab) then looks up the identity of any account still missing an email — once per app launch per account, so an account that legitimately has no email (an API-key login) isn't re-checked on every open. A slot still at "Signing in…" is re-checked every time the list opens. The row's refresh icon runs the same lookup on demand.

Two controls add accounts/credentials:

- **`Log In with ChatGPT`** — creates a brand-new managed account **slot** and opens `codex login` **in a real terminal window pointed at that slot's isolated `CODEX_HOME`**. You complete the ChatGPT sign-in in that terminal; the button can't flip to "signed in" the instant you finish, so re-open Settings to confirm. The very first account you create becomes **active** automatically.
- **OpenAI API key (optional)** — a **separate** control, kept visually apart from the managed-account list. A pasted `sk-…` key still works exactly as before and **overrides** the ChatGPT login (billing then goes to that API account). This is intentionally NOT part of the managed-account list in v1 — the tracked v1 path is ChatGPT-backed Codex logins.

#### The lower-left account popover (lighter Codex mirror)

The account pill in the lower-left of the window now has a **`Codex` tab** that **mirrors the same managed accounts** in condensed form — same rows, same `Switch` / `Remove` / refresh / `Log In` actions, backed by the exact same data. It is deliberately **lighter** than Settings: **no balancing header** (no "accounts in use" count, no "Balancing" label), and **no API-key control** (Settings owns that). (Separately, the popover also still shows the older pool-wide **"Codex usage"** section — plan bars + token totals summed across Codex sessions; that is a different surface and is unchanged.)

#### Which account a new session uses (Omniscio picks the active one)

Account choice is **automatic** — Codex accounts are managed like Claude accounts, Omniscio chooses:

- **With one managed account (or none):** every new Codex session runs under the **active** managed account — or the global `~/.codex` single-login when you have no managed accounts at all. There is **no per-session account picker**; you manage Codex logins in **Settings → Accounts → Codex**.
- **Off by default — balancing is only on for designated accounts.** By default every Codex session runs on your single **active** account; Omniscio does **not** automatically spread work across, or fail over between, multiple Codex logins. Multi-account balancing turns on **only for an account an admin has specifically designated** for it. This is deliberate: OpenAI's terms don't allow automatically hopping across accounts to get around per-account usage limits, so a normal user (and every single-user install) stays on one account.
- **For a designated account with two or more managed logins, Omniscio BALANCES automatically.** At launch a new session is placed on a **non-exhausted** account (reading each account's saved plan-usage), and a launch burst is spread across your accounts rather than piled onto one. The session authenticates against that account's isolated `CODEX_HOME` ([codex-session-manager.ts](../../src/main/services/engines/codex-session-manager.ts) `launch`).
- **Automatic switch on a usage limit (designated accounts only).** If a running Codex session on a designated account hits its account's usage limit, Omniscio moves it to another signed-in account that still has room and re-runs the turn — you'll see a short "switching to another signed-in account" note. If **every** account is out of quota (or the account isn't designated), the session waits it out on the same account (the ember "waiting" state) and auto-resends when the quota window resets, rather than switching.
- This Codex balancing is **completely separate** from Claude's — it only ever touches your managed Codex logins, never your personal `~/.codex`, and never changes which account is marked "active" for new sessions. An operator can force it on for their own machine with `AMC_ENABLE_CODEX_MULTI_ACCOUNT=1`, or turn it off entirely with `AMC_DISABLE_CODEX_ACCOUNT_BALANCE=1`. Designation takes effect the next time the designated user signs in.

#### What "owns" a session's usage

Each Codex session is stamped with a **`codex_account_id`** — a field that is **parallel to**, and completely separate from, Anthropic's `account_id`. A Codex session never carries an Anthropic `account_id`, and a Claude session never carries a `codex_account_id`. Live plan-usage snapshots (Codex's `account/rateLimits/updated` pushes) and new per-turn cost rows are routed to the **owning** managed account. Historical Codex cost rows recorded before this feature stay under the legacy synthetic shared id (`openai-shared`) and are kept readable as legacy history — the global Codex usage rollup still includes both.

#### What Codex balancing deliberately does NOT do

- **No balancing UI.** There is still no balancing header, "accounts in use" count, or pool-level coverage forecast on the Settings page — that visual layer stays Claude-only. The balancing here is behind-the-scenes account **selection**, not a dashboard.
- **No per-session account picker.** You don't choose an account per session; Omniscio places and switches sessions for you (manage logins in Settings → Accounts).
- **No mutation of your personal `~/.codex`.** Managed accounts are Omniscio-owned and isolated, and balancing never touches the global login or the "active" flag.

### Per-project default

Each project remembers a default provider in the `projectDefaultProviders` setting (a `Record<projectId, ProviderId>`, constrained to the registry's 20 `pickable` ids, validated against `PICKABLE_PROVIDER_ID_VALUES` — so the accepted set is whatever the registry currently marks pickable, and it grows automatically as new providers ship). Empty by default — every project falls back to Claude. Change it from the project's three-dot menu → Edit → Default provider radios; the change persists immediately.

You can also set the default via the CLI control server with a single per-project PATCH — no read-merge-write of the global Record map needed: `curl -X PATCH -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{"defaultProvider":"codex"}' http://127.0.0.1:19519/project/<projectUuid>`. Pass `null` to clear the override and fall back to Claude. See [cli-control.md § `PATCH /project/:id`](cli-control.md) for the full field list.

When you set a project's default to Codex but Codex isn't ready (toggle off, binary missing, or key missing), an amber **"!" badge** appears on that project's sidebar row. Hover the badge for a tooltip explaining the gap; click it to deep-link straight to the right Settings panel. The badge re-checks on every render, so fixing the gap clears it without a refresh. Claude defaults never show the badge — Claude is always considered ready.

### Choosing the model and reasoning effort

A fresh Codex session lets you pick **which OpenAI model** runs it and **how much reasoning effort** it spends — the same way you pick the provider. While the session is still blank (it shows **"Start a new session"**), the launch-config pickers carry two extra chips:

- **Model** — **GPT-6.1 Sol** (the default), **GPT-6 Astra**, **GPT-6 Sol**, **GPT-6 Luna**, **GPT-5.6 Sol**, **GPT-5.6 Terra**, **GPT-5.6 Luna**, or **GPT-5.5** — all models a **ChatGPT-plan login can run** (they are exactly what OpenAI serves that login; an API-key login runs them too). These are the REAL Codex model ids: the GPT-5.6 line ships as the named `-sol` / `-terra` / `-luna` variants — there is no bare `gpt-5.6` (sending one makes OpenAI reject the turn). The dedicated code-tuned `*-codex` line (and bare GPT-5) is no longer offered in the picker. With no explicit pick, Omniscio honors a model set in your own `~/.codex/config.toml`, otherwise starts the session on **GPT-6.1 Sol** so the first turn isn't rejected.
  - **The default is the cheapest-and-best successor, never the priciest model.** **GPT-6.1 Sol** was listed first *and* made the default on **2026-09-29**, the day it landed: it is OpenAI's newest flagship and costs the SAME as GPT-5.6 Sol — so moving to it is not a hidden price rise. **GPT-6 Astra** is the opposite case and is deliberately *not* the default: OpenAI's most capable model and its priciest — roughly **8x GPT-6.1 Sol's rate for what you send and 5x for what it writes** — so it is a pick you make on purpose, never the one you land on by not choosing.
  - **It needs a recent Codex.** Astra requires **codex-cli 0.153.3 or newer**. On an older Codex the turn is refused by OpenAI with "The 'gpt-6-astra' model requires a newer version of Codex" — update Codex (Settings → Connected Tools) and it works. Omniscio cannot hide the option based on your Codex version yet, so that message is how you find out.
- **Reasoning effort** — **Low / Medium / High / Extra High / Max / Ultra** (Codex's own scale — it has no _Auto_, unlike Claude's Thinking levels, and it goes one step deeper with _Ultra_).
  - **The deepest levels depend on the model**, and Omniscio only shows you the ones your chosen model actually accepts: GPT-6.1 Sol, GPT-6 Astra, GPT-6 Sol, GPT-5.6 Sol and GPT-5.6 Terra take the full range; **GPT-6 Luna** and GPT-5.6 Luna stop at _Max_; GPT-5.5 stops at _Extra High_. Switch models and the list adjusts — if the level you already picked isn't available on the new model, it stays visible so you can see and change it rather than silently vanishing.
  - **_Minimal_ was removed on 2026-09-04.** OpenAI withdrew it from every Codex model, and any session started on it was rejected before its first turn. If you had it saved as a default, that default is simply ignored now and the model's own default applies.

Both are staged locally and applied in one step **when you send your first message** (nothing spins up on tap), then lock in — exactly like the provider chooser. Under the hood Omniscio passes each pick to the Codex app-server as a `-c model=…` / `-c model_reasoning_effort=…` config override (the same mechanism it already uses for the sandbox mode), and validates your pick against Codex's own model/effort vocabulary at launch — so a stale value left over from a different engine is dropped rather than sent. These chips are Codex-specific; the model list and effort scale are Codex's, never Claude's. See [start-a-new-session.md](start-a-new-session.md) for the shared picker behavior and [provider-registry-contract.md](../../.claude/memory/contracts/provider-registry-contract.md) for the per-provider design.

#### Claude via Gateway route

Codex can also run **real Claude models** through a managed **Claude via Gateway** route. This is still a Codex session: Codex remains the harness, approval engine, MCP/config owner, and process being launched. The route changes only how the model is reached — OpenAI/Responses in, Anthropic out.

There are two backends behind the one route, chosen automatically at spawn:

- **Preferred — live streaming via the local proxy.** If you've done a one-time **Claude sign-in** (Settings → Accounts → Other AI tools → "Sign in with Claude"), Omniscio routes the route through its already-bundled local proxy (CLIProxyAPI), which streams Claude's reply back token-by-token — the same live typing you get in a native Claude session. This uses your **own Claude subscription** capacity (no API key to paste, no per-token credit charge). The Claude sign-in is a normal browser approval: click "Sign in with Claude", approve in the tab that opens, done — your login stays on this device in the proxy's private store.
- **Fallback — the built-in gateway (no sign-in, buffered).** With no Claude sign-in, the route uses Omniscio's app-owned in-process loopback gateway, which translates `/v1/responses` to Anthropic Messages using your Anthropic API key. It works with zero setup but returns each reply all at once (no live streaming). Existing "Claude via Codex" users keep working unchanged.

Native Codex stays the default route and continues to use OpenAI/Codex auth.

Important boundaries:

- The route is `provider = codex`, `route = claude-gateway`; it is not a new provider. Both backends write `wire_api = "responses"` into the session's **managed** `CODEX_HOME` (never your global `~/.codex/config.toml`), under **distinct** model-provider block ids so switching backends never reuses a stale block.
- Credentials stay in the main process / proxy only. Codex config references a local bearer-token env var; it never contains an Anthropic key or your Claude login.
- The Claude sign-in card is gated behind the same `proxy-models` feature as the GPT/Grok sign-ins and rides the existing `proxy-signin:*` control channels (no new channel).
- Route-aware validation keeps native Codex GPT models and Claude gateway models from leaking across routes.

Contract: [codex-claude-gateway-contract.md](../../.claude/memory/contracts/codex-claude-gateway-contract.md).

#### A custom provider via Codex route

The same idea, generalized: Codex can run **any AI provider you've set up as a Custom Provider** — a vendor endpoint you added yourself, or one of OpenRouter's models through the built-in OpenRouter preset. Pick it in **Settings → Sessions → How each AI connects**, on the Codex row: _A custom provider via Codex_.

It's still a Codex session — Codex is the harness, the approval engine, and the process being launched. Only the brain changes.

How it works, in one line: Codex talks to Omniscio's bundled local proxy in OpenAI's format, and the proxy translates each turn to whatever your vendor speaks and streams the reply back.

What you need first:

1. A **Custom Provider** set up with its API key (Settings → Accounts → Custom providers). The route's model list is exactly the models you configured there — nothing else, because nothing else has an endpoint behind it.
2. A **managed Codex account** (Settings → Accounts → Codex), since the route writes its config into that account's private folder rather than your personal `~/.codex`.

Two behaviors worth knowing:

- **It bills your vendor, not Omniscio.** The turn goes to your own provider on your own API key, exactly like your Claude Code custom-provider sessions. There is no new charge from Omniscio.
- **There is no quiet fallback.** If the provider has no API key set — or the local proxy can't start — the session refuses to start and tells you which provider to fix, instead of silently sending your turn somewhere else. That is deliberate: the Claude fallback above speaks _only_ Anthropic, so falling back here would send (say) a DeepSeek turn to Anthropic on your Anthropic key and bill the wrong vendor for the wrong answer.

Only **OpenAI-compatible** custom providers appear on this route. An Anthropic-compatible one is reached by pointing the Claude harness at it directly, so there's no OpenAI-format surface for Codex to talk to — offering it would just stage a model that can never answer.

The route is `provider = codex`, `route = custom-provider`, and like the Claude route it writes `wire_api = "responses"` into the **managed** `CODEX_HOME` under its own distinct block id. Your vendor's API key never enters Codex's config — it stays with the proxy, and Codex only ever sees a local loopback token passed as an environment variable.

## Related

Running a Codex session at all — the readiness gates, the engine mark in the header and how a Codex session behaves day to day — is on the [Codex provider (OpenAI CLI-backed sessions)](codex-provider.md) page, and what runs underneath it is in [part 3](codex-provider-part-3.md). The Claude-side equivalent of this account management is on the [Claude accounts](add-a-claude-account.md) page, and the two engines that share this launcher are described in [Gemini](gemini-provider.md) and [OpenClaw](openclaw-provider.md).
