Atlas
TechnicalHow-to

Codex config.toml: Profiles, Project Config, Precedence

How Codex config.toml layers work: user, profile, project and CLI settings, which one wins, what projects cannot set, and a safe setup for a team repo.

The short version

  • Codex reads settings from several layers. From highest to lowest: CLI flags, project files, the selected profile, your user file, cloud-managed defaults, system config, built-in defaults.
  • A profile is its own file, ~/.codex/<name>.config.toml, with top-level keys. From Codex 0.134.0 the old [profiles.name] table and the profile = selector are no longer supported.
  • A repo can ship .codex/config.toml, but Codex loads it only when the project is trusted, and it ignores provider, notification and telemetry keys set there.
  • Use -c or --config for one-off overrides, and keep shared defaults in config.toml so profiles hold only what differs.
On this page
  1. The short version
  2. Where does Codex read its configuration from?
  3. Which setting wins? The precedence order
  4. The four keys most teams set first
  5. How do Codex profiles work now?
  6. How do I set up a project config for a team repo?
  7. How do I override one setting for a single run?
  8. A layout that works
  9. Conclusion
  10. Questions people ask

Codex reads its settings from more than one place, and the place that wins is not always the one you edited last. The short rule: command-line flags beat project files, project files beat a profile you select, a profile beats your personal ~/.codex/config.toml, and everything else is a default. This guide shows how to set up each layer so a team repo behaves the same for everyone and a one-off run does not need a file edit.

Everything below comes from OpenAI's Codex configuration docs. Where the docs do not say something, this article does not either.

Where does Codex read its configuration from?

These are the layers you can meet:

  • User config: ~/.codex/config.toml. Your personal defaults.
  • Project config: a .codex/config.toml inside a repo or subfolder. It scopes settings to that project.
  • Profile files: ~/.codex/<profile-name>.config.toml, picked with --profile.
  • System config: /etc/codex/config.toml on Unix.
  • Cloud-managed defaults: a config.toml delivered for the signed-in workspace, when one exists.

Managed-device and workspace requirements exist as well. The configuration docs only point to a separate managed-configuration page for them, so check that page if your organization enforces settings.

Which setting wins? The precedence order

From highest to lowest:

  1. CLI flags and --config overrides
  2. Project config files, from the project root down to the current directory (closest wins; trusted projects only)
  3. The profile file chosen with --profile
  4. User config (~/.codex/config.toml)
  5. Cloud-managed config.toml defaults, when delivered for the signed-in workspace
  6. System config (/etc/codex/config.toml on Unix)
  7. Built-in defaults

Two consequences are easy to miss. First, a project file overrides a profile. If your profile sets model and the repo's .codex/config.toml also sets it, the repo wins. Second, there is one documented exception: for model_catalog_json, when both a profile and the project set it, Codex uses the profile value.

The four keys most teams set first

The docs show these as the basic block:

toml
model = "gpt-6.1-sol"
approval_policy = "on-request"
sandbox_mode = "workspace-write"
model_reasoning_effort = "medium"

What they do, and what values the reference page allows:

  • model sets the default model. The docs say to pick one available to your signed-in account or workspace, and use gpt-6.1-sol only as an example. Check which models you actually have.
  • approval_policy controls when Codex pauses to ask before running commands. Allowed values are on-request, never, or a granular table. The reference says untrusted is no longer supported and on-failure is deprecated; use on-request for interactive runs or never for non-interactive ones. Old configs that use the retired values need updating.
  • sandbox_mode is read-only, workspace-write or danger-full-access. It sets filesystem and network access while commands run.
  • model_reasoning_effort sets reasoning effort when the model supports it. The docs list low, medium, high, xhigh, max and ultra as examples and say the available levels depend on the model and client. Do not assume every model accepts every level.

How do Codex profiles work now?

A profile is a separate file. --profile deep-review loads ~/.codex/config.toml first, then overlays ~/.codex/deep-review.config.toml on top.

Rules from the docs:

  • Names can use letters, numbers, hyphens and underscores.
  • Use top-level keys in the profile file. Do not nest them under [profiles.deep-review].
  • Keep shared defaults in config.toml and use profiles only for values that differ.

An example profile for careful reviews:

toml
# ~/.codex/deep-review.config.toml
model = "gpt-6.1-sol"
model_reasoning_effort = "medium"
approval_policy = "on-request"
model_catalog_json = "/Users/me/.codex/model-catalogs/deep-review.json"

Use it with the interactive command:

sh
codex --profile deep-review

The profile mechanism is the same for any Codex run, so it gives you a simple way to keep different defaults for different jobs, such as careful review versus quick edits, without separate scripts.

Migrating old profiles (Codex 0.134.0 and later)

This is the change most likely to bite. From 0.134.0, --profile no longer reads [profiles.profile-name] tables from config.toml, and the top-level profile = "profile-name" selector is no longer supported. To migrate:

  1. Create ~/.codex/profile-name.config.toml.
  2. Move the keys from the old table into it as top-level keys.
  3. Remove the old table and the selector from config.toml.

If a profile seems to have no effect after an upgrade, check for the old format first. The docs do not describe what Codex prints in that case, so verify by running with the profile and checking behavior.

How do I set up a project config for a team repo?

Commit a .codex/config.toml at the repo root. Codex walks from the project root down to your working directory and loads each .codex/config.toml it finds. If several files define the same key, the one closest to your working directory wins. That lets a monorepo set a default at the root and a stricter one inside a package.

A conservative starting file:

toml
# .codex/config.toml (committed)
sandbox_mode = "workspace-write"
approval_policy = "on-request"

Details that matter:

  • Trust gate. Project layers load only when the project is trusted. In an untrusted project Codex skips project-scoped layers, including project-local config, hooks and rules. User and system config still load.
  • Relative paths. Relative paths in a project file resolve against the .codex/ folder that contains the config.toml, so committed paths work on every machine.
  • Project root. A directory containing .git is the root by default. Change the markers with project_root_markers. An empty list treats the current working directory as the root.

What a project file cannot set

A repo you cloned should not be able to redirect your traffic or turn on telemetry. So Codex ignores these keys in project files and prints a startup warning: openai_base_url, chatgpt_base_url, apps_mcp_product_sku, model_provider, model_providers, notify, profile, profiles, experimental_realtime_ws_base_url and otel.

Put these in ~/.codex/config.toml instead, and choose profiles with --profile. This is a useful property when you open unfamiliar repos. It is still worth reading the .codex/ folder, including its hooks and rules, before you trust a repo, because the trust decision is what turns those project layers on.

How do I override one setting for a single run?

Use -c or --config. Prefer a dedicated flag such as --model when one exists.

sh
codex --model gpt-6.1-sol
codex --config model='"gpt-6.1-sol"'
codex --config sandbox_workspace_write.network_access=true
codex --config 'shell_environment_policy.include_only=["PATH","HOME"]'

Notes from the docs:

  • Values are parsed as TOML. If parsing fails, Codex treats the value as a string.
  • Nested keys use dot notation, for example mcp_servers.context7.enabled=false.
  • Quote anything with spaces or special characters so the shell does not split it.
  • sandbox_workspace_write.network_access is a boolean. Setting it to true allows outbound network access inside the workspace-write sandbox, so it is safer to turn it on per run than in a committed file.
  • include_only is a legacy array. It still works, but you cannot combine it with the newer [shell_environment_policy.filters] table in the same layer.

Because CLI overrides sit at the top, they are the right tool for a script that must force a setting no matter what the repo says.

A layout that works

  • ~/.codex/config.toml: your model, effort and personal defaults, plus provider, notification and telemetry settings.
  • ~/.codex/deep-review.config.toml and similar: only the keys that differ.
  • .codex/config.toml in the repo: sandbox and approval defaults the whole team shares.
  • --config in scripts: one-off, visible overrides.

Conclusion

Think of Codex configuration as a stack: CLI flags on top, then the repo, then your profile, then your user file. Keep shared defaults in the base file, put only differences in profile files, commit conservative project settings, and use --config for exceptions. If you upgraded recently, migrate any [profiles.*] tables first, since Codex 0.134.0 and later no longer read them.

Questions people ask

Where is the Codex config.toml file?

Your personal file is ~/.codex/config.toml. A repo can add a .codex/config.toml, which Codex loads only if you trust the project. On Unix there is also a system file at /etc/codex/config.toml.

Does a project config override a Codex profile?

Yes. Project config files rank above a profile chosen with --profile, and CLI flags rank above both. The docs list one exception: if both a profile and the project set model_catalog_json, the profile value is used.

Why does my Codex profile stop working after an update?

From Codex 0.134.0, --profile no longer reads [profiles.name] tables from config.toml, and the top-level profile = selector is no longer supported. Move the settings into ~/.codex/name.config.toml as top-level keys and remove the old table.

How do I change one Codex setting for a single run?

Pass --config key=value (or -c). Values are parsed as TOML, nested keys use dots, and a dedicated flag like --model is preferred when it exists.

Can a repo change my Codex model provider or telemetry?

No. Codex ignores keys such as model_provider, model_providers, notify and otel in project files and prints a startup warning. Set them in your own ~/.codex/config.toml.

Sources

  1. Codex config basics
  2. Codex advanced configuration: profiles, project config, overrides
  3. Codex configuration reference

Researched and drafted with Claude, then checked against the sources above. Atlas is an independent product, not affiliated with Anthropic or OpenAI. Claude and Claude Code are trademarks of Anthropic; Codex is a product of OpenAI.