Add explicit config scopes with a gitignored project-local override layer
What variant of Codex are you using?
CLI / IDE / app configuration system
What feature would you like to see?
Please add an explicit gitignored project-local override layer for Codex configuration, for example:
~/.codex/config.toml # user/global defaults, safe to manage with dotfiles
<repo>/.codex/config.toml # shared project defaults, safe to commit
<repo>/.codex/config.local.toml # local user/machine override, gitignored
~/.codex/state.toml # Codex-owned mutable local state, separate concern
The immediate request is the third layer: a first-class .codex/config.local.toml or equivalent that overrides the committed project .codex/config.toml without requiring -c flags, profiles, wrapper scripts, or dirtying the repository.
Suggested precedence, fitting the current documented Codex model:
- CLI flags and
--configoverrides - Active profile values
- Local project override:
.codex/config.local.toml(trusted projects only, gitignored) - Shared project config:
.codex/config.tomlfrom project/root/current-directory layers - User config:
~/.codex/config.toml - System config
- Built-in defaults
This local layer should also be visible in /debug-config and app-server config/read layer/origin diagnostics so users can understand why a value won.
Why this matters
Codex currently documents two persistent user-controlled layers for local work:
- user/global config in
~/.codex/config.toml - shared project overrides in
.codex/config.toml
That works for simple cases, but it does not scale well for people and teams who use Codex across multiple projects, purposes, and machines:
- A repo can commit useful defaults in
.codex/config.toml, but an individual cannot make a durable per-machine/per-user override for that repo without modifying the committed file or passing-cevery time. - User config is lower precedence than project config, so it cannot override a committed project MCP/server/sandbox/model choice for one developer.
- Profiles are useful, but they are not a project-local file and do not replace a gitignored per-repo override for local ports, local paths, experimental MCP servers, disabled project MCP servers, or machine-specific provider settings.
- Dotfiles users want
~/.codex/config.tomlto remain stable user-authored configuration, while Codex also needs places for shared repo defaults and local mutable/private data.
This becomes especially important when a user wants several Codex setups: different computers, different usernames/paths, different MCP availability, different local services, or different project workflows. The desired model is not one giant file that every Codex surface writes into; it is a small config-scope hierarchy with clear ownership.
Claude Code precedent
Claude Code has a useful precedent here:
~/.claude/settings.jsonfor user settings.claude/settings.jsonfor project settings shared through git.claude/settings.local.jsonfor local project-specific settings, not shared, and gitignored when created- separate handling for app state / OAuth / per-project state in
~/.claude.json - MCP scopes with local / project / user behavior, including project-shared
.mcp.json
The important part is the scope model, not the exact filenames. Claude Code's local scope works because a repo can provide team defaults while each developer can keep private machine-specific overrides out of git. That is the missing Codex layer.
Concrete example
A repository may want to commit a shared MCP server:
# <repo>/.codex/config.toml
[mcp_servers.project-tools]
command = "project-tools-mcp"
args = ["--port", "3000"]
required = true
One developer may need a local override:
# <repo>/.codex/config.local.toml
[mcp_servers.project-tools]
enabled = false
or:
# <repo>/.codex/config.local.toml
[mcp_servers.project-tools]
command = "project-tools-mcp"
args = ["--port", "4317"]
required = false
Today, that developer either changes the committed .codex/config.toml, uses a launch wrapper / -c every time, or changes a global profile that is not scoped to the repo.
Related issues
This request is related to, but distinct from, the existing config-state pollution issues:
- #14601 and #11061 cover Codex-owned mutable state being written into
~/.codex/config.tomland making dotfile/multi-machine setups hard. - #15433 was a duplicate-ish trust-state issue around separating project trust from global config.
- #15970 is the closest previous request. It asked for
config.local.tomlto override project-shared config, especially MCP config, but was closed after the discussion appears to have focused on project.codex/config.tomloverriding user config. The clarified need there was the reverse: override an existing project-level config without-c. - #13056 and #23487 cover project-scoped MCP configuration and
codex mcp add --scoped; a local override layer would give those workflows a complete set of write targets: user, shared project, and local project. - #18334 is adjacent, but custom config search locations are not the same as a standard gitignored local override file.
Proposed acceptance criteria
- Codex reads
.codex/config.local.tomlor an equivalent local project file from trusted projects. - The local project file overrides shared
.codex/config.tomlfor the same project/current-directory layer. - Codex ensures the local file is gitignored when Codex creates it.
/debug-configand app-server config diagnostics show the local layer and per-key origins.- The same project-config denylist/safety checks apply to this local layer, or a stricter denylist is documented.
- Future CLI writes can target this scope, for example
codex mcp add --scope local ..., while--scope projecttargets shared.codex/config.tomland the default/global target remains~/.codex/config.toml.
This would make Codex's configuration system much more scalable: shared team defaults, private local project overrides, stable dotfile-managed user defaults, and Codex-owned mutable state can each live in the place users expect.