// ai
Codex
Comprehensive guide for OpenAI Codex - the codex CLI, IDE extension, cloud, authentication, configuration, and automation
A practical reference for OpenAI Codex: the codex CLI, the IDE extension,
Codex cloud, and the automation surfaces around them. Commands are written for a
POSIX shell unless marked otherwise. Checked against Codex CLI 0.147.0,
published on 2026-08-07 as npm @openai/codex@0.147.0 and GitHub release tag
rust-v0.147.0. Note that GitHub release tags carry a rust-v prefix, so
searching the releases page for a bare 0.147.0 will not match.
Codex is a coding agent that runs on your machine. It reads and edits files,
runs commands inside an OS-enforced sandbox, and asks for approval before it
crosses the boundary you set. The same config.toml drives the CLI, the IDE
extension, and Codex in the ChatGPT desktop app.
Table of Contents
- Install & Update
- Sign In & Authentication
- Quick Start
- Command Reference
- Global Flags
- Interactive Session
- Slash Commands
- Models & Reasoning
- Sandbox & Approvals
- Network Access
- AGENTS.md
- Skills
- Subagents & Custom Agents
- MCP Servers
- Plugins
- Hooks
- Rules (execpolicy)
- Non-Interactive Mode (
codex exec) - Configuration
- Config Key Reference
- Environment Variables
- Files & State Locations
- Code Review
- Codex in CI
- Codex SDK
- Codex Cloud
- IDE Extension
- Observability
- Common Issues & Solutions
- Quick Tips
Install & Update
Standalone installer
# macOS / Linux — the same command installs and updates
curl -fsSL https://chatgpt.com/codex/install.sh | sh
# Windows — the same command installs and updates
powershell -ExecutionPolicy ByPass -c "irm https://chatgpt.com/codex/install.ps1 | iex"
Package managers
npm install -g @openai/codex # install and update
brew install --cask codex # install
brew upgrade --cask codex # update
Self-update and version
codex update # apply an update when the release supports self-update
codex --version # installed CLI version
codex doctor # local diagnostic report (installation, auth, git, terminal)
codex doctor --json # redacted machine-readable support report
Installer variables
# Skip installer prompts; prompts take their default answer
curl -fsSL https://chatgpt.com/codex/install.sh | CODEX_NON_INTERACTIVE=1 sh
# Change where the `codex` command lands
# Default: ~/.local/bin (macOS/Linux), %LOCALAPPDATA%\Programs\OpenAI\Codex\bin (Windows)
CODEX_INSTALL_DIR=/opt/bin curl -fsSL https://chatgpt.com/codex/install.sh | sh
# Force GitHub Releases instead of releases.openai.com
curl -fsSL https://chatgpt.com/codex/install.sh | CODEX_INSTALLER_USE_RELEASES_OPENAI_COM=false sh
System requirements
| Requirement | Details |
|---|---|
| Operating system | macOS 12+, Ubuntu 20.04+/Debian 10+, Windows 11 (native or WSL2) |
| Git | 2.23+ recommended; Codex refuses to run outside a Git repo by default |
| RAM | 4 GB minimum, 8 GB recommended |
WSL1 was supported through Codex 0.114. Starting with 0.115 the Linux
sandbox uses bwrap, so WSL1 no longer works.
Sign In & Authentication
codex login # browser OAuth with a ChatGPT account
codex login --device-auth # device-code flow for headless machines
printenv OPENAI_API_KEY | codex login --with-api-key
printenv CODEX_ACCESS_TOKEN | codex login --with-access-token
codex login status # exits 0 when credentials exist
codex logout # clears both API key and ChatGPT credentials
Signing in with ChatGPT uses your plan’s included usage and your workspace’s admin controls. Signing in with an API key bills at standard API rates and follows your API organization’s data settings instead. Codex cloud requires ChatGPT sign-in.
Credential storage
# ~/.codex/config.toml
cli_auth_credentials_store = "keyring" # file | keyring | auto
file writes ~/.codex/auth.json, keyring uses the OS credential store, and
auto prefers the credential store and falls back to the file. Treat
auth.json like a password; it holds access tokens.
Headless and remote machines
# Preferred: device code
codex login --device-auth
# Fallback 1: copy an existing credential file
ssh user@remote 'mkdir -p ~/.codex && cat > ~/.codex/auth.json' < ~/.codex/auth.json
# Fallback 2: forward the local OAuth callback port
ssh -L 1455:localhost:1455 user@remote
# then run `codex login` inside that SSH session
Corporate TLS
export CODEX_CA_CERTIFICATE=/path/to/corporate-root-ca.pem # takes precedence over SSL_CERT_FILE
codex login
Quick Start
cd ~/code/my-project
codex # launch the interactive TUI
codex "explain this project" # launch with a first prompt
codex -m gpt-5.6-terra "fix the failing test"
codex --sandbox read-only # look but do not touch
codex resume --last # reopen the most recent chat here
codex exec "summarize the repo" # one-shot, no TUI
Inside the session:
| Step | Command |
|---|---|
| Write project instructions | /init then edit AGENTS.md |
| Check the boundary you are running under | /status |
| Change what Codex may do without asking | /permissions |
| Switch model or reasoning effort | /model |
| Inspect what changed | /diff |
| Get a second opinion on the diff | /review |
| Free context on a long chat | /compact |
Commit before and after a Codex task. A clean git status makes its patches
easy to isolate and revert.
Command Reference
| Command | Purpose |
|---|---|
codex | Launch the interactive terminal UI in the current directory |
codex exec (codex e) | Run a task non-interactively for scripts and CI |
codex resume | Continue a saved interactive session |
codex fork | Branch a saved session into a new chat |
codex review | Run a code review non-interactively |
codex apply <TASK_ID> | Apply the latest diff from a Codex cloud chat locally |
codex cloud | Browse cloud chats; cloud exec submits one, cloud list lists them |
codex login / logout | Manage credentials |
codex mcp | Add, list, inspect, and authenticate MCP servers |
codex mcp-server | Run Codex itself as an MCP server over stdio |
codex plugin | Install, list, and remove plugins from marketplaces |
codex archive / unarchive | Hide or restore a saved session without deleting it |
codex delete <SESSION> | Permanently delete a session transcript |
codex sandbox | Run a command under the same sandbox policy Codex uses |
codex execpolicy check | Test .rules files against a command |
codex features | List, enable, or disable feature flags |
codex completion <shell> | Print a shell completion script |
codex doctor | Produce a local diagnostic report |
codex update | Update the CLI in place |
codex app | Open the ChatGPT desktop app from the terminal |
codex app-server | Run the local app server (development and protocol clients) |
codex remote-control | Start, stop, and pair the remote-control daemon |
codex debug models | Print the raw model catalog as JSON |
Sessions
codex resume # pick from saved sessions in this directory
codex resume --last # most recent session in this directory
codex resume --all # widen the picker beyond this directory
codex resume <SESSION_ID> # by UUID or session name
codex fork --last # branch the most recent session
codex archive <SESSION> # hide from the picker, keep the transcript
codex unarchive <SESSION>
codex delete <SESSION_UUID> --force
When the current directory differs from the session’s saved directory, Codex
asks which one to use. Set tui.resume_cwd = "current" or "session" to answer
that once and for all; an explicit --cd still wins.
Review
codex review --uncommitted # staged, unstaged, and untracked changes
codex review --base main # branch diff against a base branch
codex review --commit 1a2b3c4 --title "Fix auth" # one commit
codex review "focus on error handling" # custom instructions
echo "check for race conditions" | codex review -
--uncommitted, --base, --commit, and a custom prompt are mutually
exclusive. --title only applies with --commit.
Shell completions
codex completion zsh > "${fpath[1]}/_codex"
# or evaluate directly from your shell rc file
eval "$(codex completion zsh)"
# If zsh reports `command not found: compdef`
autoload -Uz compinit && compinit
eval "$(codex completion zsh)"
Supported shells: bash, zsh, fish, powershell, elvish.
Global Flags
These apply to codex and propagate to most subcommands.
| Flag | Values | Purpose |
|---|---|---|
--model, -m | string | Override the configured model |
--sandbox, -s | read-only, workspace-write, danger-full-access | Sandbox policy for generated commands |
--ask-for-approval, -a | untrusted, on-request, never | When Codex pauses to ask |
--dangerously-bypass-approvals-and-sandbox, --yolo | — | No sandbox, no approvals. Use only inside an isolated VM or container |
--cd, -C | path | Set the working directory before the agent starts |
--add-dir | path (repeatable) | Grant write access to extra directories |
--image, -i | path[,path…] | Attach images to the first prompt |
--search | — | Live web search for this run (web_search = "live") |
--profile, -p | name | Layer $CODEX_HOME/<name>.config.toml over the base config |
--config, -c | key=value | Override any config key; the value is parsed as TOML |
--enable / --disable | feature (repeatable) | Force a feature flag on or off for this run |
--oss | — | Use a local open-source provider |
--local-provider | lmstudio, ollama | Pick the local provider for --oss |
--strict-config | — | Fail when config.toml holds unrecognized fields |
--no-alt-screen | — | Keep terminal scrollback instead of the alternate screen |
--remote | ws://, wss://, unix://[PATH] | Attach the TUI to a running app server |
--remote-auth-token-env | env var name | Bearer token source for --remote |
--dangerously-bypass-hook-trust | — | Run enabled hooks without persisted trust |
codex exec adds
| Flag | Purpose |
|---|---|
--json | Emit newline-delimited JSON events on stdout |
--output-last-message, -o <path> | Write the final message to a file (still printed to stdout) |
--output-schema <path> | Force the final response to match a JSON Schema |
--ephemeral | Do not persist session rollout files |
--skip-git-repo-check | Allow running outside a Git repository |
--ignore-user-config | Skip $CODEX_HOME/config.toml |
--ignore-rules | Skip user and project .rules files |
--color | always, never, auto (default auto) |
--full-auto | Deprecated. Use --sandbox workspace-write |
Config overrides on the command line
codex --model gpt-5.6-terra # prefer a dedicated flag
codex -c model='"gpt-5.6-terra"' # values are TOML, so strings need quotes
codex -c sandbox_workspace_write.network_access=true
codex -c 'shell_environment_policy.include_only=["PATH","HOME"]'
codex -c mcp_servers.context7.enabled=false # dot notation reaches nested keys
codex -c log_dir=./.codex-log # also enables the plaintext TUI log
Interactive Session
Keyboard and composer
| Input | Effect |
|---|---|
@ | Search workspace files and insert the path |
$ | Mention a skill; $app-slug mentions an app |
! at line start | Run a local shell command under the current sandbox and approval settings |
| Up / Down | Restore draft history |
| Ctrl+R | Search prompt history; Enter accepts, Esc cancels |
| Ctrl+O | Copy the latest completed response (same as /copy) |
| Tab while working | Queue a follow-up prompt, slash command, or shell command |
| Enter while working | Inject new instructions into the running turn |
| Esc Esc on an empty composer | Edit the previous message and fork from that point |
| Ctrl+G | Open $VISUAL (or $EDITOR) to write a long prompt |
| Ctrl+L | Clear the terminal view but keep the chat |
| Alt+R | Toggle raw scrollback (same as /raw) |
| Ctrl+C | Exit the session |
Rebind any of these with /keymap, which writes to tui.keymap in
config.toml:
[tui.keymap.global]
open_transcript = "ctrl-t"
[tui.keymap.composer]
submit = ["enter", "ctrl-m"]
[tui.keymap.chat]
interrupt_turn = "f12"
An empty binding list unbinds the action. Context-specific bindings override
tui.keymap.global.
Images
codex -i screenshot.png "Explain this error and suggest the smallest fix"
codex --image before.png,after.png "Compare these states and list the regressions"
You can also paste an image straight into the composer. Repeat --image or
separate paths with commas.
Slash Commands
Session control
| Command | Purpose |
|---|---|
/model | Choose the model and reasoning effort |
/fast | Toggle the model’s Fast service tier when the catalog offers one |
/permissions | Choose the approval preset (Read Only, Auto, and so on) |
/approve | Retry once an action that automatic review denied |
/plan | Switch to plan mode, optionally with an inline prompt |
/goal | Set, edit, pause, resume, view, or clear a persistent objective (max 4,000 characters) |
/personality | Choose friendly, pragmatic, or none |
/status | Show model, approval policy, writable roots, and token usage |
/usage | Show account token activity (daily, weekly, cumulative) |
/compact | Summarize the chat so far to free context |
/new | Start a fresh chat in the same CLI session |
/clear | Clear the terminal and start a fresh chat |
/rename | Rename the current chat |
/fork | Clone the current chat into a new one |
/side, /btw | Start a throwaway side chat off the current one |
/resume | Reopen a saved chat from the picker |
/archive, /delete | Archive or delete the current session, then exit |
/quit, /exit | Leave the CLI |
Code and context
| Command | Purpose |
|---|---|
/init | Generate an AGENTS.md scaffold in the current directory |
/diff | Show the Git diff, including untracked files |
/review | Review the working tree, a base branch, or a commit |
/mention <path> | Attach a file to the chat |
/ide | Pull open files and the current selection into the next prompt |
/copy | Copy the latest completed response |
/ps | List background terminals and recent output |
/stop (/clean) | Stop all background terminals |
Extensions
| Command | Purpose |
|---|---|
/skills | Browse and apply a local skill |
/plugins | Browse installed and available plugins; Space toggles one |
/apps | Browse connectors and insert one as $app-slug |
/mcp | List MCP servers and tools; /mcp verbose adds diagnostics |
/hooks | Inspect, trust, disable, or re-enable lifecycle hooks |
/agent, /subagents | Switch between agent threads |
/memories | Turn memory use and generation on or off |
/import | Import a Claude Code setup, project files, and recent chats |
Appearance and diagnostics
| Command | Purpose |
|---|---|
/theme | Pick a syntax-highlighting theme (tui.theme) |
/statusline | Choose and order footer items (tui.status_line) |
/title | Choose and order terminal title items (tui.terminal_title) |
/keymap | Remap TUI shortcuts (tui.keymap) |
/vim | Toggle composer Vim mode |
/raw | Toggle raw scrollback for easier copying |
/pets, /pet | Choose or hide a terminal pet |
/experimental | Toggle experimental features |
/debug-config | Print config layer order and policy diagnostics |
/feedback | Send logs and diagnostics to the maintainers |
/logout | Clear local credentials |
Windows-only: /setup-default-sandbox installs the elevated sandbox, and
/sandbox-add-read-dir C:\path grants read access to one more directory.
Models & Reasoning
| Model | Shape of work |
|---|---|
gpt-5.6-sol | Flagship. Ambiguous, high-value, open-ended work that needs judgment and polish |
gpt-5.6-terra | Balanced all-rounder for everyday coding and tool use |
gpt-5.6-luna | Fast and cheap. Clear, repeatable, high-volume tasks |
gpt-5.3-codex-spark | Research preview, text only, near-instant iteration (ChatGPT Pro) |
gpt-5.5 | Previous-generation frontier model |
codex --model gpt-5.6 # `gpt-5.6` resolves to a recommended model
codex exec -m gpt-5.6-terra "review the current changes"
model = "gpt-5.6"
review_model = "gpt-5.6" # only used by /review
model_reasoning_effort = "high" # minimal | low | medium | high | xhigh
model_reasoning_summary = "auto" # auto | concise | detailed | none
model_verbosity = "medium" # low | medium | high
Use the lowest reasoning effort that produces the result you need. The desktop app and IDE label the lowest level Light where the CLI calls it Low, and some models expose deeper Max and Ultra levels. Ultra runs subagents in parallel rather than thinking longer in one thread.
Retirements
gpt-5.4 and gpt-5.4-mini retire from Codex with ChatGPT sign-in on
August 31, 2026. Replace gpt-5.4 with gpt-5.6-terra and gpt-5.4-mini
with gpt-5.6-luna in config files, custom agents, and scheduled tasks.
gpt-5.2 and gpt-5.3-codex are already deprecated for ChatGPT sign-in. The
OpenAI API and API-key Codex usage are not affected.
codex debug models # print the catalog Codex actually sees
codex debug models --bundled # only the catalog compiled into this binary
Sandbox & Approvals
Two independent controls decide what happens:
- Sandbox mode sets what Codex can do — where it writes and whether it reaches the network.
- Approval policy sets when Codex must ask before it acts.
| Sandbox mode | Effect |
|---|---|
read-only | Read files only |
workspace-write | Read anywhere allowed, write inside the workspace and configured writable roots; network off by default |
danger-full-access | No filesystem or network restriction |
| Approval policy | Effect |
|---|---|
untrusted | Run only known-safe read operations automatically; ask before anything that can mutate state |
on-request | Run inside the sandbox freely; ask before leaving it |
never | Never ask; Codex does its best within the sandbox you set |
Common combinations
| Intent | Flags |
|---|---|
| Auto (the default in a Git repo) | --sandbox workspace-write --ask-for-approval on-request |
| Read-only browsing | --sandbox read-only --ask-for-approval on-request |
| Read-only in CI | --sandbox read-only --ask-for-approval never |
| Edit freely, gate commands | --sandbox workspace-write --ask-for-approval untrusted |
| Route approvals to a reviewer agent | --sandbox workspace-write -a on-request -c approvals_reviewer=auto_review |
| No guardrails | --dangerously-bypass-approvals-and-sandbox (alias --yolo) |
On launch Codex recommends Auto in a version-controlled folder and
read-only elsewhere. codex exec defaults to a read-only sandbox. The
workspace includes the current directory plus temporary directories such as
/tmp; run /status to see the actual writable roots.
Configuration
approval_policy = "on-request" # untrusted | on-request | never
sandbox_mode = "workspace-write"
allow_login_shell = false # optional hardening: reject login-shell requests
[sandbox_workspace_write]
network_access = true # off by default
writable_roots = ["/srv/build-cache"]
exclude_tmpdir_env_var = false
exclude_slash_tmp = false
Granular approvals keep some prompt categories interactive and auto-reject the rest:
approval_policy = { granular = {
sandbox_approval = true,
rules = true,
mcp_elicitations = true,
request_permissions = false,
skill_approval = false
} }
Protected paths
Inside a writable root these stay read-only, recursively:
<root>/.git(and the resolved Git directory when.gitis a pointer file)<root>/.agents<root>/.codex
Automatic approval review
approval_policy = "on-request"
approvals_reviewer = "auto_review" # user (default) | auto_review
A reviewer agent screens only the requests that already need approval:
sandbox escalations, blocked network calls, request_permissions prompts, and
side-effecting app or MCP tool calls. It checks for data exfiltration,
credential probing, persistent security weakening, and destructive actions. It
denies critical-risk actions and fails closed on parse or prompt-build errors.
It costs extra model calls.
Permission profiles
default_permissions = ":workspace" # built-ins: :read-only, :workspace, :danger-full-access
[permissions.ci]
description = "Read-only with one allowed host"
extends = ":read-only"
network.enabled = true
network.domains = { "api.example.com" = "allow" }
Do not combine default_permissions with sandbox_mode or
[sandbox_workspace_write].
OS enforcement
| Platform | Mechanism |
|---|---|
| macOS | Seatbelt via sandbox-exec with a profile matching the selected mode |
| Linux | bwrap plus seccomp |
| Windows (WSL2) | The Linux sandbox |
| Windows (native) | The Windows sandbox: windows.sandbox = "elevated" recommended, "unelevated" as fallback |
Test the sandbox
codex sandbox macos [--permissions-profile <name>] [--log-denials] -- <command>...
codex sandbox linux [--permissions-profile <name>] -- <command>...
codex sandbox windows [--permissions-profile <name>] -- <command>...
codex sandbox seatbelt and codex sandbox landlock are aliases, and the whole
group is also reachable as codex debug.
Containers
Inside Docker the sandbox may fail when the host blocks the namespace, setuid
bwrap, or seccomp operations Codex needs. Make the container the security
boundary, then run codex --sandbox danger-full-access inside it so Codex does
not try to build a second sandbox layer. The
secure devcontainer example
ships an Ubuntu image, bubblewrap, and an allowlist firewall:
devcontainer up --workspace-folder . --config .devcontainer/devcontainer.secure.json
A devcontainer is not a complete boundary. With --yolo inside it, a hostile
repository can still exfiltrate anything the container can reach, including
Codex credentials.
Network Access
workspace-write blocks outbound network until you turn it on:
[sandbox_workspace_write]
network_access = true
Turning access on alone gives unrestricted outbound traffic. Add the
network_proxy feature to constrain it:
[features.network_proxy]
enabled = true
domains = { "api.openai.com" = "allow", "example.com" = "deny" }
allow_local_binding = false # default: block loopback and private ranges
codex \
-c 'features.network_proxy.enabled=true' \
-c 'features.network_proxy.domains={ "api.openai.com" = "allow" }' \
-c 'sandbox_workspace_write.network_access=true'
| Network | Proxy | Result |
|---|---|---|
| off | on | Network stays off; the feature does nothing |
| on | off | Unrestricted direct outbound access |
| on | on | Outbound traffic constrained by your policy |
Domain rules are allowlist-first. example.com matches only itself,
*.example.com matches subdomains but not the apex, **.example.com matches
both, and * matches any public host. deny always beats allow. Codex
classifies resolved addresses before allowing a hostname, so names that resolve
to private IPs stay blocked, but that check reduces DNS-rebinding risk rather
than removing it. Enforce egress at the network layer too when hostile DNS is
in scope.
Web search
web_search = "cached" # cached (default) | indexed | live | disabled
Cached mode serves an OpenAI-maintained index instead of fetching pages live,
which lowers prompt-injection exposure. --search switches one run to live.
Under --yolo or another full-access setting, web search defaults to live.
Treat every web result as untrusted input.
AGENTS.md
Codex reads AGENTS.md before it does any work and rebuilds the instruction
chain once per run.
Discovery order:
- Global —
$CODEX_HOME/AGENTS.override.md, otherwise$CODEX_HOME/AGENTS.md. Only the first non-empty file counts. - Project — walk from the project root down to the current directory. In
each directory try
AGENTS.override.md, thenAGENTS.md, then anyproject_doc_fallback_filenames. At most one file per directory. - Merge — concatenate root-first. Files nearer your working directory appear later and therefore win.
Codex skips empty files and stops once the combined size reaches
project_doc_max_bytes (32 KiB by default).
# AGENTS.md
## Repository expectations
- Run `npm run lint` before opening a pull request.
- Use `make test-payments` in `services/payments/`, not `npm test`.
- Document public utilities in `docs/` when behavior changes.
## Code Review Rules
### Experiment cohorts
- Do not filter treatment comparisons on post-exposure behavior.
Safe path: build cohorts from assignment or exposure; report conversion as an outcome.
project_doc_max_bytes = 65536
project_doc_fallback_filenames = ["TEAM_GUIDE.md", ".agents.md"]
project_root_markers = [".git", ".hg", ".sl"] # [] means "current directory is the root"
Verify what loaded:
codex --ask-for-approval never "Summarize the current instructions."
codex --cd services/payments -a never "List the instruction sources you loaded."
codex -c log_dir=./.codex-log # then read ./.codex-log/codex-tui.log
Keep it short. Start minimal and add a rule only after Codex repeats a mistake. Put durable rules here rather than in every prompt.
Skills
A skill is a directory holding a SKILL.md with name and description in
front matter, plus optional scripts/, references/, and assets/.
---
name: release-notes
description: Draft release notes from merged PRs. Use when preparing a tagged release.
---
1. List merged PRs since the previous tag.
2. Group them by user-visible change, then by internal change.
3. Write one line per change with the PR number.
| Scope | Location |
|---|---|
| Repo | $CWD/.agents/skills, any .agents/skills above it, $REPO_ROOT/.agents/skills |
| User | $HOME/.agents/skills |
| Admin | /etc/codex/skills |
| System | Bundled with Codex |
Invoke a skill explicitly with /skills or by typing $skill-name. Codex also
picks skills implicitly by matching your task against the description, so
front-load the trigger words. The initial skill list is capped at 2% of the
context window (or 8,000 characters when the window is unknown); Codex shortens
descriptions first and warns if it has to omit skills.
$skill-creator # built-in authoring assistant
$skill-installer linear # install a curated skill
# Disable a skill without deleting it
[[skills.config]]
path = "/path/to/skill/SKILL.md"
enabled = false
Optional agents/openai.yaml inside the skill sets display metadata, invocation
policy, and tool dependencies:
interface:
display_name: "Release notes"
short_description: "Draft release notes from merged PRs"
policy:
allow_implicit_invocation: false
dependencies:
tools:
- type: "mcp"
value: "openaiDeveloperDocs"
transport: "streamable_http"
url: "https://developers.openai.com/mcp"
Custom prompts (deprecated)
Markdown files in ~/.codex/prompts/ still work as /prompts:<name> slash
commands, with $1–$9, $ARGUMENTS, and named $UPPERCASE placeholders.
Prefer skills: they can be shared through a repository and invoked implicitly.
Subagents & Custom Agents
Subagents keep noisy intermediate output — exploration notes, test logs, stack traces — off the main thread. Ask for them directly:
Review this branch with parallel subagents. Spawn one for security risks, one for
test gaps, and one for maintainability. Wait for all three, then summarize the
findings by category with file references.
Use /agent (or /subagents) to switch between agent threads. Subagents inherit
the parent’s sandbox policy and any live overrides you set with /permissions
or --yolo, even when a custom agent file says otherwise. They cost more tokens
than one comparable run, so prefer them for read-heavy work — exploration,
triage, tests, summarization — and be cautious with parallel writes.
Built-in agents: default, worker, explorer.
Custom agent files
One TOML file per agent under ~/.codex/agents/ (personal) or .codex/agents/
(project). name, description, and developer_instructions are required; any
other config.toml key may appear too.
# .codex/agents/reviewer.toml
name = "reviewer"
description = "PR reviewer focused on correctness, security, and missing tests."
model = "gpt-5.6-terra"
model_reasoning_effort = "high"
sandbox_mode = "read-only"
developer_instructions = """
Review code like an owner.
Prioritize correctness, security, behavior regressions, and missing test coverage.
Lead with concrete findings and include reproduction steps when possible.
Avoid style-only comments unless they hide a real bug.
"""
[mcp_servers.openaiDeveloperDocs]
url = "https://developers.openai.com/mcp"
# config.toml
[agents]
enabled = true
max_concurrent_threads_per_session = 8
default_subagent_model = "gpt-5.6-luna"
default_subagent_reasoning_effort = "medium"
interrupt_message = true
Codex identifies an agent by its name field, not the filename. A custom agent
that reuses a built-in name replaces it.
MCP Servers
Model Context Protocol servers give Codex tools beyond the repository. The CLI, IDE extension, and desktop app share the same configuration.
codex mcp add context7 -- npx -y @upstash/context7-mcp
codex mcp add gh --env GITHUB_TOKEN=$TOKEN -- npx -y @modelcontextprotocol/server-github
codex mcp add figma --url https://mcp.figma.com/mcp --bearer-token-env-var FIGMA_OAUTH_TOKEN
codex mcp list --json
codex mcp get context7
codex mcp login <name> # OAuth, streamable HTTP servers only
stdio servers
[mcp_servers.context7]
command = "npx"
args = ["-y", "@upstash/context7-mcp"]
cwd = "/opt/tools"
env_vars = ["LOCAL_TOKEN", { name = "REMOTE_TOKEN", source = "remote" }]
[mcp_servers.context7.env]
MY_ENV_VAR = "MY_ENV_VALUE"
Streamable HTTP servers
[mcp_servers.chrome_devtools]
url = "http://localhost:3000/mcp"
auth = "oauth" # oauth (default) | chatgpt
bearer_token_env_var = "DEVTOOLS_TOKEN"
http_headers = { "X-Region" = "us-east-1" }
env_http_headers = { "X-Trace" = "TRACE_ID" }
enabled = true
required = false # true makes `codex exec` fail if it cannot start
startup_timeout_sec = 20 # default 10
tool_timeout_sec = 45 # default 60
enabled_tools = ["open", "screenshot"]
disabled_tools = ["screenshot"] # applied after enabled_tools
default_tools_approval_mode = "prompt" # auto | prompt | writes | approve
[mcp_servers.chrome_devtools.tools.open]
approval_mode = "approve"
# Only needed when your OAuth provider demands a fixed callback
mcp_oauth_callback_port = 5555
mcp_oauth_callback_url = "https://devbox.example.internal/callback"
writes prompts only for tools that are not marked read-only. Tool calls that
advertise a destructive annotation always require approval.
Codex as an MCP server
codex mcp-server # speaks MCP over stdio so another agent can call Codex
Useful servers: OpenAI Docs, Context7, Playwright, Chrome DevTools, GitHub, Sentry, Figma.
Plugins
Plugins package skills, connectors, MCP servers, and hooks for distribution.
codex plugin marketplace add openai/skills # GitHub shorthand, Git URL, SSH URL, or local path
codex plugin marketplace add owner/repo@v1 --sparse skills/
codex plugin marketplace list --json
codex plugin marketplace upgrade # refresh all Git-backed marketplaces
codex plugin marketplace remove <name>
codex plugin add <plugin>@<marketplace> --json
codex plugin list --available --json
codex plugin remove <plugin> -m <marketplace>
[plugins."sample@test".mcp_servers.sample]
enabled = true
default_tools_approval_mode = "prompt"
enabled_tools = ["read", "search"]
Browse and toggle plugins in the TUI with /plugins.
Hooks
Hooks run your own scripts inside the agent loop — to log turns, block pasted secrets, enforce a validation step, or add directory-specific context.
| Timing | Events |
|---|---|
| During a turn | PreToolUse, PermissionRequest, PostToolUse, PreCompact, PostCompact, UserPromptSubmit, SubagentStop, Stop |
| At session or subagent start | SessionStart, SubagentStart |
| When the main thread ends | SessionEnd (not for subagents) |
Codex reads hooks.json or an inline [hooks] table next to each active config
layer. The four locations that matter in practice:
~/.codex/hooks.json~/.codex/config.toml<repo>/.codex/hooks.json<repo>/.codex/config.toml
{
"hooks": {
"SessionStart": [
{
"matcher": "startup|resume",
"hooks": [
{
"type": "command",
"command": "python3 ~/.codex/hooks/session_start.py",
"statusMessage": "Loading session notes",
"additionalContextLimit": 5000
}
]
}
],
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{ "type": "command", "command": "python3 ~/.codex/hooks/check_bash.py", "timeout": 30 }
]
}
]
}
}
# Equivalent inline form
[[hooks.PreToolUse]]
matcher = "^Bash$"
[[hooks.PreToolUse.hooks]]
type = "command"
command = '/usr/bin/python3 "$(git rev-parse --show-toplevel)/.codex/hooks/pre_tool_use_policy.py"'
timeout = 30
statusMessage = "Checking Bash command"
Every matching hook from every layer runs, and matching command hooks for one
event start concurrently. A non-managed command hook must be reviewed and
trusted before it runs; Codex records trust against the hook’s hash, so editing
a hook sends it back for review. Manage all of this with /hooks. Project hooks
load only when the project .codex/ layer is trusted.
Rules (execpolicy)
Rules decide which commands may run outside the sandbox. They are experimental and written in Starlark.
# ~/.codex/rules/default.rules
prefix_rule(
pattern = ["gh", "pr", "view"],
decision = "prompt", # allow | prompt | forbidden
justification = "Viewing PRs is allowed with approval",
match = [
"gh pr view 7888",
"gh pr view --repo openai/codex",
],
not_match = [
"gh pr --repo openai/codex view 7888", # pattern must be an exact prefix
],
)
codex execpolicy check --pretty \
--rules ~/.codex/rules/default.rules \
-- gh pr view 7888 --json title,body,comments
Codex scans rules/ under every active config layer, including
<repo>/.codex/rules/ when the project is trusted. When several rules match, the
most restrictive decision wins (forbidden > prompt > allow). Allowing a
command from the TUI writes it to ~/.codex/rules/default.rules.
Codex splits a shell wrapper such as bash -lc "git add . && rm -rf /" into
separate commands when the script is a plain chain joined by &&, ||, ;, or
|, then evaluates each one — so allowing git add never auto-allows the rm.
When the script uses redirection, substitution, variables, globs, or control
flow, Codex refuses to split it and applies your rules to the whole invocation.
Non-Interactive Mode (codex exec)
codex exec "summarize the repository structure and list the top 5 risky areas"
codex exec --sandbox workspace-write "fix the failing unit test"
codex exec --ephemeral "triage this repository" # no rollout files on disk
codex e "short form"
Progress goes to stderr; only the final message goes to stdout, so piping is clean:
codex exec "generate release notes for the last 10 commits" | tee release-notes.md
Stdin
# Prompt as the argument, piped output as context
npm test 2>&1 | codex exec "summarize the failing tests and propose the smallest fix"
# Stdin is the whole prompt
cat prompt.txt | codex exec -
generate_prompt.sh | codex exec - --json > result.jsonl
Machine-readable output
codex exec --json "summarize the repo structure" | jq
{"type":"thread.started","thread_id":"0199a213-81c0-7800-8aa1-bbab2a035a53"}
{"type":"turn.started"}
{"type":"item.started","item":{"id":"item_1","type":"command_execution","command":"bash -lc ls","status":"in_progress"}}
{"type":"item.completed","item":{"id":"item_3","type":"agent_message","text":"Repo contains docs, sdk, and examples."}}
{"type":"turn.completed","usage":{"input_tokens":24763,"cached_input_tokens":24448,"output_tokens":122,"reasoning_output_tokens":0}}
Event types: thread.started, turn.started, turn.completed, turn.failed,
item.*, error. Items cover agent messages, reasoning, command executions,
file changes, MCP tool calls, web searches, and plan updates.
Structured output
{
"type": "object",
"properties": {
"project_name": { "type": "string" },
"programming_languages": { "type": "array", "items": { "type": "string" } }
},
"required": ["project_name", "programming_languages"],
"additionalProperties": false
}
codex exec "Extract project metadata" \
--output-schema ./schema.json \
-o ./project-metadata.json
Resume
codex exec "review the change for race conditions"
codex exec resume --last "fix the race conditions you found"
codex exec resume <SESSION_ID> "now add tests"
codex exec resume --last --all "continue" # consider sessions from any directory
Automation notes
- Set the least permission the job needs. The default is read-only.
codex execrefuses to run outside a Git repository; use--skip-git-repo-checkwhen you are sure.CODEX_API_KEYworks only incodex exec. Set it inline for the single invocation, never as a job-level variable in a workflow that also runs repository-controlled code.- An enabled MCP server with
required = truethat fails to initialize makescodex execexit with an error. - Pair
--jsonwith-oin CI to capture both the event stream and the final summary.
Configuration
User settings live in ~/.codex/config.toml. Project overrides live in
.codex/config.toml files inside the repository.
Precedence, highest first
- CLI flags and
-c/--configoverrides - Project config:
.codex/config.toml, root down to the working directory (closest wins, trusted projects only) - Profile file selected with
--profile <name>(~/.codex/<name>.config.toml) - User config:
~/.codex/config.toml - System config:
/etc/codex/config.toml - Built-in defaults
Run /debug-config to print the resolved layer order and any policy that
overrides it.
Project trust
If a project is untrusted, Codex skips every project .codex/ layer — config,
hooks, and rules. User and system layers still load. Project config also cannot
set machine-local keys; Codex ignores and warns about openai_base_url,
chatgpt_base_url, apps_mcp_product_sku, model_provider, model_providers,
notify, profile, profiles, experimental_realtime_ws_base_url, and otel
in a project file.
Profiles
Each profile is its own file with top-level keys:
# ~/.codex/deep-review.config.toml
model = "gpt-5.6-sol"
model_reasoning_effort = "xhigh"
approval_policy = "on-request"
codex --profile deep-review
codex exec --profile deep-review "review this change"
Since Codex 0.134.0, [profiles.<name>] tables inside config.toml and the
top-level profile = "<name>" selector no longer work. Move them to separate
profile files.
Model providers
model = "gpt-5.6-terra"
model_provider = "proxy"
[model_providers.proxy]
name = "OpenAI via LLM proxy"
base_url = "https://proxy.example.com/v1"
env_key = "OPENAI_API_KEY" # or requires_openai_auth = true to reuse Codex login
wire_api = "responses"
http_headers = { "X-Example" = "value" }
env_http_headers = { "X-Features" = "EXAMPLE_FEATURES" }
[model_providers.azure]
name = "Azure"
base_url = "https://YOUR_PROJECT.openai.azure.com/openai"
env_key = "AZURE_OPENAI_API_KEY"
query_params = { api-version = "2025-04-01-preview" }
wire_api = "responses"
To point the built-in provider at a proxy without defining a new one, set
openai_base_url. openai, ollama, and lmstudio are reserved provider IDs.
Chat Completions support is deprecated; prefer wire_api = "responses".
Command-backed auth for providers that mint short-lived tokens:
[model_providers.proxy.auth]
command = "/usr/local/bin/fetch-codex-token"
args = ["--audience", "codex"]
timeout_ms = 5000
refresh_interval_ms = 300000 # 0 refreshes only after an auth retry
The command receives no stdin and prints the token to stdout. Do not combine it
with env_key, experimental_bearer_token, or requires_openai_auth.
Amazon Bedrock is built in:
model_provider = "amazon-bedrock"
model = "<bedrock-model-id>"
[model_providers.amazon-bedrock.aws]
profile = "default"
region = "eu-central-1"
Local models
codex --oss --local-provider ollama
oss_provider = "ollama" # ollama | lmstudio
codex exec --oss errors out when neither --local-provider nor oss_provider
is set; the interactive CLI prompts instead.
Feature flags
codex features list
codex features enable memories
codex features disable hooks
codex --enable network_proxy --disable pets # one run only
| Flag | Default | Purpose |
|---|---|---|
apps | true | App (connector) integrations |
goals | true | Persisted goals and automatic continuation |
hooks | true | Lifecycle hooks |
fast_mode | true | Fast service tier and /fast |
memories | false | Memories (experimental) |
multi_agent | true | Subagent tools |
personality | true | Personality selection |
remote_plugin | true | Remote plugin catalog |
shell_snapshot | true | Cache the shell environment between commands |
shell_tool | true | The default shell tool |
unified_exec | true except Windows | PTY-backed exec tool and background terminals |
network_proxy | false | Constrain outbound traffic to a policy |
web_search, web_search_cached, and web_search_request are deprecated flags;
use the top-level web_search setting instead.
Command environment
[shell_environment_policy]
inherit = "core" # all | core | none
ignore_default_excludes = false # false turns ON filtering of *KEY*, *SECRET*, *TOKEN*
[shell_environment_policy.filters]
"PATH" = "include"
"HOME" = "include"
ignore_default_excludes defaults to true, meaning Codex does not filter
variables whose names contain KEY, SECRET, or TOKEN. Set it to false to
turn that filtering on.
Notifications
notify = ["python3", "/path/to/notify.py"] # external program, user config only
[tui]
notifications = true # or ["agent-turn-complete", "approval-requested"]
notification_method = "auto" # auto | osc9 | bel
notification_condition = "unfocused" # unfocused | always
The notify program receives one JSON argument. The only event today is
agent-turn-complete, and the payload carries type, thread-id, turn-id,
cwd, input-messages, and last-assistant-message.
History
[history]
persistence = "save-all" # save-all | none
max_bytes = 104857600 # 100 MiB; oldest entries drop first
Clickable citations
file_opener = "vscode" # vscode | vscode-insiders | windsurf | cursor | none
A citation like /home/user/project/main.py:42 becomes a vscode://file/…:42
link.
Config Key Reference
The keys you are most likely to set. See
/debug-config for what is actually in effect.
| Key | Values | Notes |
|---|---|---|
model | string | Active model |
review_model | string | Model for /review only |
model_provider | provider id | Default openai |
model_reasoning_effort | minimal…xhigh | Responses API models |
model_reasoning_summary | auto, concise, detailed, none | Summary detail |
model_verbosity | low, medium, high | Response length |
model_context_window | number | Override the detected window |
model_auto_compact_token_limit | number | When automatic compaction kicks in |
personality | none, friendly, pragmatic | Communication style |
service_tier | string | fast maps to request priority |
approval_policy | untrusted, on-request, never, { granular = … } | on-failure is deprecated |
approvals_reviewer | user, auto_review | Who screens approval requests |
sandbox_mode | read-only, workspace-write, danger-full-access | Command sandbox |
sandbox_workspace_write.network_access | boolean | Off by default |
sandbox_workspace_write.writable_roots | array | Extra writable directories |
allow_login_shell | boolean | Default true; false rejects login shells |
default_permissions | profile name | Do not mix with sandbox_mode |
web_search | disabled, cached, indexed, live | Default cached |
windows.sandbox | elevated, unelevated | Native Windows only |
project_doc_max_bytes | number | Default 32768 |
project_doc_fallback_filenames | array | Extra instruction filenames |
project_root_markers | array | Default [".git"] |
developer_instructions | string | Extra instructions injected into the session |
model_instructions_file | path | Replaces the built-in instructions instead of AGENTS.md |
history.persistence | save-all, none | Local transcript storage |
history.max_bytes | number | Cap the history file |
tool_output_token_limit | number | Token budget per stored tool output |
file_opener | editor scheme | Clickable citations |
notify | array | External notification command |
tui.notifications | boolean or array | Terminal notifications |
tui.resume_cwd | current, session | Skip the resume directory prompt |
tui.alternate_screen | auto, always, never | never keeps terminal scrollback |
tui.vim_mode_default | boolean | Vim composer by default |
tui.theme | theme name | Syntax highlighting |
tui.status_line | array or null | Footer items |
hide_agent_reasoning | boolean | Quieter CI logs |
show_raw_agent_reasoning | boolean | Surface raw reasoning when emitted |
check_for_update_on_startup | boolean | Disable when updates are centrally managed |
cli_auth_credentials_store | file, keyring, auto | Credential storage |
forced_login_method | chatgpt, api | Managed environments |
forced_chatgpt_workspace_id | UUID | Restrict to one workspace |
log_dir | path | Setting it enables codex-tui.log |
sqlite_home | path | SQLite-backed runtime state |
Environment Variables
| Variable | Used by | Purpose |
|---|---|---|
CODEX_HOME | everything | Root for config, auth, logs, sessions, skills. Codex creates the default ~/.codex for you, but when you set CODEX_HOME yourself the directory must already exist — Codex does not create it and exits with CODEX_HOME points to "…", but that path does not exist |
CODEX_SQLITE_HOME | CLI, app server | SQLite state location; sqlite_home config wins |
CODEX_API_KEY | codex exec only | API key for a single non-interactive run |
CODEX_ACCESS_TOKEN | CLI, app server | ChatGPT or Codex access token for trusted automation |
CODEX_CA_CERTIFICATE | HTTPS, login, WebSocket | PEM CA bundle; takes precedence over SSL_CERT_FILE |
SSL_CERT_FILE | HTTPS, login, WebSocket | Fallback CA bundle |
RUST_LOG | CLI, app server | Log filter: error, warn, info, debug, trace, or targeted filters |
CODEX_NON_INTERACTIVE | installers | Skip installer prompts |
CODEX_INSTALL_DIR | installers | Where the codex command is installed |
VISUAL / EDITOR | TUI | Editor opened by Ctrl+G |
# Verbose troubleshooting run with a plaintext log
RUST_LOG=debug codex -c log_dir=./.codex-log
tail -F ./.codex-log/codex-tui.log
# Targeted filters
RUST_LOG=codex_core=debug,codex_tui=debug codex
# Create the directory first when you point CODEX_HOME somewhere new
mkdir -p /srv/codex-home
CODEX_HOME=/srv/codex-home codex
codex exec defaults to RUST_LOG=error and prints messages inline instead of
to a separate log file.
Files & State Locations
| Path | Contents |
|---|---|
~/.codex/config.toml | User configuration |
~/.codex/<profile>.config.toml | Profile layer selected with --profile |
~/.codex/AGENTS.md, AGENTS.override.md | Global instructions |
~/.codex/auth.json | Cached credentials when using file storage. Treat as a secret |
~/.codex/history.jsonl | Session transcript history when history.persistence is on |
~/.codex/sessions/ | Session transcripts (session-*.jsonl) |
~/.codex/archived_sessions/ | Archived transcripts |
~/.codex/agents/ | Personal custom agent files |
~/.codex/rules/ | execpolicy .rules files |
~/.codex/prompts/ | Deprecated custom prompts |
~/.codex/themes/ | Custom .tmTheme files |
~/.codex/hooks.json | User hooks |
~/.codex/worktrees/ | Desktop-app managed worktrees |
~/.codex/log/ | Logs, including codex-login.log |
~/.agents/skills/ | User skills |
<repo>/.codex/config.toml | Project configuration (trusted projects only) |
<repo>/.codex/agents/, rules/, hooks.json | Project agents, rules, hooks |
<repo>/.agents/skills/ | Repository skills |
<repo>/AGENTS.md | Project instructions |
/etc/codex/config.toml | System configuration |
/etc/codex/skills/ | Machine-wide skills |
~/Library/Logs/com.openai.codex/YYYY/MM/DD | Desktop app logs (macOS) |
Code Review
codex review --uncommitted
codex review --base main
codex review --commit 1a2b3c4
In a session, /review offers four scopes:
- Against a base branch — finds the merge base and reviews the branch diff.
- Uncommitted changes — staged, unstaged, and untracked files.
- A commit — the exact change set of one commit.
- Custom instructions — your own criteria.
The reviewer reads the diff and reports prioritized findings without touching
your working tree. It uses the session model unless you set review_model. If
you then ask Codex to apply the fixes, your normal sandbox and approval settings
apply.
Repository-wide review criteria belong in a ## Code Review Rules section of the
AGENTS.md nearest the code they govern. Keep them about behavior, and leave
formatting to CI.
Codex in CI
Prefer the openai/codex-action over
installing the CLI and exporting a key yourself. The action installs Codex,
starts a Responses API proxy, and runs codex exec under a safety strategy.
name: Codex pull request review
on:
pull_request:
types: [opened, synchronize, reopened]
jobs:
codex:
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
final_message: ${{ steps.run_codex.outputs.final-message }}
steps:
- uses: actions/checkout@v5
with:
ref: refs/pull/${{ github.event.pull_request.number }}/merge
fetch-depth: 0
persist-credentials: false
- name: Run Codex
id: run_codex
uses: openai/codex-action@v1
with:
openai-api-key: ${{ secrets.OPENAI_API_KEY }}
prompt-file: .github/codex/prompts/review.md
output-file: codex-output.md
sandbox: read-only
| Input | Purpose |
|---|---|
prompt / prompt-file | Inline instructions or a repository path. Set exactly one |
codex-args | Extra CLI flags as a JSON array (["--ephemeral"]) or a string |
model, effort | Model and reasoning effort |
sandbox | read-only, workspace-write, danger-full-access |
output-file | Where to save the final message |
codex-version | Pin a CLI release |
codex-home | Reuse a configuration directory across steps |
safety-strategy | drop-sudo (default), unprivileged-user, read-only, unsafe |
codex-user | Account to run as with unprivileged-user |
allow-users, allow-bots | Who may trigger the workflow beyond write collaborators |
Windows runners require safety-strategy: unsafe. The final-message output
carries the last Codex message.
Separate the key from write access
Give the Codex job contents: read and have it upload a patch artifact. Apply
that patch and open the pull request in a second job that has write permission
but no API key:
- name: Create patch artifact
run: |
git add -N .
git diff --binary HEAD > codex.patch
Sanitize any prompt text that comes from pull requests, commit messages, or issue bodies. Hidden HTML comments are a prompt-injection vector.
Codex SDK
TypeScript (Node 18+)
npm install @openai/codex-sdk
const codex = new Codex();
const thread = codex.startThread();
const result = await thread.run("Make a plan to diagnose and fix the CI failures");
console.log(result.finalResponse);
const next = await thread.run("Implement the plan");
const resumed = codex.resumeThread("<thread-id>");
await resumed.run("Pick up where you left off");
Python (3.10+)
pip install openai-codex
from openai_codex import Codex, Sandbox
with Codex() as codex:
thread = codex.thread_start(
model="gpt-5.6-terra",
sandbox=Sandbox.workspace_write,
)
result = thread.run("Make a plan to diagnose and fix the CI failures")
print(result.final_response)
review = thread.run("Review the diff only.", sandbox=Sandbox.read_only)
import asyncio
from openai_codex import AsyncCodex
async def main() -> None:
async with AsyncCodex() as codex:
thread = await codex.thread_start(model="gpt-5.6-terra")
result = await thread.run("Implement the plan")
print(result.final_response)
asyncio.run(main())
Sandbox presets: Sandbox.read_only, Sandbox.workspace_write,
Sandbox.full_access. A sandbox passed to run() applies to that turn and every
later turn on the thread.
Use the SDK for coding threads. When Codex is one specialist inside a wider
orchestration, run codex mcp-server and drive it from the Agents SDK instead.
Codex Cloud
Codex cloud runs tasks in isolated OpenAI-managed containers. Setup runs first with network access to install dependencies; the agent phase then runs offline unless you enable internet access for that environment. Secrets are available only during setup and are removed before the agent phase.
codex cloud # interactive picker
codex cloud exec --env <ENV_ID> "migrate the config loader" --attempts 3
codex cloud list --env <ENV_ID> --limit 20 --json
codex apply <TASK_ID> # apply the resulting diff locally
codex cloud list --json returns a tasks array with id, url, title,
status, updated_at, environment_id, environment_label, summary,
is_review, and attempt_total, plus an optional cursor. --attempts accepts
1–4 and runs best-of-N. codex apply exits non-zero when git apply fails.
Getting started: open chatgpt.com/codex, connect GitHub, create an environment for the repository, then start a task. You can also start work from GitHub pull requests, Linear issues, and Slack.
IDE Extension
Install the ChatGPT extension for VS Code, Cursor, Windsurf, or VS Code Insiders. Xcode and JetBrains IDEs have their own Codex integrations.
| Command ID | Default binding | Purpose |
|---|---|---|
chatgpt.openSidebar | — | Open the Codex sidebar |
chatgpt.newChat | Cmd+N / Ctrl+N | New chat |
chatgpt.newCodexPanel | — | New Codex panel |
chatgpt.addToThread | — | Add the selected range as context |
chatgpt.addFileToThread | — | Add the whole file as context |
chatgpt.openCommandMenu | — | Open the command menu |
IDE slash commands: /approve, /cloud, /cloud-environment, /compact,
/fast, /feedback, /fork, /goal, /ide-context, /init, /local,
/mcp, /memories, /model, /personality, /plan, /project,
/reasoning, /review, /side, /status, /worktree.
On Windows, keep the agent inside WSL2 so it inherits Linux sandbox semantics:
{ "chatgpt.runCodexInWindowsSubsystemForLinux": true }
Set chatgpt.reviewDelivery to detached when /review should open its own
chat instead of running in the current one.
Observability
Telemetry is off by default.
[otel]
environment = "staging" # dev | staging | prod
exporter = "none" # none | otlp-http | otlp-grpc
log_user_prompt = false # keep false unless policy allows storing prompts
[otel]
exporter = { otlp-http = {
endpoint = "https://otel.example.com/v1/logs",
protocol = "binary",
headers = { "x-otlp-api-key" = "${OTLP_TOKEN}" }
}}
Representative events: codex.conversation_starts, codex.api_request,
codex.sse_event, codex.websocket_request, codex.websocket_event,
codex.user_prompt, codex.tool_decision, codex.tool_result. Each has a
matching counter and duration histogram.
Route telemetry only to collectors you control, apply retention limits, and redact tool arguments and outputs at the collector. Export cannot reach your collector when the CLI runs with network access off.
Common Issues & Solutions
| Issue | Cause | Fix |
|---|---|---|
codex exec refuses to start | Not inside a Git repository | Run it in a repo, or pass --skip-git-repo-check |
| Sandbox fails to start in Docker | Container blocks namespaces, setuid bwrap, or seccomp | Make the container the boundary and run --sandbox danger-full-access inside it |
Project .codex/config.toml ignored | Project is untrusted, or the key is machine-local | Trust the project; move model_providers, notify, otel, and similar keys to user config |
| Instructions look stale or wrong | An AGENTS.override.md higher in the tree, or a truncated file | Remove the override; raise project_doc_max_bytes or split the file |
| Fallback instruction filenames ignored | Not listed in config | Add them to project_doc_fallback_filenames and restart |
| Browser login never completes | Headless host or blocked localhost callback | codex login --device-auth, forward port 1455 over SSH, or copy auth.json |
| TLS errors on login or requests | Corporate TLS interception | Set CODEX_CA_CERTIFICATE to a PEM bundle |
| Codex asks approval for everything | approval_policy = "untrusted" | Switch to on-request, or add a prefix_rule with decision = "allow" |
| A command needs the network and stalls | workspace-write blocks network by default | Set sandbox_workspace_write.network_access = true, ideally with network_proxy |
| Answers cite outdated releases | Web search is cached by default | Run with --search or set web_search = "live" |
| MCP server never appears | Slow start, or disabled | Raise startup_timeout_sec, check enabled, run /mcp verbose |
codex exec exits over an MCP server | Server has required = true and failed to initialize | Fix the server or set required = false |
| A hook never runs | Non-managed hooks need explicit trust | Review and trust it with /hooks |
| A hook stopped running after an edit | Trust is recorded against the hook hash | Re-trust the changed hook in /hooks |
allowing git add did not allow a chained command | Codex splits safe shell chains and evaluates each part | Write a rule for the other command, or approve it once |
--profile has no effect | [profiles.<name>] tables stopped working in 0.134.0 | Move settings to ~/.codex/<name>.config.toml |
| Model not found or rejected | gpt-5.4, gpt-5.4-mini, gpt-5.2, or gpt-5.3-codex under ChatGPT sign-in | Use gpt-5.6-terra or gpt-5.6-luna |
/fast is missing | The active model advertises no Fast tier | Switch models, or check features.fast_mode |
| Sandbox broken on Windows | WSL1 is unsupported since 0.115 | Move to WSL2, or use the native Windows sandbox |
| Windows sandbox reported as degraded | Restricted-token fallback in use | Run /setup-default-sandbox and set windows.sandbox = "elevated" |
fatal: '<branch>' is already used by worktree at … | Git allows one checkout per branch | Check out a different branch on the worktree, or hand the chat off to Local |
| Secrets leak into spawned commands | Default policy does not filter *KEY*, *SECRET*, *TOKEN* | Set shell_environment_policy.ignore_default_excludes = false or use include_only |
| Chat degrades over a long run | Context filled with intermediate output | /compact, /new, or delegate noisy work to subagents |
| CI logs are noisy | Reasoning events are printed | Set hide_agent_reasoning = true |
| Feature works in the CLI but not the desktop app | The two ship different Codex versions | Compare codex --version with /Applications/Codex.app/Contents/Resources/codex --version |
Quick Tips
- Run
/statusbefore you trust a session. It shows the model, the approval policy, and the writable roots you are actually running under. - Commit before and after a Codex task. A clean tree makes its patch trivial to review and revert.
- Put durable rules in
AGENTS.md, not in every prompt. Add a rule only after Codex makes the same mistake twice. - State the goal, the context, the constraints, and how you will judge the result. A prompt missing the last part usually produces work you have to redo.
- Prefer
--add-dirover--sandbox danger-full-accesswhen Codex needs to write somewhere else. --yolobelongs inside a disposable VM or container, nowhere else.- Use
--sandbox read-onlyfor anything exploratory. Most questions do not need write access. codex execwrites progress to stderr and only the final message to stdout, so it pipes cleanly. Add--jsonwhen a script must read the events.- Use
--output-schemawhen a downstream step needs stable fields; parsing prose is a false economy. - Keep one chat per outcome. Use
/forkto explore an alternative and/compactbefore the context fills. - Delegate read-heavy work — exploration, triage, log analysis — to subagents so their output never lands in the main thread. Be careful with parallel writes.
- Turn a workflow you have repeated three times into a skill, not another prompt.
- Treat every web result and MCP tool output as untrusted input. Cached search is the default for exactly that reason.
- Never set
OPENAI_API_KEYorCODEX_API_KEYjob-wide in a workflow that also runs repository-controlled code. - Give the CI job that runs Codex
contents: readand let a separate job hold write permission. - Pin
codex-versionin CI so a new release cannot change your pipeline’s behavior overnight. - Run
codex doctorbefore filing a bug; it checks installation, config, auth, Git, and terminal in one pass. codex execpolicy checktests a rule before you rely on it, andmatch/not_matchact as inline unit tests inside the rule itself.