Skip to content

Codex configuration lives in config.toml files that stack in a fixed order: built-in defaults, system config, your user file at ~/.codex/config.toml, an optional --profile file, a trusted repository’s .codex/config.toml, and finally command-line overrides. Codex ignores a mistyped key with only a startup warning.

This guide is for developers setting up Codex for themselves and tech leads writing the project config a whole team commits. The situation it prevents is familiar: you set web_search = "live", searches still come from the cache, and the reason is a typo that Codex skipped without stopping. Or a colleague’s run passes a test that fails for you because a repository config you never read overrode your sandbox.

  • A user ~/.codex/config.toml whose every line you can explain, validated by your editor against Codex’s own schema
  • A committed .codex/config.toml that gives the whole team the same permissions and secret filtering
  • Profiles for review, quick iteration, unattended runs, and local models, switched with one flag
  • A four-command check (codex doctor, /status, /debug-config, codex sandbox) that proves what is in effect, instead of trusting the file
  • Three copy-paste prompts that audit a configuration, explain why a setting did not apply, and draft the team config

Every key and command on this page was checked against codex-cli 0.157.1 on 2026-09-26, including a codex exec --strict-config run of each example file (the starter config, the project config, and the four profiles). The config keys in those files were checked again against the 0.162.1 config schema on 2026-10-12, and each is still listed; every behaviour stays stamped 0.157.1 unless its section says otherwise. The model, effort and speed statements that name GPT-6.1 Sol, codex-cli 0.159.1 or later, or 2026-10-12 come from the 0.162.1 model catalog and OpenAI’s pages as read on 2026-10-12. Install Codex and sign in first: see installing Codex and Codex authentication.

Codex builds one effective configuration from several layers. A later layer overrides an earlier one, key by key:

OrderLayerPathNotes
1Built-in defaultsInside CodexWhat you get with no file at all
2System/etc/codex/config.toml (Unix), %ProgramData%\OpenAI\Codex\config.toml (Windows)Machine-wide defaults
3Managed configmacOS managed preferences, enterprise cloud config fragmentsSet by admins; override system defaults
4User$CODEX_HOME/config.toml (CODEX_HOME defaults to ~/.codex)Your personal defaults
5Profile$CODEX_HOME/<name>.config.tomlOnly when you pass --profile <name>
6Project.codex/config.toml from the repository root down to the working directoryIgnored while the project is untrusted
7Session-c key=value, -m, -a, -s, --enable, --search, the model pickerThis run only

The order comes from the configuration loader in the Codex source (codex-rs/config/src/loader, checked 2026-09-26). Two consequences surprise people:

  • A project config beats your profile. If the repository sets model_reasoning_effort = "medium", codex --profile review with high still runs at medium. Override it for one run with -c model_reasoning_effort="high".
  • Administrators can also constrain values. Managed requirements.toml files (/etc/codex/requirements.toml, or the enterprise cloud bundle) do not set values; they limit which values any layer may choose. When a value you set is refused, the constraint is there, not in your file. Policy rollout is covered in Codex enterprise governance.

The CLI, the desktop app, and the IDE extension read the same CODEX_HOME. Codex cloud tasks do not read local files; you configure Codex cloud environments separately.

The file below is a complete user config. Each section after the steps explains one decision in it.

  1. Create ~/.codex/config.toml (or open the existing one) and paste:

    #:schema https://raw.githubusercontent.com/openai/codex/rust-v0.157.1/codex-rs/core/config.schema.json
    # Model: leave `model` unset to follow Codex's bundled default (GPT-6.1 Sol).
    # Tune effort first; switch model only when your own results say so.
    model_reasoning_effort = "medium"
    # Permissions: the built-in workspace profile writes only the workspace
    # and grants no network. Do not also set sandbox_mode.
    default_permissions = ":workspace"
    approval_policy = "on-request"
    # Web search: "cached" is the default; "live" fetches in real time.
    web_search = "cached"
    # Clickable file citations in your editor.
    file_opener = "vscode"
    # Keep variables named like keys, secrets and tokens out of commands.
    [shell_environment_policy]
    ignore_default_excludes = false
    [tui]
    notifications = ["agent-turn-complete", "approval-requested"]
  2. Install an editor extension that reads the #:schema directive (Even Better TOML in VS Code or Cursor). Unknown keys now show a red underline as you type. Pin the schema URL to the tag of the Codex version you run, because keys appear and disappear between releases.

  3. Validate the file with the installed binary. --strict-config turns an unknown key into an error instead of a warning:

    Terminal window
    codex exec --strict-config --ephemeral "Reply with OK."

    Run it from inside a trusted repository (or add --skip-git-repo-check); it makes one short model call.

    A typo stops the run with the file, line, and key: config.toml:14:1: unknown configuration field followed by the key name.

  4. Run codex doctor and read the Configuration block (model, config files, startup warnings with each ignored key) and the sandbox row below it (approval policy, filesystem and network restriction).

GPT-6.1 Sol is Codex’s bundled default model since codex-cli 0.159.1 (2026-09-29), and its default effort in Codex is low; Codex labels it “Latest workhorse model for coding and everyday work”. GPT-6 Astra (“Frontier intelligence for the most demanding work”), GPT-6 Sol (“Previous generation workhorse model”) and GPT-6 Luna (“Fast and affordable model for easier tasks”) sit below it in the picker. The older GPT-5.6 models remain selectable. OpenAI’s models page (checked 2026-10-12) recommends GPT-6.1 Sol for complex coding and agentic workflows and GPT-6 Luna for focused, repeatable tasks, and says to choose Astra “when a task needs the strongest capability across steps and tools”, so treat Astra as the model you pick by hand for the hardest work. Prices, context windows, and when to pick each model are on the models hub; this page does not repeat them.

GPT-5.5, which the 0.162.1 catalog labels “Legacy coding model.”, retires from ChatGPT, ChatGPT Work and Codex on 2026-10-14, on all plans (OpenAI models page, checked 2026-10-12); the OpenAI API is not affected. The 0.162.1 catalog still carries no retirement date for it, so the server enforces the date: move any model = "gpt-5.5" pin before then.

The rule the whole site follows: start on the default model, tune effort before switching model, and switch only when your own results say so. In practice:

  • Leave model unset in your user file, so a new bundled default reaches you on upgrade. Pin model = "gpt-6-luna" only in a profile that exists for cost reasons.
  • Set model_reasoning_effort to medium or high for daily work. GPT-6.1 Sol and Astra accept low through max plus Codex’s ultra (“Maximum reasoning with automatic task delegation”); Luna has no ultra. Change it live with /model.
  • Speed is a separate setting from model and effort. The Fast and Ultrafast tiers trade allowance for speed, and Ultrafast needs a Pro $500 plan or an eligible Enterprise or Edu plan in Codex; how service_tier, fast_mode and /fast fit together is on Codex credits, usage limits and cost optimization.
  • Codex opens a 272K-token window by default for the GPT-6 models. Raise it with model_context_window up to the catalog ceiling of 872K when a task needs it, and read Codex context patterns first, because a bigger window costs more per turn.

Choose permissions: permission profiles or the legacy sandbox

Section titled “Choose permissions: permission profiles or the legacy sandbox”

Two settings decide what Codex may do, and they are separate axes. The permissions decide what a command can technically touch. The approval policy decides whether Codex may ask you to cross that boundary.

For permissions, OpenAI now prefers permission profiles (beta, codex-cli 0.138.0 and later): default_permissions = ":workspace" writes the workspace and grants no network, and ":read-only" writes nothing. The legacy sandbox_mode key (read-only, workspace-write, danger-full-access) still works. Pick one system per file: OpenAI states that “the profile and legacy sandbox systems do not compose”, so never set default_permissions and sandbox_mode together.

approval_policyBehaviourUse it for
on-request (default)Works inside the permissions; asks before crossing themInteractive work
untrustedRemoved: codex-cli 0.157.1 refuses to start with it (“no longer supported; remove this setting”, checked 2026-09-26)Nothing; use on-request or granular
granularA table of per-category switches (shell commands, rules, skill scripts, MCP prompts); a category set to false is rejected instead of askedTeams that need finer control
neverNever asks; an action outside the permissions fails and the model gets the errorUnattended runs in a profile, never your default

On the command line, -a accepts only on-request and never in 0.157.1, and it applies to the interactive codex. codex exec rejects -a and needs none: it runs with approval never (on-request under --approve-for-me), and a codex -a … exec prefix does not change that. Setting approvals_reviewer = "auto_review" lets a reviewer model decide escalations instead of you; --approve-for-me does the same for one run, but it also switches to the legacy workspace-write sandbox, so don’t combine it with default_permissions. The cross-tool comparison of these modes, and the risk class each fits, is in permissions and sandboxing.

web_search accepts cached (the default), live, indexed, and disabled. cached answers from pre-fetched results and is the safer choice for most work. Set live in a profile, or pass codex --search for one session, when you need a release that shipped this week. Set disabled in unattended profiles, where a fetched page is untrusted input that nobody reads.

Keep secrets out of the commands Codex runs

Section titled “Keep secrets out of the commands Codex runs”

By default, every command Codex spawns inherits your whole shell environment, cloud credentials included. [shell_environment_policy] controls that:

[shell_environment_policy]
inherit = "all" # "all" (default), "core" (HOME, PATH, SHELL, USER…), or "none"
ignore_default_excludes = false # default true: set false to drop *KEY*, *SECRET*, *TOKEN* names
exclude = ["AWS_*", "AZURE_*"] # extra patterns to drop
set = { NODE_ENV = "test" } # injected into every command

The effect is observable. With ignore_default_excludes = false in 0.157.1, this canary printed MY_VAR=1 and nothing else; with the default, it also printed FAKE_API_KEY=abc:

Terminal window
FAKE_API_KEY=abc MY_VAR=1 codex sandbox -- sh -c 'env | grep -E "FAKE_API_KEY|MY_VAR"'

exclude and include_only are the legacy array form; the canonical form is a table, [shell_environment_policy.filters] with "AWS_*" = "exclude". Do not mix the two in one file.

Because Codex inherits the shell, launch it from a ready one. Activate the virtual environment, start the services the tests need, and export non-secret variables first. Otherwise Codex spends turns discovering that pytest is missing or Postgres is down:

Terminal window
source .venv/bin/activate
docker compose up -d postgres redis
export DATABASE_URL="postgresql://localhost:5432/myapp_test"
codex

A variable the tests need that matches *KEY*, *SECRET*, or *TOKEN* is now filtered out. Pass a test-only value with set, never the production one.

Commit a project config for the whole team

Section titled “Commit a project config for the whole team”

A repository’s .codex/config.toml is where a tech lead makes behaviour consistent for everyone who trusts the project. Keep it to settings that belong to the codebase, and leave model choice to each person:

# .codex/config.toml: committed; reviewed like CI config
default_permissions = ":workspace"
approval_policy = "on-request"
web_search = "cached"
[shell_environment_policy]
ignore_default_excludes = false
set = { NODE_ENV = "test", TZ = "UTC" }

A project file cannot choose where credentials go or which local commands run: model_provider, notify, profile and base-URL keys are ignored there and must live in user or system config (checked in codex-rs/config/src/loader, 0.157.1).

Treat a change to this file as a harness change: it alters what every developer’s agent may do. Require review from the harness owner, and attach the codex sandbox canary output from the next section to the pull request, as described in the evidence bundle. Project instructions belong in AGENTS.md, not here; see AGENTS.md for Codex. MCP servers can go in either file as [mcp_servers.<name>] tables; see Codex MCP setup.

A profile is a separate file, $CODEX_HOME/<name>.config.toml, layered on your user config when you pass --profile <name> (or -p). The older [profiles.<name>] tables inside config.toml are still parsed but superseded; use files.

~/.codex/review.config.toml
model_reasoning_effort = "high"
review_model = "gpt-6-astra" # model used by /review
approval_policy = "on-request"

Run with codex --profile review, then /review. It inherits default_permissions from your user file.

A profile applies only when you name it on the command line. To see which layers a session loaded, run /debug-config.

You do not need to edit a file to change one run:

Terminal window
codex -m gpt-6-sol # model for this session
codex -c model_reasoning_effort="high" # any key, as TOML
codex -c shell_environment_policy.inherit=core # nested keys use dots
codex --enable memories # same as -c features.memories=true
codex --search # live web search for this session
codex exec --ephemeral "Run the linter and report." # exec: approval is never

codex features list prints every flag with its stage and effective state; codex features enable <name> and disable <name> write the change to config.toml under [features]. Flags are read at startup, so restart Codex after a change. In 0.157.1:

FlagStageDefaultWhat it does
shell_snapshotstableonSnapshots the shell environment so repeated commands start faster
unified_execstableonPTY-backed command execution
goalsstableonPersisted goals and automatic continuation (/goal)
multi_agentstableonSubagents
memoriesstableoffMemory across sessions; turn it on deliberately

Some flags still appear in the list with stage removed, including personality, steer, tool_search, and js_repl. Toggling them changes nothing. The same goes for the personality config key: “friendly and pragmatic no longer select a style” (checked in config_toml.rs, 2026-09-26).

Prove the configuration does what you think

Section titled “Prove the configuration does what you think”

A configuration file is a claim. These checks turn it into evidence, and none of them needs you to read the agent’s output line by line:

  1. Codex parses every key. Run codex doctor --all. Under Configuration, “startup warnings” must be 0; each ignored key is listed by name and layer.

  2. The right layer wins. In the TUI, /debug-config shows the config layers and requirement sources, and /status shows the session’s model, approvals, and sandbox. A non-interactive run prints the same header: model:, approval:, sandbox:.

  3. The boundary holds. Run a canary through the same sandbox the agent gets. With default_permissions = ":workspace" in 0.157.1, this printed ok, then Read-only file system for /etc/probe:

    Terminal window
    codex sandbox -- sh -c 'echo ok > probe.txt && cat probe.txt; echo x > /etc/probe'
  4. Secrets stay out. Run the env canary from the secrets section. No *KEY*, *SECRET*, or *TOKEN* name may appear.

The developer runs these after any change to their own file. For a committed .codex/config.toml, the tech lead or harness owner signs off on the canary output in the pull request, not on the settings diff. Re-run all four after every Codex upgrade, because keys and defaults move between releases.

A setting has no effect, and nothing errors. Codex skips unknown keys with a startup warning, so web_serach = "live" or the deprecated personality key does nothing. Run codex doctor --all and read the ignored keys, or run once with --strict-config, then fix the spelling against the schema.

The project config is ignored. The project is untrusted. Reopen Codex in the repository and accept the trust prompt, or check the [projects."<path>"] entry in your user config. Trust the project only after you have read its .codex/ directory.

Your profile setting loses. A trusted project’s .codex/config.toml sits above profiles. Use -c key=value for the run, or agree a different value in the project file.

A command fails with “invalid value” for -a. Only on-request and never are accepted by -a in 0.157.1; on-failure and untrusted are rejected there. For finer control than on-request, set granular (a table) in config.toml, which -a cannot express; untrusted is refused in config.toml too. A -a after exec fails as an unexpected argument; move it before the subcommand.

Codex refuses a sandbox or approval value you set. A managed requirements.toml constrains it. Run /debug-config to see the requirement source, then take the question to whoever owns the policy.

Tests fail inside Codex but pass in your terminal. The environment policy removed a variable the tests need. Check with the env canary, then add a test-only value under set. Never widen inherit or flip ignore_default_excludes back to true to fix one variable.

The run cannot reach the network. :workspace grants no network. Install dependencies before starting Codex, or define a named [permissions] profile with per-domain network access; the permissions and sandboxing guide shows how.

A model name is rejected. The model is not in your version’s catalog, or your plan or workspace does not include it. Pick from /model, and update Codex with codex update. GPT-6 Sol and Luna need codex-cli 0.155.0 or later. GPT-5.5 stops being available in Codex on 2026-10-14 (OpenAI models page, checked 2026-10-12).

A custom provider stops connecting. Current Codex releases do not support wire_api = "chat" or a Chat Completions-only endpoint (OpenAI models page, checked 2026-10-12). Point model_provider at an endpoint that supports the Responses API; the provider block is shown in advanced Codex setups.

Recovery of last resort. Move ~/.codex/config.toml aside, start Codex, and confirm it runs on defaults. Then add your settings back one block at a time, running codex doctor after each block.

Did this guide help you?

One tap, no sign-in.

not at all a lot