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:

  1. Cloud – Managed cloud requirements via cloud_requirements.get()
  2. Admin – macOS managed profiles loaded via macos::load_managed_admin_requirements_toml
  3. System/etc/codex/config.toml (Unix) or %ProgramData%\OpenAI\Codex\config.toml (Windows), loaded via system_config_toml_file()
  4. User$CODEX_HOME/config.toml (the primary CONFIG_TOML_FILE constant)
  5. CWD${PWD}/config.toml (disabled for untrusted directories)
  6. Tree – Ancestor directories' ./.codex/config.toml (disabled for untrusted directories)
  7. Repo – Git repository root's .codex/config.toml (detected via git rev-parse, disabled for untrusted directories)
  8. 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 profiles
  • set_default_oss_provider() – Update the default OSS provider (lines 72–94 in mod.rs)
  • set_path_value() – Generic path-based value updates
  • apply_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 ConfigToml struct in codex-rs/core/src/config/mod.rs, which supports model selection, sandbox settings, and authentication stores.
  • Runtime modifications occur through ConfigEditsBuilder in codex-rs/core/src/config/edit.rs, which provides atomic writes via apply_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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →