Configure Codex with config.toml: model, permissions, and profiles
PLCodex 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.
What a deliberate config.toml gives you
Section titled “What a deliberate config.toml gives you”- A user
~/.codex/config.tomlwhose every line you can explain, validated by your editor against Codex’s own schema - A committed
.codex/config.tomlthat 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.
Where does Codex read configuration from?
Section titled “Where does Codex read configuration from?”Codex builds one effective configuration from several layers. A later layer overrides an earlier one, key by key:
| Order | Layer | Path | Notes |
|---|---|---|---|
| 1 | Built-in defaults | Inside Codex | What you get with no file at all |
| 2 | System | /etc/codex/config.toml (Unix), %ProgramData%\OpenAI\Codex\config.toml (Windows) | Machine-wide defaults |
| 3 | Managed config | macOS managed preferences, enterprise cloud config fragments | Set by admins; override system defaults |
| 4 | User | $CODEX_HOME/config.toml (CODEX_HOME defaults to ~/.codex) | Your personal defaults |
| 5 | Profile | $CODEX_HOME/<name>.config.toml | Only when you pass --profile <name> |
| 6 | Project | .codex/config.toml from the repository root down to the working directory | Ignored while the project is untrusted |
| 7 | Session | -c key=value, -m, -a, -s, --enable, --search, the model picker | This 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 reviewwithhighstill runs atmedium. Override it for one run with-c model_reasoning_effort="high". - Administrators can also constrain values. Managed
requirements.tomlfiles (/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.
Write a starter config.toml
Section titled “Write a starter config.toml”The file below is a complete user config. Each section after the steps explains one decision in it.
-
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"] -
Install an editor extension that reads the
#:schemadirective (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. -
Validate the file with the installed binary.
--strict-configturns 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 fieldfollowed by the key name. -
Run
codex doctorand 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).
Choose the model and reasoning effort
Section titled “Choose the model and reasoning effort”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
modelunset in your user file, so a new bundled default reaches you on upgrade. Pinmodel = "gpt-6-luna"only in a profile that exists for cost reasons. - Set
model_reasoning_efforttomediumorhighfor daily work. GPT-6.1 Sol and Astra acceptlowthroughmaxplus Codex’sultra(“Maximum reasoning with automatic task delegation”); Luna has noultra. 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_modeand/fastfit 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_windowup 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_policy | Behaviour | Use it for |
|---|---|---|
on-request (default) | Works inside the permissions; asks before crossing them | Interactive work |
untrusted | Removed: 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 |
granular | A table of per-category switches (shell commands, rules, skill scripts, MCP prompts); a category set to false is rejected instead of asked | Teams that need finer control |
never | Never asks; an action outside the permissions fails and the model gets the error | Unattended 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.
Choose the web search mode
Section titled “Choose the web search mode”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* namesexclude = ["AWS_*", "AZURE_*"] # extra patterns to dropset = { NODE_ENV = "test" } # injected into every commandThe 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:
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.
Prepare the shell before you launch Codex
Section titled “Prepare the shell before you launch Codex”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:
source .venv/bin/activatedocker compose up -d postgres redisexport DATABASE_URL="postgresql://localhost:5432/myapp_test"codexA 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 configdefault_permissions = ":workspace"approval_policy = "on-request"web_search = "cached"
[shell_environment_policy]ignore_default_excludes = falseset = { 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.
Switch setups with profiles
Section titled “Switch setups with profiles”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.
model_reasoning_effort = "high"review_model = "gpt-6-astra" # model used by /reviewapproval_policy = "on-request"Run with codex --profile review, then /review. It inherits default_permissions from your user file.
model = "gpt-6-luna"model_reasoning_effort = "low"Run with codex -p quick "Rename getUserData to fetchUserProfile across src/" for mechanical edits whose correctness the test suite proves.
approval_policy = "never"default_permissions = ":workspace"web_search = "disabled"hide_agent_reasoning = trueRun with codex exec --profile unattended --ephemeral "…" for scripted jobs on your own machine. never removes prompts but not the permission boundary. For CI runners, use the patterns in non-interactive Codex, which also cover secrets and untrusted pull requests.
oss_provider = "ollama" # or "lmstudio"Run with codex --profile local --oss. Choosing a local model is covered in gateways and local models.
A profile applies only when you name it on the command line. To see which layers a session loaded, run /debug-config.
Override one setting for one run
Section titled “Override one setting for one run”You do not need to edit a file to change one run:
codex -m gpt-6-sol # model for this sessioncodex -c model_reasoning_effort="high" # any key, as TOMLcodex -c shell_environment_policy.inherit=core # nested keys use dotscodex --enable memories # same as -c features.memories=truecodex --search # live web search for this sessioncodex exec --ephemeral "Run the linter and report." # exec: approval is neverWhich feature flags matter
Section titled “Which feature flags matter”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:
| Flag | Stage | Default | What it does |
|---|---|---|---|
shell_snapshot | stable | on | Snapshots the shell environment so repeated commands start faster |
unified_exec | stable | on | PTY-backed command execution |
goals | stable | on | Persisted goals and automatic continuation (/goal) |
multi_agent | stable | on | Subagents |
memories | stable | off | Memory 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:
-
Codex parses every key. Run
codex doctor --all. Under Configuration, “startup warnings” must be 0; each ignored key is listed by name and layer. -
The right layer wins. In the TUI,
/debug-configshows the config layers and requirement sources, and/statusshows the session’s model, approvals, and sandbox. A non-interactive run prints the same header:model:,approval:,sandbox:. -
The boundary holds. Run a canary through the same sandbox the agent gets. With
default_permissions = ":workspace"in 0.157.1, this printedok, thenRead-only file systemfor/etc/probe:Terminal window codex sandbox -- sh -c 'echo ok > probe.txt && cat probe.txt; echo x > /etc/probe' -
Secrets stay out. Run the
envcanary 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.
When Codex configuration breaks
Section titled “When Codex configuration breaks”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.
Where to go next with Codex configuration
Section titled “Where to go next with Codex configuration”Did this guide help you?
One tap, no sign-in.
What will you do with it?
How did it read?
What got in the way? Pick any that apply
Your role?
Thanks. I read every answer. Michał Jaskólski
Did this guide help?
One tap each. Close whenever you like.
no sign-in