---
title: Codex provider (OpenAI CLI-backed sessions)
---

# Codex provider (OpenAI CLI-backed sessions)

## What it is

Codex is **OpenAI's CLI agent** — a coding agent in the same shape as Claude Code, but driven by OpenAI models and shipped as the `codex` binary. Omniscio supports spawning Claude-Code-style sessions backed by Codex as one of several alternative providers, alongside `claude` (the default) and the other registry providers (Gemini, Antigravity, DeepSeek, Kimi, Cursor, Hermes, Pi, …). From the user's perspective a Codex session looks identical to a Claude session: same sidebar, same streaming bubbles, same Ctrl+Enter to send, same archive / pause / snooze. The only visible signal that it's NOT Claude is the small **Codex icon** (the OpenAI "flower" logo, no text label) next to the session title in the header — the mark tells you which engine is running, and every started session shows its engine mark (Claude included, in brand orange), so a Codex session's mark is the OpenAI flower. The per-launch provider dropdown shows the same logo next to each provider's row. Unlike the other providers' marks — which render in their brand colors (Claude orange, Gemini's blue→purple→pink gradient, Anti-Gravity blue) — the OpenAI flower stays adaptive monochrome: OpenAI's logo has no official color version, so it inherits the surrounding text color (dark on light backgrounds, light on dark).

Codex is opt-in and off by default. Two readiness gates must be green before the Codex row is offered (see [How to enable](#how-to-enable)): the **Allow Codex sessions** toggle and the **Codex CLI binary**. An OpenAI API key is NOT a gate — it's optional (Codex authenticates via your own `codex login` when no key is set; see below). When a readiness gate is red, the per-launch ChangeProviderButton (on a fresh session header) and the per-project Default-provider radios (Edit Project dialog) show the Codex row as `aria-disabled` with a "Set up…" / "Install…" suffix; clicking the row deep-links you to the right Settings panel instead of trying to spawn.

## Where to find it

Crossing over to Codex is not a separate app to install and learn: it is a choice of engine, made in the same places you already choose one. Its **Settings → Accounts → Codex** panel is where the sign-in and the optional API key live, and the account pill at the lower-left of the window mirrors the same Codex logins in a lighter form. Once it is switched on, a Codex session is an ordinary row in the left sidebar — the same transcript, the same statuses, the same Ctrl+Enter — and the only visible difference is a small OpenAI flower next to the session title in the header.

The choice of *which engine* a session uses is offered in three places: on a brand-new session, where a provider picker sits above the message box; in a project's **Edit** dialog, where a project can be given a default engine for every session it starts; and, for anything created programmatically, wherever a session is created with Codex named. If Codex is not ready when you ask for it — the toggle is off or the program is not installed — the picker row is greyed out and clicking it takes you straight to the settings panel that fixes it.

## How it behaves

### How to enable

> **Master toggle required first.** Codex and Gemini are alternative providers — by default Omniscio ships as a Claude-only product, and the entire Codex setup section below is hidden in Settings → Accounts. Flip **Settings → Accounts → Show alternative AI providers** to ON (off by default) and the Codex panel appears. With the master off, the per-project "Default provider" radio collapses to a single Claude row and the session header's provider switcher (ChangeProviderButton) is hidden — Codex effectively does not exist in the UI even if every gate below is configured. Your saved API key, "Allow Codex sessions" toggle, and per-project defaults are preserved across master-toggle flips.

You need these in place:

1. **Codex CLI binary** — must be present on PATH or installable from the same Settings panel. Click the **Install Codex CLI** button to run `npm install -g @openai/codex` (or your platform equivalent); the panel polls for version and shows a green "Installed (vX.Y)" status when ready.
2. **Settings → Account → Allow Codex sessions** toggle — off by default. A small extra step so Codex isn't spawnable until you opt in.
3. **Auth — sign in to Codex, OR (optionally) paste a key.** Omniscio no longer _requires_ an OpenAI API key. If you've run `codex login` (Sign in with ChatGPT), Omniscio uses that login automatically — no key needed, and Codex usage counts against your ChatGPT plan. You don't have to find a terminal yourself: once the Codex CLI is installed, **Settings → Accounts → Codex** shows a one-click **Sign in with ChatGPT** button that runs a NON-terminal, in-app **browser** sign-in: Omniscio opens your default browser to OpenAI, catches the redirect on a local loopback, and writes the Codex login file (`~/.codex/auth.json`) itself, flipping to "Signed in to Codex" the moment it completes — no terminal window. Prefer the old flow (or you're on Linux, where the browser sign-in isn't offered)? A **"Use the terminal login instead"** link beneath it opens a real terminal and runs `codex login` in it — complete the sign-in there, then return (that terminal path can't flip to "signed in" the instant you finish, so re-open Settings to confirm). Alternatively, paste an `sk-...` key in **Settings → Account → Codex → API key** (stored encrypted via `safeStorage`, sent to the CLI as an env var, never to the renderer); a pasted key is OPTIONAL and, when present, **overrides** the CLI login (billing then goes to that API account). Omniscio also strips any stray `OPENAI_API_KEY` from your shell so it can't silently bill an API account. With neither a key nor a `codex login`, starting a Codex session shows a plain "run `codex login`, or add a key" message rather than spawning a wedged session. See [cli-login-auth-contract.md](../../.claude/memory/contracts/cli-login-auth-contract.md). **You can also start this sign-in during first-run onboarding:** if you pick **Codex** on the Setup v2 "Which AI agent do you use most?" step, an optional **"Sign in with Codex"** button runs the same in-app browser sign-in right there (installing the Codex CLI first if needed), with a **"use the terminal login instead"** fallback link, so you can connect your ChatGPT account during setup instead of finding Settings later.

Once the binary + toggle are green (and you're signed in or have a key), you can launch a Codex session in three ways:

- **Per-launch override** — on a fresh (zero-message) session, the **ChangeProviderButton** in the new session's main panel (the launch-config pickers on a fresh session) lets you pick a one-off provider before sending the first message. Non-ready providers appear `aria-disabled` with a "Set up…" / "Install…" / "Add key…" suffix and deep-link to Settings.
- **Per-project default** — Edit Project dialog (three-dot menu → Edit) has a "Default provider" section with one radio per `pickable` registry provider (Claude / Codex / Gemini / Antigravity / DeepSeek and the rest of the pickable set — 20 today, in `pickerOrder`; the set grows automatically as new providers ship). Pick Codex and the project's sidebar "+ New Session" button spawns Codex automatically.
- **Programmatically** — anything that creates a session with `provider: 'codex'` (recipes, agent-driven sessions, the API). Same readiness gates apply on the backend.

### How sessions look different

- **Codex icon in the header** — the Codex mark next to the session title (no text label; OpenAI's mark is monochrome, so it adapts to light/dark). Every started session shows its engine mark now (Claude included). Hovering reveals "Codex."
- **Omniscio behavior conventions ride as standing developer instructions (2026-08-14)** — on Codex CLI versions that support `developerInstructions`, Omniscio sends the shared engine prompt bundle through Codex's real standing instruction channel instead of only burying it in the first user message. That bundle now includes the standard/custom response-format block, the QuestionWidget/asking rules, the Plain Speak/final marker reminders, and the portable Dev Pipeline workflow when the pipeline is active. Clean Room still strips the response-format and QuestionWidget guidance.
- **Resumes by context-replay, not native rehydration (2026-06-10)** — Codex sessions run via a child process per session; if Omniscio quits (or the child dies), the process is gone and Codex has no on-disk transcript to `claude --resume` from. Instead, **sending a new message to a stopped Codex session re-spawns Codex, opens a fresh thread, and replays Omniscio's stored conversation as context on that first message**, so you continue where you left off — the same seamless resume OpenClaw and Pi use. (Multi-turn _during_ a live session is native — the same process handles every turn, no replay needed.) Earlier this was a dead end ("the old context is gone"); now it isn't.
- **A stalled Codex session shows "Continue" and resumes (2026-06-10)** — the orange "stopped responding" alert now offers **Continue** like Claude; clicking it re-spawns Codex and replays your conversation (above), so you pick up where you left off. (Earlier it showed a **[ Start a new session ]** dead-end, because Codex couldn't resume.) The honest "This Codex session is no longer running. Start a new session to continue." error now fires ONLY when the re-spawn itself genuinely fails (e.g. the binary or key is gone) — not merely because the child died. Codex sessions are also never swept by Anthropic rate-limit recovery (they don't run on your Anthropic account). See [stalled-session.md](stalled-session.md) and the [codex-rate-limit-rebalance-wedge contract](../../.claude/memory/contracts/provider-registry-contract.md).
- **Full execution access + real approval prompts (Claude parity, 2026-06-06)** — Codex runs **unsandboxed** (`sandbox_mode=danger-full-access`) at every level except the project-sandbox one below, so the agent has the same freedom a Claude agent does: it can run git, create its own worktree, and edit files wherever Claude could. Before this it ran in Codex's default `workspace-write` sandbox, which silently blocked every `.git/` write — the agent could edit files but couldn't run a single git command. It now also **asks before non-trusted commands** (`approval_policy=untrusted`): a shell-command or file-change request pauses the session, marks it **Needs You**, and shows an **Allow / Deny** prompt in the SAME permission pane Claude uses; your decision is sent back over the protocol, and anything that goes wrong **fails closed (denies)**. **Since 2026-09-23 the level follows your [Agent Permission Level](agent-permission-level.md#which-agents-it-controls) by default** — Read-only/Guarded → ask before every command, Autonomous → the project sandbox with internet access, Full trust → never ask — so choosing Autonomous no longer leaves Codex prompting on every command. **Settings → Accounts → Codex permission level** defaults to **Follow Agent Permission Level**; an upgrade moves an install still on the old default (**Ask before every command**) to it once and keeps any other level picked on purpose. The other three options override the level for Codex only: **Ask before every command** = full machine access + ask every time, exactly like Claude; **Ask only when it reaches outside the project** runs Codex _restricted to the project folder_ (sandbox `workspace-write`) and prompts only when it needs to escalate — including any command that needs the internet, since that sandbox has no network (`npm install`, `git push`); **Allow all** lets Codex run everything with full access and never asks. (Codex's `on-failure` policy is deliberately NOT offered — its sandbox isn't enforced on Windows, so it would never prompt: a dead option.) _(A 2026-06-07 fix made these prompts work at all: Codex numbers its JSON-RPC approval requests and Omniscio had been dropping the numeric-id ones, which silently hung the whole turn — see [codex-approval-numeric-id-routing postmortem](../../.claude/memory/postmortems/codex-approval-numeric-id-routing-postmortem.md).)_ Both knobs also have env kill switches (`AMC_CODEX_SANDBOX_MODE`, `AMC_CODEX_APPROVAL_POLICY`). Contract: [provider-registry-contract.md](../../.claude/memory/contracts/provider-registry-contract.md).
- **Per-session cost / token counters** — the Codex app-server protocol reports usage events; Omniscio translates them into the same `cost_usd` / `tokens_in` / `tokens_out` columns it uses for Claude, so the Stats virtual project rolls them up the same way.
- **Plan usage + token totals in the account pill (2026-06-11)** — the lower-left account popover's **"Codex usage"** section (on its **Codex tab** since 2026-06-26 — previously the Claude view) shows your ChatGPT-plan **remaining usage** (% used + reset for the ~5-hour and weekly windows, the same `MiniUsageBar` Claude's account rows use) plus tokens used over 24h / 7d / 30d. The plan bars ride in free on Codex's `account/rateLimits/updated` push as sessions run (no extra request, no token cost) and are absent under an OpenAI **API key** (no plan window); tokens are shown but never a `$` (no OpenAI pricing table). See [account-indicator.md § Codex usage section](account-indicator.md#codex-usage-section) and [provider-registry-contract.md](../../.claude/memory/contracts/provider-registry-contract.md).
- **Tool activity folds like Claude's** — when a Codex turn runs shell commands, edits files, calls MCP tools, or searches the web, each action surfaces as the same collapsed `▸ call` / `← result` activity marker Claude uses (e.g. `▸ Shell: npm test` → `← exit 0`; `▸ Edit: src/foo.ts` → `← 1 file changed`). Because those markers exist, the **real-conversation layout** folds the turn's pre-final narration into a compact "N actions" activity summary exactly the way it folds Claude's: only the turn's **final answer** renders as full prose, and the intermediate "Let me check…" / "Now I'll…" narration collapses into the expandable activity block. Before this, a multi-step Codex turn rendered as one long blob — every narration paragraph plus the answer, with no fold. (Reasoning and plan items are deliberately NOT turned into markers — they're prose, not actions. Context-compaction is not a marker either, but it is not noise: it gets its own divider — see **Compaction** below.)
- **Compactions are visible, like Claude's (2026-09-10)** — when a long Codex session fills its context window, Codex rewrites the whole history into a summary. That rewrite can take a full minute, and it used to leave **no trace at all** in the transcript: the turn simply went quiet and older context silently stopped existing. Now it shows the same two things a Claude compaction shows — a pulsing **“Compacting conversation…”** pill while the rewrite runs, then a settled **“Conversation compacted”** divider (with the pre-compaction token count when Codex reported one) at the point in the feed where it happened. The one difference: the divider has **no “Show summary” button**. That button reads the summary back out of the Claude CLI's on-disk transcript, and Codex keeps no such file — so rather than offer a button whose only possible answer is “unavailable”, the divider hides it. See [compaction-summary.md](compaction-summary.md).
- **A helper agent's words are labelled as the helper's, not the session's (2026-09-03)** — Codex can spawn its own helper agents for a task and runs them all over one connection. Omniscio used to drop the tag saying which agent a message came from, so a helper's write-up appeared **as the session's own reply** — and, worse, a helper finishing its answer could suppress the session's real one. One session's whole visible turn was a helper signing off with "I sent both findings to the parent agent", which reads as that session having messaged another session; nothing had been sent anywhere, and its own reply was missing. Now a helper's write-up lands as its own labelled sub-agent row, a helper finishing no longer ends your turn, and the helper's tool activity still shows in the main activity fold (it is activity, not speech). The delegation marker also names **what** was handed off instead of repeating an opaque `Agent: wait` — one real session showed thirteen identical ones and nothing else. Contract: [codex-robustness-contract.md](../../.claude/memory/contracts/codex-robustness-contract.md) (`sub-agent-prose-is-not-the-session-voice`).
- **Image & document attachments (2026-06-07)** — attach images and documents to a Codex message just like Claude. Images go to Codex as native image input — each is saved into the project workdir and passed by **file path** (`localImage`), not as inline bytes over the protocol pipe. Documents (PDF / Word / Excel / PowerPoint / plain-text) are saved into the project and their paths are injected into the prompt so Codex opens them with its file tools (Office files are auto-extracted to text first). **Caveat vs Claude:** Codex reads text-based PDFs, but cannot "see" scanned / image-only PDF pages the way Claude's vision can. Nothing is silently dropped — every attachment shows as a chip in the transcript, and a file that can't be read surfaces an in-chat warning instead of vanishing. Contract: [provider-registry-contract.md](../../.claude/memory/contracts/provider-registry-contract.md) §7.

Everything else — archive, snooze, pause, send-later, search, the inbox, **auto-generated session titles**, plain view, plain speak overlay, question widgets — works the same as a Claude session. Title generation in particular is provider-agnostic: the first operator message in any Codex session triggers the same `titleOrchestrator.maybeGenerate()` call that runs for Claude / Gemini / OpenClaw, so the "Session 2,702" placeholder gets rewritten to a real title within a few seconds regardless of which provider answered.

### Error states and fixes

The same readiness probe powers the ChangeProviderButton row, the per-project Default-provider radios, the project-row "!" badge, and the backend spawn guard. **Readiness no longer includes an API-key gate** (the key is optional — see [How to enable](#how-to-enable)), so there are two gap codes:

| Gap              | What it means                             | Click-to-fix lands you at…                       |
| ---------------- | ----------------------------------------- | ------------------------------------------------ |
| `toggle-off`     | "Allow Codex sessions" is OFF in Settings | Settings → Account → Allow Codex sessions toggle |
| `binary-missing` | `codex` CLI not on PATH                   | Settings → Account → Codex CLI binary panel      |

Auth (a `codex login` session or a pasted key) is NOT a readiness gate — it's checked when the session actually starts. With neither, the session surfaces a plain "run `codex login`, or add a key" message instead of a `key-missing` picker suffix — and says the conversation is saved, so after signing in you just send a message in the same chat.

**Detection survives a slow cold-start.** `binary-missing` confirms the CLI via a `--version` probe (5 s budget); under heavy app load that probe can be killed before it answers, so detection falls back to the CLI's **presence on disk** at a known install dir (npm-global / well-known paths). An installed-but-slow Codex CLI therefore never false-flags as missing, and a successful detection is cached so the check stops re-probing. See [provider-registry-contract.md](../../.claude/memory/contracts/provider-registry-contract.md) (a-cold-start-probe-does-not-report-a-present-binary-missing).

If a Codex spawn fails _after_ the gates were green (network blip, stale key, model rejected the prompt), the session lands in `error` status with the failure message in the header — same UX as a failing Claude session. There is no auto-retry; sending a new message re-spawns Codex and replays your conversation (so an errored-but-recoverable session resumes), or you can archive and start fresh.

**Outdated Codex CLI → one-click update.** If a turn fails because your chosen model needs a newer Codex than the one you have installed (e.g. _"The 'gpt-5.6-luna' model requires a newer version of Codex. Please upgrade…"_), the paused chat row now carries an **Update Codex CLI** button. It deep-links to Settings → Account → Codex CLI binary, whose button now doubles as an updater when Codex is already installed — one click re-runs the idempotent `npm install -g @openai/codex` to pull the latest, then you re-send. That replaces the old dead-end where the message just told you to "re-send to try again" against a CLI that would keep rejecting the model. (This does NOT auto-switch your model — you picked it deliberately, so the fix is to update the CLI.) Locked by [codex-robustness-contract.md](../../.claude/memory/contracts/codex-robustness-contract.md) (`outdated-cli-offers-update`).

**Archive cleanly when the child is mid-turn.** Archiving (or pausing) a Codex session that's still running terminates the JSON-RPC child via `codexSessionManager.terminate()` _before_ the archive UPDATE lands in the database — there is no race where the child fires a "needs you" status push after the row is archived and resurrects the session in the sidebar. There is also a defense-in-depth guard inside `codex-session-manager.updateStatus`: any incoming status change is dropped if the database row already reads `archived` or `paused`, so orchestration-engine / action-dispatcher / direct-DB archive paths that bypass `terminate()` are still safe. Symptom of the original bug, since fixed: "It won't let me archive this session — it stays permanently there till something happens that immediately comes back." If you ever see this on Codex again, the regression is one of those two layers.

**Robustness under stress (2026-06-15).** Several failure modes that used to wedge a Codex session are now handled cleanly: a turn the model **rejects** (usage limit, server error) shows as a red error with any partial reply kept — it no longer looks like a silent empty answer and it doesn't count toward your usage; a turn that **runs away** (loops past a size/time cap) stops on its own with the partial kept and a clear note, instead of only an app-close stopping it; **Restart** now resumes the session with its full conversation context (it used to come back looking brand-new); and if Codex asks for **two approvals at once**, both are queued and shown one at a time instead of the second silently replacing — and stranding — the first. A long pause while Codex waits on **your** approval no longer trips the stall watchdog, and non-English / emoji output is no longer occasionally garbled by a split stream frame. And if your chosen **model isn't available on your account type** — e.g. a code-tuned Codex model (`gpt-5.3-codex` / `gpt-5-codex`) that needs API-key billing while you're signed in with a ChatGPT plan (which can't run ANY `*-codex` model — OpenAI 400s them) — Omniscio automatically switches the session to a compatible general model (**GPT-5.5**), tells you in a chat note, and re-runs your message once, instead of dead-ending with a cryptic "turn ended without completing" (loop-guarded, so it never switches in circles). New ChatGPT-plan sessions also start on GPT-5.6 by default, so they don't hit this at all. Full invariants + the tests that lock them: [codex-robustness-contract.md](../../.claude/memory/contracts/codex-robustness-contract.md).

- **A wedged-but-running turn auto-restarts instead of dead-ending (2026-08-06).** When the stall / turn-cap watchdog force-recover fires on a Codex session that is still `running` (e.g. one turn ran past the 4-hour cap because its commands kept timing out under load), Omniscio now tears down the stuck app-server and re-runs your last message on a fresh one — you see "Codex appeared stuck — restarting…" instead of the terminal "Codex stopped responding and couldn't recover. Start a new session to continue." It retries up to 2 times by default (`AMC_CODEX_STALL_RECOVERY_MAX`); only if the turn is genuinely stuck does the honest terminal error still run. Full invariants + the tests that lock them: [codex-robustness-contract.md](../../.claude/memory/contracts/codex-robustness-contract.md).

**Your Codex accounts survive a data-folder move.** Each managed Codex account keeps its sign-in in its own private folder inside Omniscio's app data. If that app-data folder is ever renamed or moved, Omniscio re-points each account to its new location the next time it starts, so an account does not silently read as signed-out and can still be removed. Before this, an account stranded that way refused to be removed at all and behaved as though it had never been signed in. Implementation detail and the safety rules that constrain it live in [provider-registry-engines-core-codex-persistent-external-contract.md](../../.claude/memory/contracts/provider-registry-engines-core-codex-persistent-external-contract.md) (CX-32).

## Related

Codex is one of several alternative engines Omniscio can run sessions on: [Gemini](gemini-provider.md) uses the same launcher, readiness check and per-project default with a different binary and credential, and [OpenClaw](openclaw-provider.md) is the remote-gateway alternative. Claude itself needs no toggle at all — its setup is on the [Claude accounts](add-a-claude-account.md) page — and what happens when a session stops responding is on the [stalled session](stalled-session.md) page.

This page is split across three parts: [part 2](codex-provider-part-2.md) covers the managed Codex accounts, the per-project default and the model and reasoning-effort chips, and [part 3](codex-provider-part-3.md) covers what actually runs when a Codex session starts, and the files involved.

- [codex-robustness-contract.md](../../.claude/memory/contracts/codex-robustness-contract.md) — turn-lifecycle robustness invariants (failed-turn honesty, runaway cap, frame/decoder safety, approval-hang + concurrent-approval queue, busy-guard, restart-resume, account integrity) + the tests that lock them
- [gemini-provider.md](gemini-provider.md) — same launcher / readiness / per-project-default model, different binary + credential
- [openclaw-provider.md](openclaw-provider.md) — separate "alternative provider" model (remote WebSocket gateway, not a local CLI)
- [add-a-claude-account.md](add-a-claude-account.md) — Claude account setup (the default provider; no toggle needed)
