Codex

Agentby Tori @gettoriApache-2.0Bundled
Verified against
codex-cli 0.155.1 with @agentclientprotocol/codex-acp 1.12.0Measured Sep 20, 2026
Platforms
macOS, Linux, Windows
Install
Tori installs it with npmnpm install -g @openai/codex
Needs Tori
26.1009.0 or newer
Schema
Version 4
Id
codex
Source file
agents/codex.toml ↗gettori/packs on GitHub

Add it in Tori

  1. Open Settings with the gear in the title bar.
  2. Go to Agents.
  3. Codex is already there: it ships inside Tori. When the catalog has a newer version, Add an agent lists it with Update.

Adding writes one file and runs nothing. Installing it with npm is a separate click on its card.

Use it without the catalog

Download the file and drop it in the folder below. Tori loads it the next time it starts.

Download file codex.toml
~/.config/tori/packs/agents/

Chat and accounts

ChatChat over ACP

Tori opens a chat pane next to the terminal and talks to Codex through the Agent Client Protocol.

AccountsOne account

Tori uses whichever account the agent is signed in to.

Usage readoutsShown

Tori shows remaining usage for each account in the sidebar.

The file

codex.tomlRead only
1schema_version = 42id = "codex"3label = "Codex"4description = "OpenAI's Codex CLI, with chat over ACP"5license = "Apache-2.0"6contributor = { name = "Tori", github = "gettori" }7icon = "codex"89# Measured against this pair with10# `node dev/acp-probe.mjs --agent codex-acp --per-model`, most recently11# 2026-09-20. Two versions because12# two binaries are involved: the PTY tab runs the `codex` a user installed, and13# the chat surface runs the ACP wrapper below, which drives that same `codex`14# underneath. `verified_against` is compared against `codex --version`, and15# health.rs reads the first semver-looking token, so the `codex-cli` version has16# to come first.17verified_against = "codex-cli 0.155.1 with @agentclientprotocol/codex-acp 1.12.0"18verified_on = "2026-09-20"1920[launch]21program = "codex"22# The TUI, for a PTY tab. Unrelated to the chat surface below, which launches23# the ACP wrapper instead.24base_args = []25# Codex's own "skip all confirmation prompts and execute without sandboxing".26# Its help calls it EXTREMELY DANGEROUS, the same standing as claude's27# `--dangerously-skip-permissions` and opencode's `--auto`.28yolo_args = ["--dangerously-bypass-approvals-and-sandbox"]29# Empty, which the UI reads as "this agent's sessions can't be resumed" (see30# ADAPTERS.md) rather than mis-resuming. Codex does have its own resume, but the31# id Tori holds for an ACP row is Tori's own: see opencode.toml for the full32# reasoning, which applies here unchanged.33resume_args = []3435# No [discovery], [parser] or [running]: a protocol-backed adapter reaches its36# sessions through ACP, never through files. See opencode.toml.3738[capabilities]39pty_quiet_ms = 200040# Not claimed. The quiet-PTY join is Claude-shaped and unmeasured against41# Codex's TUI, and a chat tab does not need it: over ACP the agent asks42# in-protocol and Tori renders the question.43needs_you = false44hooks = false4546# --- schema v3: accounts ---47#48# Measured 2026-08-14 against the `codex-cli` named in `verified_against`.49#50# `codex login status` puts the entire answer in its exit code: 0 signed in, 151# not, with the prose ("Logged in using ChatGPT" / "Not logged in") on **stderr**52# and stdout empty. So `whoami_kind = "exit_code"`, and Tori learns no account53# name from it - Codex does not print one, and inventing a parse of that prose54# would be a guess about a sentence nobody promised to keep.55#56# **No `home_env`, and `supports_isolation` is absent (so false).** `CODEX_HOME`57# does relocate the credential store: pointed at an empty directory, the probe58# reports not-logged-in while the real home stays signed in. What has *not* been59# measured is the thing isolation actually claims - two accounts holding60# simultaneous logins without one signing the other out - because that needs a61# second Codex account. Until somebody runs it, Codex offers no "add account"62# action, which is the honest rendering of "we do not know".63[accounts]64login_args = ["login"]65logout_args = ["logout"]66whoami_args = ["login", "status"]67whoami_kind = "exit_code"6869# --- schema v4: usage ---70#71# **No `sessions` rung, measured rather than assumed.** The `app-server`72# underneath does send `account/rateLimits/updated` around a turn, but73# `codex-acp` 1.2.0 files it into its own state and emits no session update74# (`acp_transport::tests::codex_forwards_no_rate_limits_over_acp`, 2026-09-06);75# the only way back out is `/status`, as markdown prose. So Codex's quota costs76# a read Tori schedules for itself: `usage_probe.rs` drives77# `codex app-server` for `account/rateLimits/read`, which answers the two78# windows, the plan and the credit balance in one exchange.79[usage]80sources = ["cli"]8182[chat]83transport = "acp"84# **Codex is the one bundled adapter whose chat binary is not its launch85# binary.** `codex app-server` exists and other clients drive it, but `codex` has86# no `acp` subcommand, so the first-party wrapper is how Codex reaches an ACP87# client. Measured 2026-08-14 against both on one live turn: the wrapper carries88# the permission prompt, the exact before-and-after diff, the same four models89# and the same token-only usage that the native app-server does, for one TOML90# file instead of a second typed transport over `codex app-server generate-ts`.91# That surface is also moving: it went from 598 files / 6,230 lines on 0.144.5 to92# 642 / 6,923 on 0.147.0, three patch versions apart and inside one afternoon.93# What the wrapper gives up is `thread/archive`, `thread/rollback`,94# `thread/fork` and `turn/steer`, none of which Tori drives over ACP anyway.95program = "npx"96# Pinned to the version measured, matching how the ACP catalog pins its own97# rows. `npx -y @agentclientprotocol/codex-acp` unpinned would silently move the98# agent underneath a `verified_against` that names 1.12.0.99base_args = ["-y", "@agentclientprotocol/codex-acp@1.12.0"]100101# All empty because ACP has no command line for any of it, not because Codex102# lacks the feature. Measured on the handshake instead:103#104#   * ids are minted by the agent inside `session/new`,105#   * resume is `session/load`; `sessionCapabilities` advertises106#     `resume, list, close, delete, additionalDirectories`,107#   * a model switch is `session/set_config_option`,108#   * modes arrive as config options: `mode` (read-only, agent,109#     agent-full-access) and `collaboration_mode` (default, plan),110#   * reasoning effort is a `thought_level` select with six levels111#     (low, medium, high, xhigh, max, ultra).112#113# Re-measured 2026-08-17 with the catalogue probe (`catalog_probe.rs`, live test114# `the_real_codex_answers_a_catalogue_from_one_session`), which reads the same115# handshake without submitting a turn. Four config options, and two findings116# worth keeping:117#118#   * the effort selector's **id is `reasoning_effort`** while its **category is119#     `thought_level`**. Tori selects by category, which is the only reason it120#     finds this at all: opencode's ids happen to match their categories, and121#     matching on the id here would have found nothing.122#   * `collaboration_mode` is categorized as *itself*, so no bespoke control123#     claims it. It is the first live option to reach the chat's generic mirror,124#     and before that mirror existed it was read off the wire and dropped.125#126# `session/list` is advertised and answered, **scoped to the asking session's127# cwd**: a chat in a project directory is told about that directory's sessions128# and nothing else. So a probe session in Tori's probe directory is out of a129# user's history twice over, the agent's scoping and `adopt`'s own filter.130session_id_args = []131resume_args = []132fork_args = []133model_args = []134effort_args = []135mode_args = []136add_dir_args = []137138# No [[chat.models]].139#140# Measured 2026-09-20: the handshake advertises five (`gpt-5.6-sol`,141# `gpt-6-astra`, `gpt-5.6-terra`, `gpt-5.6-luna`, `gpt-5.5`). There is no142# shortfall to publish,143# and the list is per account: signed *out*, the same call returned seven, which144# is a reminder that a catalogue measured without an account is not this user's.145# A bundled table would be a guess about somebody else's entitlement, and the146# picker takes the live list whenever there is one.147148# No [[chat.modes]] or [[chat.effort]] either: all three selectors above arrive149# on the handshake, which is what the ACP transport reads them from.150151[chat.acp]152# Measured doing its own file I/O, so the client's fs stays declined.153serve_client_fs = false154# Measured with dev/mcp-probe.mjs --acp on 1.12.0: it starts a server handed in155# `mcpServers`, passes the `env` pairs through, and the model calls the tool156# with no `session/request_permission`.157send_mcp_servers = true158159[install]160# npm names the package that ships the launch binary, and all three verbs were161# run on macOS. The binary lands in npm's global bin, which has to be on the162# login shell's PATH for Tori to find it.163program = "npm"164args = ["install", "-g", "@openai/codex"]165update_args = ["install", "-g", "@openai/codex"]166uninstall_args = ["uninstall", "-g", "@openai/codex"]