Repository navigation
Command Reference
The installed binary remains authoritative: use codex-switch --help and codex-switch <command> --help for the exact flags and examples supported by your version.
Custom API providers (Beta): save Responses-compatible endpoints and API keys, configure multiple models with per-model reasoning and web_search, fetch a gateway model catalog, and launch Codex. Compatibility depends on the gateway and selected model. Providers do not show ChatGPT quota or participate in ChatGPT automatic account selection.
| Command | Purpose |
|---|---|
login [--device] [alias] |
Add or reauthorize a profile through browser PKCE or device-code login. If the alias already exists, it is reauthorized; otherwise a new profile is created. |
import <path> [alias] |
Validate and import one auth.json, or recursively scan a directory for JSON files. The alias applies to single-file imports only; directories auto-assign aliases. An account that is already saved (same file, or same account_id and email) is skipped instead of duplicated, so its single-use refresh token is not spent. |
export [FILE] [--plaintext [--yes]] [--force] [--passphrase-stdin] [--no-providers] [--no-config] |
Write every saved profile, custom provider (API key and models.json included) and config.toml into one bundle, default ./codex-switch-<YYYYMMDD-HHMMSS>.csbundle, mode 0600. The bundle is encrypted with AES-256-GCM under an Argon2id key (m = 64 MiB, t = 3, p = 1); the whole header is authenticated. The passphrase is prompted twice, or read from the first stdin line with --passphrase-stdin; it is never taken from argv or the environment. An existing file is refused unless --force. --plaintext writes an unencrypted bundle and needs interactive confirmation or --yes (always --yes under --json or without a TTY). Caches, logs, deleted profiles, recovery/ and Codex-owned files are not exported. Refresh tokens are single-use: the exported accounts stay valid on the source, and using one account on both machines makes one of them log in again. |
import <bundle> [--strategy skip|overwrite|merge] [--dry-run] [--yes] [--activate[=ALIAS]] [--passphrase-stdin] [--replace-live] |
Import an export bundle, detected by content ("format": "codex-switch-export"), not extension. Offline: no Usage API call, but the managed workspace policy, the account_id requirement and the identity rules still apply, and any invalid entry aborts before a write. Same account (account_id + email) or same provider (alias + identity_id) with different content, or a different config.toml, is a conflict handled by --strategy (default skip; overwrite replaces after a backup; merge keeps the newer credential by last_refresh and adds only missing config.toml keys; provider merge is treated as skip). A different account under a taken alias (case-insensitive) is always imported under <alias>_2. Email-only matches, and accounts saved under several local aliases, are skipped as ambiguous; an account that appears more than once in the bundle is written once, from the entry with the provably newest last_refresh (none if that cannot be shown). overwrite/merge, replacing the live auth.json, providers that add codex_config overrides, and any write from an unencrypted bundle need confirmation or --yes; the plan lists each provider's base_url and override count. --dry-run prints the plan and writes nothing; [proxy] in config.toml is flagged "machine-specific, review". Replaced files are backed up under import-backups/<UTC timestamp>/ with a journal.json; an error rolls back. An import interrupted by a crash leaves an in-progress journal that maps every replaced path to its backup; the next import refuses and prints those pairs, and import --dry-run, use, launch and export warn. current changes only with --activate (default alias: the source machine's current account), which, like use, will not overwrite a live auth.json that belongs to no saved profile without interactive confirmation; when that live file is the same account as the profile being activated and cannot be shown to be older than it, --activate refuses outright, on a terminal too, before anything is written. When the local current profile is updated, its live auth.json is replaced too only if it belongs to the same account (same account_id and email; a live file without an account_id is never replaced) and is provably older than the imported credentials (same refresh_token, or an earlier last_refresh); otherwise merge skips the profile and overwrite skips it unless --replace-live is given. A live file of another account is never touched. JSON items carry replaces_live. Exit status: 0 when every item was written or is already identical locally; 1 when any item was skipped or ambiguous (its content then exists only in the bundle) — --json prints one object with ok:false and code nothing_imported (nothing written) or partial_import (the other items were written and stay), plus written / not_imported counts, and the text output says to keep the bundle instead of deleting it. Without a terminal or with --json, any write from an unencrypted bundle and any provider with codex_config overrides needs --yes, otherwise the import stops with exit 1 before writing. Identical copies of one account in a bundle count once. Bundle-only flags on an auth.json path, or an alias with a bundle, are usage errors (exit 2). |
doctor [--desktop-codex <path>] |
Check the selected Codex runtime and, optionally, a desktop app's explicitly supplied bundled engine. Runtime selection uses CODEX_SWITCH_CODEX, then PATH, then known macOS desktop installations. A missing PATH CLI alone does not fail a healthy desktop-only setup. Invalid selected or explicitly supplied engines produce a nonzero exit. |
list [-f] |
Show profiles, usage, and availability; -f / --force bypasses the cache. |
use [alias] [--consume-card] |
Switch explicitly, or omit the alias to auto-select with the unified scoring algorithm. When the pool is exhausted, --consume-card consumes the earliest-expiring reset card to revive an account (auto-select only; ignored when an alias is given). |
launch [alias] [--consume-card] [--model <id>] [-- <codex-args>] |
Requires a selected Codex engine at or above the supported minimum 0.159.2, checked before account selection, reset-card consumption, provider run creation, or credential staging. A definitively older version is refused; a version that cannot be determined (probe timeout, error or unparseable output) only prints a warning on stderr and the launch continues. A prerelease of the minimum (for example 0.159.2-rc.1) counts as meeting it. This is the project's support baseline, not a statement that older Codex releases cannot work independently. Start Codex with the best (or specified) ChatGPT profile's auth, or with a custom API provider when alias names one. A ChatGPT launch adds --no-daemon when codex --help lists it (see Automation contract); for a ChatGPT profile, --model is forwarded to Codex as --model. Provider runs retain the default CODEX_HOME and use a separate native Codex profile for each run (--profile cs-*); resume resolves only that provider's sessions and passes an exact session ID. --last follows Codex cwd/visibility filters, and bare resume opens a provider-scoped picker. For a provider, --model before -- selects a saved model; after -- it is Codex's own --model. A known Codex subcommand (exec, resume, …) can start the argv without --. Tokens on both sides of -- are kept. Auto-select (no alias) is ChatGPT-only. |
provider add <alias> --base-url <URL> (--model <id> | --fetch-models) |
Save a custom API provider. HTTPS is required unless --allow-insecure-http is explicitly passed; the URL is validated before the API key is requested. --model is repeatable; the first is the default. --fetch-models imports chat slugs from GET {base_url}/models (embedding/reranker omitted; catalogs larger than 48 must use --model or TUI f). The API key is read from a hidden prompt, or from stdin with --api-key-stdin — never from argv. |
provider list |
List saved providers (no keys). |
provider show <alias> |
Show one provider; the key is redacted. |
provider fetch-models <alias> [--model <id>] |
Replace saved models with chat slugs from the provider's GET /models. Matching ids keep reasoning / web_search. Large catalogs require --model. |
provider probe <alias> [--model <id>] |
POST {base_url}/responses with only model (no input) to see if Codex can use the slug. Does not generate tokens. Default: every saved model. Results are kept 7 days (scoped to the model, credential and effective connection settings); launch re-checks a saved unsupported result live before refusing. |
provider rename <old> <new> |
Rename a provider (directory + derived ids). |
provider remove <alias> [-y] |
Delete a provider and its stored key; -y / --yes skips the prompt. Non-interactive and --json runs require --yes. |
reset-card <alias> [-y] |
Consume the earliest-expiring reset card for a profile after confirmation; -y / --yes skips the prompt. |
warmup [alias] |
Send a minimal request to activate the 5h quota-window countdown for one or all profiles. Accounts with only a 7-day window are skipped. |
rename <old> <new> |
Rename a saved profile. |
delete <alias> [-y] |
Move an inactive profile into recoverable deleted storage; -y / --yes skips the prompt. |
self-update [--check] [--dev|--stable] [--version <VERSION>] |
Check or update a direct installation. Without flags it stays on the current channel; --version installs a specific newer stable version and conflicts with the channel flags. |
tui |
Open the interactive terminal dashboard. |
open |
Open the codex-switch data directory in the platform file manager. |
| Option | Environment variable | Behavior |
|---|---|---|
--json |
— | Compact structured output (supported by list, use, launch, warmup, reset-card, rename, delete, login, import, export, self-update, doctor, provider add, provider list, provider show, provider rename, provider remove, provider fetch-models, provider probe). doctor --json reports ok, minimum_version, aligned_version, required runtime_note, core_account_commands_available, launch_runtime_available, path_cli, selected_runtime, selected_runtime_source, desktop_codex, and (when both versions parse) versions_match plus version_relation; each executable report has executable, version, status, and optional note. launch --json prints one envelope after Codex exits; each captured Codex stream is limited to 1 MiB and has a *_truncated flag. |
--json-pretty |
— | Indented structured output. |
--proxy <URL> |
CS_PROXY |
Override proxy configuration for this process; supports http(s)://, socks4://, socks5://, and socks5h:// (remote DNS). |
--color <auto|always|never> |
CS_COLOR |
Control CLI terminal color. NO_COLOR disables CLI color regardless of this option. The TUI still paints its designed palette. |
--debug |
— | Emit diagnostic information (HTTP status, retry, cache status) to stderr. Review it before sharing. |
-V, --version
|
— | Print the binary version. |
- Structured data is written to stdout; progress and diagnostics are written to stderr.
- JSON and other non-interactive execution never consumes a reset card or deletes a profile without an explicit opt-in flag.
- Usage output labels
credits_balanceas credits, not dollars. The JSON field remains the raw numeric balance for compatibility; do not infer a universal USD conversion because credit pricing depends on model, speed, plan, and agreement. See Codex pricing. -
launchtreats a known Codex subcommand (exec,resume, …) or a non-launch flag as the start of Codex argv, even without--. Tokens on both sides of--are kept, solaunch work exec -- --jsonstill runsexec. A prompt that looks like an alias still needs--. Whenaliasnames a custom provider, Codex is started with-coverrides (including the saved model catalog, afterexec/resume/ … so Codex 0.149 applies them; user flags that preceded the subcommand move with them),--profileselecting the run's nativecs-*.config.tomlin the normal$CODEX_HOME, and the key in the child environment;auth.jsonis not swapped and the user'sconfig.tomlis not rewritten. For a ChatGPT profile,--no-daemonis prepended (before any subcommand) whencodex --helplists it, so the session reads the stagedauth.jsonrather than the shared app-server daemon. The help probe is bounded to 10 seconds; if it fails, times out, or returns no usable help, launch refuses before staging any credentials because the routing is unknown. An argv that already contains--no-daemon,--remote, or the daemon-onlyagentscommand is passed through unchanged.--json launchcaptures Codex stdout/stderr into the JSON envelope instead of mixing them onto stdout. - A manual
useaffects the next Codex process and accepts ChatGPT profile aliases only. It updatesauth.jsonand resets existingmodel_providerselections in the userconfig.tomland its default inline profile toopenai, preserving models, provider definitions, MCP settings, and comments. When the liveauth.jsonchanges (compared as canonical JSON, so formatting-only rewrites do not count) and the Codex app-server daemon (Codex 0.157+) is running,use(explicit or auto-selecting), the TUIuswitch, and aloginthat activates credentials restart it withcodex app-server daemon restartand report the outcome as a diagnostic; each daemon call is bounded to 15 seconds, and a failed or timed-out restart is a warning, not a failed switch. Set[use] restart_app_server = false(or toggle it in TUI Settings) to leave the daemon alone; the outcome then names the manual command. Restart an already-runningcodex execorcodex --no-daemonprocess yourself;usewithout an alias selects the best eligible profile once. Launch flags, project configuration, separately selected Codex profiles, andopenai_base_url/OPENAI_BASE_URLoverrides remain unchanged. - Update checks are manual except for the one check performed when the TUI starts.
-
list --forceandwarmupare one-time operations. The project does not install or manage an OS scheduler; see the Feature guide for user-managed examples.
Examples:
codex-switch --json list
codex-switch doctor
codex-switch doctor --desktop-codex <path-to-desktop-codex-engine>
codex-switch --json doctor --desktop-codex <path-to-desktop-codex-engine>
codex-switch --json use work
codex-switch launch work -- exec --json "review this"
codex-switch launch work exec -- --json "review this"
codex-switch launch exec --json "do the thing"
codex-switch launch work -- --model gpt-5.4
codex-switch provider add openrouter --base-url https://openrouter.ai/api/v1 --model openai/gpt-5.3-codex
codex-switch provider add zai --base-url https://api.example/v1 --fetch-models
codex-switch provider fetch-models zai
codex-switch launch openrouter -- -s workspace-write -a never
codex-switch provider probe AI-KR
codex-switch provider probe AI-KR --model deepseek-v4-flash
codex-switch self-update --check最低支持版本为 Codex 0.159.2,当前对齐基线为 0.162.1。 doctor reports the PATH CLI and the selected launch runtime separately. Selection follows CODEX_SWITCH_CODEX, PATH, then known macOS desktop installations; a healthy selected desktop engine works without a PATH CLI. --desktop-codex <path> checks an additional engine and does not persist a launch selection. Omitting it reports desktop_codex.status = "not_checked", even when the selected runtime is automatically discovered from a desktop installation. Status values are not_checked, not_found, unknown, dev_build, below_minimum, supported_older, aligned, and above_baseline_unverified. A supported older engine is accepted; a locally built engine (0.0.0 or a -dev / -local suffix) is not compared with the minimum and uses the alignment baseline for HTTP requests. Each version probe has a 10-second bound and a temporary CODEX_HOME. An invalid selected runtime or explicitly checked desktop engine makes doctor exit nonzero after printing one report. core_account_commands_available means account operations do not require a Codex runtime; it does not certify login state, authentication policy or credential-store support. launch_runtime_available reports version suitability for launching. With no engine, core account operations remain available while launch explains the missing requirement. doctor does not certify desktop GUI account changes or daemon compatibility. Version comparisons between PATH and an explicitly checked desktop engine remain informational and ignore build metadata.
If launch or the TUI reports that the PATH CLI is below the 0.159.2 minimum, upgrade that CLI using the method you originally used to install it. For an npm-managed CLI, run npm install -g @openai/codex@latest in the same Node environment; with fnm, select the same fnm Node version/environment used for the installation. Then restart the terminal and TUI, and verify where.exe codex, codex --version, and codex-switch doctor. If doctor --desktop-codex <path> reports that the bundled desktop engine is below minimum, update the Codex desktop app through its own updater or installer and check the new bundled engine path. Updating the npm CLI does not update the desktop engine.
launch applies the same minimum-version check to the selected executable for ChatGPT and custom-provider launches. It runs before account selection, consuming a reset card, creating a provider run, or staging credentials. The existing bounded codex --help probe remains in place to determine --no-daemon routing for ChatGPT launches.
provider diagnose <alias> [--child-model <id>] performs an offline configuration check. Repeat --child-model for planned children. JSON reports network_checked: false, catalog provenance/age, advertised capabilities, child-model membership and structured issues; errors return nonzero while metadata warnings alone do not. It also checks default subagent models and referenced role files in CODEX_HOME/config.toml plus saved overrides. Project/system policy and resumed profiles are not resolved. Neither this command nor provider probe certifies tool or subagent execution against a real gateway.
provider list --json always includes providers, ok, complete and errors. A damaged provider produces an error entry containing its alias, retains valid rows and returns nonzero; raw TOML is omitted. provider show adds catalog information. Inspection redacts sensitive override values. Saved literal HTTP headers are transported through child environment variables; other arbitrary --set values remain CLI configuration.
provider add required flags are --base-url and either --fetch-models or at least one --model. --model is repeatable; the first is default_model. --fetch-models GETs {base_url}/models and saves chat slugs plus launch catalog metadata (embedding/reranker omitted; more than 48 chat models must be picked with --model, or with TUI f). --reasoning EFFORT and --no-web-search attach to the most recent --model. Optional --env-key defaults to CODEX_SWITCH_<ALIAS>_KEY; --wire-api defaults to responses (the only protocol current Codex accepts). --set KEY=VALUE (repeatable) saves a provider-level codex -c override. --metadata-fallback URL|PATH|none picks the catalog metadata fallback used after the gateway /models call (default: the public OpenRouter list). --allow-insecure-http opts that provider into plain HTTP. Per-model and extra settings are passed to Codex, with saved literal HTTP headers converted to environment references. Provider table/auth overrides are validated before use. --api-key-stdin is required when there is no interactive terminal. provider fetch-models <alias> replaces the saved list from the gateway and persists its launch catalog; matching ids keep their settings. On a large catalog pass --model (repeatable). provider probe <alias> POSTs {base_url}/responses with only model (no input) so a supporting handler 400s at validation without generating tokens; --model probes one saved slug and conclusive verdicts are saved for 7 days (fingerprint-scoped: any endpoint, key, header, query or catalog change drops them). provider rename <old> <new> moves the directory and re-derives provider_id / env_key. launch <alias> --model <id> (before --) selects a saved model on a provider. launch <alias> -- --model <id> forwards Codex's own --model and drops the competing per-model -c pairs (model, model_reasoning_effort, web_search). Provider launch never refuses on a saved "unsupported" result alone: it first sends one live probe. A confirming answer refuses the launch; a "supported" answer proceeds and refreshes the record; an inconclusive answer or a failed request proceeds with a warning on stderr and drops the stale record. Saved "supported" or missing results add no request.
The alias must not collide with a ChatGPT profile, another provider, or Codex's reserved ids openai, ollama, and lmstudio. Removal is immediate and is not archived under deleted-profiles/.
See Custom API providers for OpenRouter, DeepSeek-via-gateway, storage, and the no-argv key contract.
Four tabs: Accounts, Providers, Settings, and Logs. Tab / Shift+Tab cycles them. q and h are main-view shortcuts; forms, text edits, menus, and confirmations use their own Esc and confirmation rules.
Mouse input is available alongside the keyboard: click a tab to switch pages, click an Accounts or Providers row to select it, and double-click the selected row to open its account menu or provider launch menu. On Settings, click a field to edit or toggle it and use the wheel to move among fields; clicking another field while editing commits the current value first. Provider add/edit forms, launch pickers, and confirmation prompts accept clicks on their own controls (fields, checkboxes, model rows, y/n) and do not click through to the page behind them. Use the wheel to scroll Logs, Help, menus, and modal lists. Clicking outside a dismissible popup closes it.
Enter opens the scrollable detail and action menu for the selected account; if accounts are marked, it opens the batch menu instead.
| Key | Action |
|---|---|
j / k or ↑ / ↓
|
Navigate |
Tab |
Next tab (Providers) |
Enter |
Open the account menu, or the batch menu when accounts are marked |
/ |
Filter accounts |
r |
Refresh visible accounts |
a |
Add a new account |
t |
Toggle auto-refresh |
i |
Toggle the compact quota panel on the main view |
s |
Cycle sort order (name / quota / status) |
Space |
Mark or unmark an account |
u (Accounts page when no accounts are marked, or account menu) |
Switch to the selected account; the status line shows Switching to … while it is in progress |
o |
Open the selected account's launch picker (also o in the account menu): use Codex's default, or choose a cached model, one-shot reasoning, and extra Codex arguments |
c (account menu) |
Confirm and consume the earliest-expiring reset card |
r (account menu) |
Refresh usage and the account's authenticated model catalog |
w (account menu) |
Warm up the selected account |
l (account menu) |
Re-login the selected account |
n (account menu) |
Rename the selected account |
d (account menu) |
Delete the selected account (confirmation required) |
r / w / l / d (batch menu) |
Refresh, warm up, re-login, or delete the marked accounts |
h |
Show the complete shortcut list (main view) |
Esc |
Clear filter/marks or close the current popup |
q |
Quit (main view) |
The ChatGPT model list comes from the selected profile's authenticated /models response, using the selected Codex runtime version; it is account- and route-specific and is cached in the TUI for five minutes. Use Enter then r in the account menu to refresh that account's usage and model catalog. The app does not add models that the service did not return. Model request errors report the client_version used.
The selected runtime version supplies the client_version query parameter and User-Agent value for shared HTTP requests, including when the selected executable comes from a desktop installation. If no usable version can be detected, HTTP requests use the 0.162.1 alignment baseline as a transport fallback; doctor preserves the actual missing or unknown state. launch checks the selected engine's minimum version; an undetectable version only warns. The TUI compatibility notice refers to that selected runtime. An explicit invalid CODEX_SWITCH_CODEX does not silently fall back to another executable.
Daybreak eligibility discovery uses the alignment baseline as its model-catalog client_version, because older catalog schemas can omit access-program declarations for eligible accounts. This does not change the installed CLI, its launch catalog, or Daybreak opt-in settings.
Usage refresh is gated by a parseable access-token expiry: it proactively refreshes when that token is within five minutes of expiry. If the access-token expiry is unavailable, the quota request is tried first and an HTTP 401/403 can enter the existing recovery flow. An expired ID token by itself does not mean the access token is expired and does not block an otherwise valid quota request. If refresh reports refresh_token_invalidated for a profile, stop retrying refresh for that profile; use codex-switch login <alias> to reauthenticate it, or codex-switch use <alias> to switch to another saved account.
Usage and refresh diagnostics record request phase start and completion, including elapsed time, outcome, and HTTP status when available. They do not log credential values or response bodies.
| Key | Action |
|---|---|
j / k or ↑ / ↓
|
Navigate |
a |
Add a provider (form dialog) |
Enter / o
|
Launch Codex: pick a saved model, reasoning, and optional extra argv |
e |
Edit the selected provider |
n |
Rename the selected provider |
d |
Remove the selected provider (confirmation required) |
Tab |
Next tab (Settings) |
h |
Show help (main view) |
q |
Quit (main view) |
The Providers table never renders the stored key. Enter or o picks a saved model (and optionally changes reasoning or extra Codex argv for this session) then launches, or run codex-switch launch <alias> from the shell. e opens the edit form (including env key, wire API, and extra -c). l is re-login on the Accounts tab, not launch.
Edits $CODEX_SWITCH_HOME/config.toml. Saving rewrites the file (comments and unknown keys are not kept). The TUI process applies changes immediately. t on the Accounts page controls session-only automatic usage refresh; quota warmup remains a one-time account-menu action (w) or CLI warmup.
Fields are labelled with their config.toml keys: proxy.url, proxy.no_proxy, cache.ttl, network.max_concurrent, tui.auto_refresh_interval_secs, use.safety_margin_7d, use.team_priority, use.restart_app_server, and launch.restore_delay_secs. The focused field shows a short explanation under the list (units, minimums, and for use.restart_app_server what the restart does).
| Key | Action |
|---|---|
j / k or ↑ / ↓
|
Move among fields |
Enter / Space
|
Edit the focused value, or toggle a boolean. Clicking a field does the same. |
← / →
|
Toggle the boolean field |
s |
Save config.toml
|
Esc |
Cancel the current field edit (does not discard other unsaved fields) |
Tab |
Next tab (Logs). Ignored while a field is being edited. Unsaved edits are kept. |
h |
Show help (main view) |
q |
Quit (main view) |
Destructive or consumptive actions always require confirmation.
Session diagnostics stay inside the TUI instead of writing through the active terminal screen. It shows INFO and above, including completed or failed account operations; DEBUG requires --debug or RUST_LOG. Use j / k or PgUp / PgDn to scroll and End to return to the latest line. Tab continues to Accounts.
- See how these commands combine into workflows in the Feature guide.
- Custom API endpoints, OpenRouter, and key handling: Custom API providers.
- Adjust defaults, proxy, cache, selection, and launch behavior in Configuration.
- Check update channels and flags in Updating.
Provider launches inherit native MCP credentials, skills, agents, plugins, hooks, and project configuration from the normal Codex environment. Provider keys are injected into the child environment, never saved in the generated profile. Settings saved inside Codex belong to that run's profile; default config.toml is not swapped or restored. Forwarding another --profile/-p is rejected. Legacy isolated-home sessions remain resumable in their original environment.
For provider --json launches, child output is captured in persistent run files, read and removed on normal completion. A launcher crash leaves those files available and does not close the child's output destination. Intentional shutdown still terminates the child; closing a terminal or killing an entire process tree is distinct from a launcher-only crash.