# How the Codex CLI Configuration System Works: Complete config.toml Guide

> Explore the Codex CLI configuration system and understand how config.toml works. Learn about layered sources, strict precedence, and atomic edits.

- Repository: [OpenAI/codex](https://github.com/openai/codex)
- Tags: internals
- Published: 2026-03-06

---

**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`](https://github.com/openai/codex/blob/main/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`](https://github.com/openai/codex/blob/main/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`](https://github.com/openai/codex/blob/main//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`](https://github.com/openai/codex/blob/main/./.codex/config.toml) (disabled for untrusted directories)
7. **Repo** – Git repository root's [`.codex/config.toml`](https://github.com/openai/codex/blob/main/.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.

```rust
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`](https://github.com/openai/codex/blob/main/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`](https://github.com/openai/codex/blob/main/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:

```rust
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`](https://github.com/openai/codex/blob/main/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`](https://github.com/openai/codex/blob/main/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`](https://github.com/openai/codex/blob/main/mod.rs))
- `set_path_value()` – Generic path-based value updates
- `apply_blocking()` – Persist changes atomically

```rust
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:

```rust
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:

```rust
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:

```rust
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`](https://github.com/openai/codex/blob/main/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`](https://github.com/openai/codex/blob/main/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`](https://github.com/openai/codex/blob/main/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`](https://github.com/openai/codex/blob/main//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`](https://github.com/openai/codex/blob/main/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`](https://github.com/openai/codex/blob/main/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.