Codex config.toml: location, example and options
Updated 24 October 2026
Codex CLI, the IDE extension and the Codex desktop app all read their settings from config.toml. It decides which model Codex uses, when it stops to ask you, what its commands can touch, which MCP servers it starts and how it notifies you. This guide covers where the file lives, a starter file you can copy, the options worth setting, and the mistakes that make a setting quietly do nothing. Everything here was checked against Codex CLI 0.163.
The short answer
| File | Path | Applies to |
|---|---|---|
| User | ~/.codex/config.toml (Windows: %USERPROFILE%\.codex\config.toml) | You, in every project |
| Project | .codex/config.toml in a repository | That project, once you trust it |
| Profile | ~/.codex/<name>.config.toml | Runs started with --profile <name> |
| System | /etc/codex/config.toml | Every user on a macOS or Linux machine |
| One run | codex -c key=value | That run only |
Run codex doctor after any edit. It parses the file without starting a session and names many keys Codex is ignoring.
1. Codex config.toml location
Codex keeps its config, login, logs and session history in one folder, CODEX_HOME, which defaults to ~/.codex. Your config is config.toml inside it:
- macOS and Linux:
~/.codex/config.toml - Windows:
%USERPROFILE%\.codex\config.toml, shared by the Codex CLI and the Windows desktop app. - WSL: the CLI inside WSL uses the Linux home, so it doesn’t share config or login with Windows. To share them, set
export CODEX_HOME=/mnt/c/Users/<windows-user>/.codexin your shell profile. - Custom location: set
CODEX_HOMEto another folder. The folder must already exist.
If the file isn’t there, create it. Commands that change settings, such as codex mcp add and codex features enable, write to it for you and create it if needed. In the IDE extension, the gear icon opens it from Codex Settings → Open config.toml.
Project config files
A repository can carry its own .codex/config.toml. Codex walks from the project root (the folder with .git) down to the folder you started in and loads every one it finds; the closest file wins. Project files load only when the project is trusted, so a cloned repo can’t change your settings until you say so.
Some keys are refused in a project file, and Codex prints a startup warning instead: model_provider, model_providers, openai_base_url, notify, profile, profiles and otel, among others. Keep those in your user file.
Which file wins
When a key is set in several places, the highest one in this list wins:
- CLI flags and
-coverrides - Project
.codex/config.toml, closest folder first (trusted projects only) - The profile file you picked with
--profile ~/.codex/config.toml- Config managed by your workspace, then
/etc/codex/config.toml - Built-in defaults
On a work machine, an admin’s requirements.toml sits above all of this and can forbid values such as approval_policy = "never".
2. A full config.toml example
A starter file with the settings most people change. Everything is optional; delete what you don’t need. Note the order: plain key = value lines first, then the [tables].
~/.codex/config.toml#:schema https://developers.openai.com/codex/config-schema.json
# Model
model = "gpt-6.1-sol" # pick a model your account can use
model_reasoning_effort = "medium" # low, medium, high, xhigh... depends on the model
# Approvals and sandbox
approval_policy = "on-request" # or "never"
sandbox_mode = "workspace-write" # read-only, workspace-write, danger-full-access
# Search: "cached" (default), "live", or "disabled"
web_search = "cached"
# Run a program when a turn finishes (user config only)
notify = ["python3", "/Users/you/.codex/notify.py"]
[sandbox_workspace_write]
network_access = true # let commands reach the network
[tui]
notifications = ["agent-turn-complete", "approval-requested"]
notification_method = "auto" # auto, osc9 or bel
[features]
hooks = true # on by default; false turns hooks off
[mcp_servers.context7]
command = "npx"
args = ["-y", "@upstash/context7-mcp"]
[projects."/Users/you/code/my-app"]
trust_level = "trusted"
The #:schema line is optional. With the Even Better TOML extension in VS Code or Cursor, it gives you autocomplete and flags unknown keys while you type. Replace the paths with your own; codex doctor reports this file as config.toml parse ok with one MCP server.
3. Codex config.toml options worth knowing
The full reference lists hundreds of keys. These are the ones you’re likely to set:
| Key | What it does |
|---|---|
model | Model for new sessions. Same as --model. |
model_reasoning_effort | low, medium, high, xhigh and higher levels where the model offers them |
approval_policy | When Codex stops to ask: on-request, never or { granular = { … } } |
sandbox_mode | What commands can touch: read-only, workspace-write, danger-full-access |
[sandbox_workspace_write] | network_access = true for the network, writable_roots for extra folders |
approvals_reviewer | user, or auto_review to let a reviewer agent answer prompts |
default_permissions, [permissions.<name>] | Beta permission profiles; an alternative to sandbox_mode, not an addition |
web_search | cached (default), indexed, live or disabled |
notify | A program to run when a turn finishes; it gets one JSON argument |
[tui] notifications | Built-in terminal notifications: true or a list of events, plus notification_method and notification_condition |
[features] | Optional features by name, such as hooks = false or memories = true. codex features list shows them all. |
[mcp_servers.<name>] | MCP servers, with command and args or a url |
model_provider, [model_providers.<id>] | Send requests to a proxy, Azure, a local model or another API |
[projects."<path>"] trust_level | "trusted" or "untrusted"; Codex writes this when you answer the trust prompt |
[shell_environment_policy] | Which environment variables commands Codex runs can see |
cli_auth_credentials_store | Where your login is cached: file, keyring, auto or ephemeral |
[history] persistence | "none" stops Codex saving transcripts to history.jsonl |
file_opener | Which editor opens file citations: vscode, cursor, windsurf, vscode-insiders or none |
For notifications in more detail, see How to get Codex notifications. Hooks live in their own file, ~/.codex/hooks.json, or inline under [hooks]; see the Codex hooks guide.
4. Approval policy, sandbox and permissions
approval_policy and sandbox_mode work as a pair. The sandbox is the fence, and the approval policy decides whether Codex can ask you to let a command past it. The usual setup in a Git repository is workspace-write with on-request, plus network_access = true if your work needs package installs. Two values from older guides no longer work: approval_policy = "untrusted" is retired and can stop Codex from starting, and on-failure is deprecated.
Codex also has beta permission profiles, which describe folders and network rules in more detail than sandbox_mode. This one starts from the built-in :workspace profile and blocks .env files:
~/.codex/config.tomlapproval_policy = "on-request"
default_permissions = "no-env"
[permissions.no-env]
extends = ":workspace"
[permissions.no-env.filesystem.":workspace_roots"]
"**/*.env" = "deny"
Permission profiles don’t mix with the older settings. If sandbox_mode or [sandbox_workspace_write] appears in any loaded config, or you pass --sandbox, Codex uses those and ignores default_permissions. Every value, flag and combination is covered in Codex approval modes and sandbox settings.
5. Profiles are separate files now
A profile is a second config file layered on top of yours. codex --profile review loads ~/.codex/config.toml, then ~/.codex/review.config.toml. Put only the keys that differ, at the top level:
~/.codex/review.config.tomlmodel_reasoning_effort = "high"
approval_policy = "on-request"
sandbox_mode = "read-only"
Since Codex 0.134, --profile no longer reads [profiles.<name>] tables inside config.toml, and a top-level profile = "…" line is no longer supported. Most profile examples online still use the old tables, which is why a copied profile often seems to do nothing. Move each one into its own file. Profile names can use letters, numbers, hyphens and underscores.
6. MCP servers in config.toml
Each server is a [mcp_servers.<name>] table. A local server runs a command; a remote one has a url:
~/.codex/config.toml[mcp_servers.context7]
command = "npx"
args = ["-y", "@upstash/context7-mcp"]
[mcp_servers.figma]
url = "https://mcp.figma.com/mcp"
bearer_token_env_var = "FIGMA_OAUTH_TOKEN"
tool_timeout_sec = 45
codex mcp add context7 -- npx -y @upstash/context7-mcp writes the first table for you. bearer_token_env_var holds the name of a variable, not the token, so the file stays safe to share. Other useful keys: env, enabled = false to switch a server off without deleting it, enabled_tools and disabled_tools, and startup_timeout_sec (default 10). Type /mcp in a session to see what’s running.
7. API keys, login and model_providers
Your OpenAI login doesn’t go in config.toml. Codex keeps it separately:
- ChatGPT account:
codex loginopens a browser. On a remote machine, usecodex login --device-auth. - API key:
printenv OPENAI_API_KEY | codex login --with-api-key. Piping it in keeps the key out of your shell history. - One scripted run:
CODEX_API_KEY=… codex exec "…". It works withcodex execandcodex review. In CI, set it only for that one command, not for the whole job, so build scripts and tests can’t read it.
The login is cached in ~/.codex/auth.json or your OS credential store; cli_auth_credentials_store picks which. Treat auth.json like a password. To see which login is active without printing it, run codex login status.
For anything other than OpenAI’s own endpoint, define a provider and point model_provider at it. env_key names the environment variable that holds the key:
~/.codex/config.tomlmodel = "gpt-6.1-sol"
model_provider = "proxy"
[model_providers.proxy]
name = "Company LLM proxy"
base_url = "https://llm-proxy.example.com/v1"
env_key = "PROXY_API_KEY"
If PROXY_API_KEY isn’t set, codex doctor says so: “active model provider auth env var is missing”. A few rules:
- You can’t redefine the built-in IDs
openai,ollamaandlmstudio. To send OpenAI traffic through a proxy, setopenai_base_urlinstead. requires_openai_auth = truemakes the provider use your normal Codex login, and Codex then ignoresenv_key.- With neither set, Codex assumes the provider needs no key, which suits a local model.
wire_apionly accepts"responses", the default.- Provider keys only work in your user file or a profile file. A project
.codex/config.tomlcan’t change them.
8. One-off overrides with -c
-c key=value (or --config) changes any key for one run without touching the file. Use dots for keys inside tables:
Terminalcodex -c model_reasoning_effort=high
codex -c sandbox_workspace_write.network_access=true
codex -c 'tui.notifications=["approval-requested"]'
codex -c mcp_servers.context7.enabled=false
The value is parsed as TOML, not JSON. If it doesn’t parse, Codex uses the raw text as a string, which is why -c model_reasoning_effort=high works without quotes. Lists and anything with spaces need single quotes around the whole argument so your shell passes it through intact. --enable <feature> and --disable <feature> are shortcuts for -c features.<name>=true and false.
9. Check your file with codex doctor
codex doctor loads your config the way a session would, without starting one, and reports on config, login, MCP servers and the sandbox. A good file shows:
[ok] config loaded
config.toml parse ok
A key in the wrong place gets named:
startup warning Codex is ignoring 1 unrecognized configuration setting. Check for typos or deprecated settings.
user (~/.codex/config.toml): `sandbox_workspace_write.approval_policy` is ignored.
And a file that doesn’t parse shows the line and column, while any other command stops with the full error:
Error: failed to load bootstrap configuration
Caused by:
0: ~/.codex/config.toml:1:9: string values must be quoted, expected literal string
codex doctor --summary prints just the check rows, and --json gives a redacted report you can share. Inside a session, /debug-config shows which config layers loaded and /status shows the model and approval policy in effect. Start Codex with --strict-config to make unknown keys an error instead of a warning.
10. Common mistakes
A top-level key below a table header. This is the classic one. In TOML, every line after [tui] belongs to tui until the next header, so this model is tui.model:
~/.codex/config.toml (wrong)[tui]
notifications = true
model = "gpt-6.1-sol" # read as tui.model, not model
Move model, approval_policy, sandbox_mode, notify and the other top-level keys above the first [header]. Don’t rely on codex doctor to catch this one: it names a stray key under [sandbox_workspace_write], but in our test a model line under [tui] was dropped without any warning.
The other usual suspects:
- Unquoted strings.
model = gpt-6.1-solstops Codex loading at all. Strings need quotes; onlytrue,falseand numbers don’t. - Windows paths in double quotes. In
"C:\Users\you\notify.ps1",\Ustarts an escape sequence and the file fails to parse. Use single quotes,'C:\Users\you\notify.ps1', or forward slashes. - The same key or table twice. Pasting a second
[tui]block or a secondapproval_policyline is a parse error, not an override. Merge them. - Old
[profiles.<name>]tables. Ignored since 0.134. Use<name>.config.tomlfiles. approval_policy = "untrusted". Retired. For the strict behavior, settrust_level = "untrusted"on the project and leaveapproval_policyunset.- Provider or
notifysettings in a project file. Codex ignores them there and warns at startup. They belong in~/.codex/config.toml. - An untrusted project. Its
.codex/config.toml, hooks and rules are all skipped. Check[projects]in your user file. - Editing the wrong home. If
CODEX_HOMEis set, or you’re in WSL,~/.codexmay not be the folder Codex reads.codex doctorprints theconfig.tomlpath it used. - Secrets in the file. Use
env_keyandbearer_token_env_varsoconfig.tomlholds variable names, not keys.
Answer Codex approvals from your browser
With approval_policy = "on-request", Codex waits in the terminal until you answer, and [tui] notifications only tells you to go back to it. Agent Pets turns each Codex session into a pet that walks along the bottom of every Chrome page:
- When Codex asks for approval, its pet bounces. Click it and answer Allow or Deny from the page you’re on.
- A capsule over each pet says Thinking, Your Turn or Done, and you can read Codex’s latest answer and send the next message from any tab. Claude Code, OpenCode and omp sessions get pets too.
- In another app, a desktop notification names the pet that needs you, with Allow and Deny on it.
npx getagentpets init adds hooks to ~/.codex/hooks.json; open Codex once and trust them with /hooks. It doesn’t edit your config.toml, so just make sure you haven’t set hooks = false under [features]. The terminal prompt keeps working, and everything runs on your computer.
Get Agent Pets — was $25, now $6Get Agent Pets — $25
Questions
Where is the Codex config.toml file?
Your user config is ~/.codex/config.toml on macOS and Linux and %USERPROFILE%\.codex\config.toml on Windows. If CODEX_HOME is set, Codex reads config.toml from that folder instead. A repository can add .codex/config.toml, which loads only when you trust the project.
How do I set an API key for Codex?
Not in config.toml. Run printenv OPENAI_API_KEY | codex login --with-api-key once, and Codex stores the credential in ~/.codex/auth.json or your OS credential store. For a single codex exec run, set CODEX_API_KEY inline. A custom provider names its variable with env_key.
Why is my Codex config.toml setting ignored?
Usually the key sits below a [table] header, so TOML reads it as part of that table. Move top-level keys like model and approval_policy above the first header. Also check for a project file or -c flag that overrides it, an untrusted project, or an old [profiles] table. codex doctor names many ignored keys.
Where did profiles go in Codex config.toml?
Since Codex 0.134, --profile reads a separate file, ~/.codex/<name>.config.toml, instead of a [profiles.<name>] table. Move each table’s keys to the top level of its own file and delete the old table and any profile = line.
How do I change one Codex setting for a single run?
Use -c key=value, for example codex -c model_reasoning_effort=high or codex -c sandbox_workspace_write.network_access=true. The value is parsed as TOML; if it doesn’t parse, Codex uses it as a plain string.
Sources: Codex documentation on config basics, advanced configuration, the configuration reference, environment variables, authentication, non-interactive mode, permissions, MCP, the CLI reference, slash commands and the Windows app; codex --help and codex doctor for Codex CLI 0.163.0, run against each example file on this page.