Skip to main content
@openai/codex (Rust port, v0.153.2 verified). Distributed as an npm package wrapping a per-platform Rust binary.

Install

Pre-installed in every seeded crew container via Crewship’s baseCLIPostCreate provisioning script.

Auth

Two paths, both measured against codex-cli 0.153.2. Codex is not Claude Code: it has no environment variable for a subscription login, and the one it has for API keys (CODEX_API_KEY) overrides a stored login.

API key

Codex reaches its provider only through its own model_providers config — OPENAI_BASE_URL no longer exists in the binary, and the built-in openai provider refuses to be overridden. Crewship therefore emits a custom provider per run:
The OPENAI_API_KEY in the environment is a dummy; the sidecar replaces it with the real key from its CredStore. The real key never enters the container.

ChatGPT plan

Run codex login on your own machine, then store the whole ~/.codex/auth.json as a credential:
The server splits the file: the access token becomes the credential’s value, refresh_token and id_token become secret parts (the refresh token is sealed — never revealed, never delivered), account_id, plan, expires_at and mode identifier parts. The older form — the whole file stored as --type AI_CLI_TOKEN --provider OPENAI — still works and is delivered the same way, but it has no owner, no expiry badge and no central refresh; see Provider logins. The slot name on assign is the binding’s identity, not something Codex reads — the login is never exported as a variable. Or skip the paste: crewship credential login --provider OPENAI prints a one-time code and a URL, you enter the code in OpenAI’s device page, and the server finishes the sign-in itself — no codex binary involved — and stores the resulting auth.json as the same kind of credential, named after the plan and account. See Sign in with a code. In the dashboard, Add secret → shape Provider login → brand OpenAI → Subscription takes the same file; API key on the same tile stores a metered key instead. A bare access token is refused at submit time: Codex insists on id_token, access_token, refresh_token and account_id all being present, so only the file codex login writes can be delivered. At every run start Crewship renders the login into the agent’s $CODEX_HOME/auth.json (/crew/agents/<slug>/.codex/auth.json, mode 0600) with the real id/access tokens and account id, refresh_token replaced by rt.crewship-managed-no-refresh, and last_refresh stamped now. Codex only touches the refresh token when the access token nears expiry, so the file authenticates normally — and because no container ever holds a real refresh token, one login can be assigned to any number of agents without the containers rotating (and invalidating) each other’s tokens. Revoking the credential removes the file from running containers; unassigning it removes the file at the next run start. Subscription traffic goes to chatgpt.com through the sidecar’s CONNECT tunnel, exactly like Claude Code’s OAuth mode: the sidecar cannot meter it, so the run is billed flat_rate with CREWSHIP_SUBSCRIPTION_PLAN set from the token’s chatgpt_plan_type claim (“ChatGPT Plus”). Model policy on the credential is not enforced in this mode.
For a PROVIDER_LOGIN with a stored refresh token, Crewship renews the login centrally before its reported expiry and checks freshness at run start. If refresh cannot recover and the account shows needs_relogin, sign in again. Legacy access-only imports cannot renew automatically. CODEX_API_KEY is never set by Crewship — it would override the login.
Credential-backed OPENROUTER and OPENAI_COMPAT models use Codex’s native custom model_provider configuration for that invocation. For example, openrouter/anthropic/claude-sonnet-4 is sent to /llm/openrouter with anthropic/claude-sonnet-4 as Codex’s provider-local model ID. The provider must implement the OpenAI Responses API; current Codex no longer supports wire_api = "chat". Use the OpenCode adapter for a Chat-Completions-only compatible endpoint.

Models

Codex CLI is a STRICT subset of OpenAI’s general API — only the coding-tuned GPT-5.x/6.x family is accepted: Codex CLI rejects o3, o4-mini, gpt-4o etc. — those are general-API only.

Command shape

  • exec — non-interactive subcommand (NOT --quiet, that flag doesn’t exist)
  • --json — newline-delimited JSON events on stdout
  • --sandbox — read-only (MINIMAL profile) | workspace-write (all other profiles — CODING/FULL) | danger-full-access (never opted into)
  • -- separator prevents user message dash-prefixed tokens from being parsed as flags
  • System prompt is folded into the user message body with [SYSTEM]/[USER] delimiters because Codex exec has no system-prompt flag

MCP

Codex uses TOML, not JSON. Crewship writes /crew/agents/<slug>/.codex/config.toml (HOME, NOT workdir — Codex requires interactive trust ceremony for project-scoped configs).
Authorization: Bearer ${TOKEN} headers are translated to bearer_token_env_var = "TOKEN". Generic X-API-Key: ${KEY} headers go to env_http_headers = { "X-API-Key" = "KEY" }. Literal headers go to http_headers = { ... }.
Two sidecar-hosted MCP servers are auto-injected into every generated config (injectMemoryMCP + injectRoutinesMCP): crewship-memory (http://127.0.0.1:9119/mcp/memory/<slug>) and crewship-routines (.../mcp/routines) — both http transport. They give the model native memory.read/write/search/append_daily and save_routine/list_routines tools regardless of CLI. A user-declared server of the same name wins (no overwrite).

Memory

Canonical memory file set written to /output/<slug>/AGENTS.md (Codex’s auto-discovered file). Plus the cross-CLI parity files for an agent swapping CLI mid-mission. First-turn parity: system prompt is also prepended to the user message via [SYSTEM]/[USER] delimiters since Codex doesn’t load AGENTS.md until the second invocation.

Output stream

Per developers.openai.com/codex/cli/reference, Codex emits an envelope-and-item model (NOT the Agents SDK schema): Item subtypes: agent_message, reasoning, command_execution (uses aggregated_output + exit_code, NOT output), file_change, mcp_tool_call (uses server/tool/arguments/result), web_search, plan_update, todo_list, collab_tool_call.

Troubleshooting

codex: not found — npm install failed in container. Check journalctl -u prod-server | grep codex. unknown flag: --quiet — adapter regression; ensure orchestrator pinned to current schema (see cli_adapter_versions_test.go). MCP server returns 401 — verify bearer_token_env_var references a credential present in the container env. Run crewship agent mcp <slug> --resolved to dump the effective merged MCP config (crew + agent, including each server’s bound credential name) and confirm the expected credential is wired.