How the Codex CLI Configuration System Works: Complete config.toml Guide
The Codex CLI builds a deterministic configuration stack from eight layered sources—from cloud policies to CLI flags—merges them in strict precedence order, deserializes the result into a ConfigToml struct, and persists user edits atomically via the ConfigEditsBuilder API.
The Codex CLI configuration system manages settings through a hierarchical config.toml file located in the user's Codex home directory. According to the openai/codex source code, the system implements a sophisticated layering mechanism that allows enterprise administrators, system operators, and end users to define defaults while respecting security boundaries and runtime overrides.
Configuration Layers and Precedence
The loading logic resides in codex-rs/core/src/config_loader/mod.rs. When the CLI starts, it invokes load_config_layers_state to construct a configuration stack from multiple sources, merged in the following immutable order:
- Cloud – Managed cloud requirements via
cloud_requirements.get() - Admin – macOS managed profiles loaded via
macos::load_managed_admin_requirements_toml - System –
/etc/codex/config.toml(Unix) or%ProgramData%\OpenAI\Codex\config.toml(Windows), loaded viasystem_config_toml_file() - User –
$CODEX_HOME/config.toml(the primaryCONFIG_TOML_FILEconstant) - CWD –
${PWD}/config.toml(disabled for untrusted directories) - Tree – Ancestor directories'
./.codex/config.toml(disabled for untrusted directories) - Repo – Git repository root's
.codex/config.toml(detected viagit rev-parse, disabled for untrusted directories) - Runtime – CLI flags and UI model selectors converted via
build_cli_overrides_layer
Earlier layers in this stack cannot be overridden by later ones. The system selectively enables the cwd, tree, and repo layers only when operating in trusted directories.
How Configuration Layers Are Merged
All layers merge into a single toml::Value using the merge_toml_values function re-exported from codex_config. The algorithm applies later layers on top of previously merged values without overwriting fields already set by higher-precedence layers.
let mut merged = TomlValue::Table(toml::map::Map::new());
for layer in &layers {
merge_toml_values(&mut merged, &layer.config);
}
if let Some(cli) = cli_overrides_layer {
merge_toml_values(&mut merged, cli);
}
This merge loop appears in load_config_layers_state (lines ~93–100), ensuring that your local config.toml respects system-wide policies while allowing runtime CLI flags to take final precedence.
The ConfigToml Struct and Deserialization
After merging, the system deserializes the final toml::Value into the ConfigToml struct defined in codex-rs/core/src/config/mod.rs (lines 1010–1060). This struct contains all configurable fields, including:
- Model selection:
model,model_provider,model_context_window - Sandbox configuration:
sandbox_mode,sandbox_workspace_write - Authentication stores, MCP server lists, and permission flags
The deserialization process applies default values first, then overlays the merged configuration:
let cfg: ConfigToml = toml::Value::try_from(ConfigToml::default())
.and_then(|default| merge_toml_values(&mut merged, &default))
.and_then(|merged| merged.try_into())
.map_err(|e| ConfigError::...)?;
Runtime Editing with ConfigEditsBuilder
The CLI and TUI modify persisted configuration through the ConfigEditsBuilder API located in codex-rs/core/src/config/edit.rs. This builder pattern enables type-safe, atomic modifications to $CODEX_HOME/config.toml.
Atomic Writes and Safety
The builder guarantees atomicity by writing to a temporary file before renaming it, ensuring config.toml never exists in a partially-written state. Key methods include:
set_profile()– Switch configuration profilesset_default_oss_provider()– Update the default OSS provider (lines 72–94 inmod.rs)set_path_value()– Generic path-based value updatesapply_blocking()– Persist changes atomically
use codex_core::config::edit::ConfigEditsBuilder;
let result = ConfigEditsBuilder::new(&codex_home)
.set_profile("work")
.apply_blocking()?;
Practical Code Examples
The following patterns demonstrate how to interact with the Codex CLI configuration system programmatically.
Loading the Effective Configuration
To load the fully resolved configuration respecting all layers:
use codex_core::config_loader::load_config_layers_state;
use codex_core::config::ConfigToml;
use std::path::Path;
async fn effective_config(codex_home: &Path) -> anyhow::Result<ConfigToml> {
let layers = load_config_layers_state(
codex_home,
Some(AbsolutePathBuf::from(std::env::current_dir()?)),
&[], // no CLI overrides
LoaderOverrides::default(),
CloudRequirementsLoader::default(),
).await?;
let merged = layers.merge()?;
let cfg: ConfigToml = merged.try_into()?;
Ok(cfg)
}
Modifying Settings Programmatically
Update the default model provider from the TUI or a subcommand:
use codex_core::config::edit::ConfigEditsBuilder;
fn set_model_provider(codex_home: &Path, provider: &str) -> std::io::Result<()> {
ConfigEditsBuilder::new(codex_home)?
.set_path_value(&["model_provider"], provider)?
.apply_blocking()
}
Enable sandbox workspace-write mode:
use codex_core::config::edit::ConfigEditsBuilder;
use codex_protocol::config_types::SandboxWorkspaceWrite;
fn enable_workspace_write(codex_home: &Path) -> std::io::Result<()> {
let mode = SandboxWorkspaceWrite::default();
ConfigEditsBuilder::new(codex_home)?
.set_path_value(&["sandbox_workspace_write"], &mode)?
.apply_blocking()
}
Summary
- The Codex CLI configuration system uses a strict eight-layer stack (cloud → admin → system → user → cwd → tree → repo → runtime) defined in
codex-rs/core/src/config_loader/mod.rs. - Configuration values merge via
merge_toml_values, with earlier layers taking precedence over later ones. - The final configuration deserializes into the
ConfigTomlstruct incodex-rs/core/src/config/mod.rs, which supports model selection, sandbox settings, and authentication stores. - Runtime modifications occur through
ConfigEditsBuilderincodex-rs/core/src/config/edit.rs, which provides atomic writes viaapply_blocking(). - Untrusted directory protections disable the cwd, tree, and repo layers automatically.
Frequently Asked Questions
What is the order of precedence for Codex CLI configuration files?
The Codex CLI configuration system loads settings in the following immutable order: cloud requirements, admin profiles (macOS only), system-level config (/etc/codex/config.toml), user-level config ($CODEX_HOME/config.toml), current working directory, ancestor tree directories, Git repository root, and finally runtime CLI flags. Settings from earlier sources override later ones.
How does Codex CLI handle configuration edits safely?
The system uses the ConfigEditsBuilder API to modify config.toml atomically. When you call apply_blocking(), the builder writes changes to a temporary file first, then renames it to replace the original. This guarantees that the configuration file never exists in a corrupted or partially-written state, even if the process crashes mid-write.
Can I override system-wide Codex settings as a user?
Yes, but only for settings not locked by higher-priority layers. The user layer ($CODEX_HOME/config.toml) can override system defaults, but cannot override admin or cloud layers. Runtime CLI flags provide the final override mechanism for individual command invocations, processed through build_cli_overrides_layer in the configuration loader.
Where is the ConfigToml struct defined and what fields does it contain?
The ConfigToml struct is defined in codex-rs/core/src/config/mod.rs (lines 1010–1060). It contains fields for model selection, model_provider, sandbox_mode, sandbox_workspace_write, authentication stores, MCP server configurations, and various permission flags. This struct represents the fully merged and validated configuration state used throughout the application.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →