Skip to content

配置系統

源码版本rust-v0.145.0

codex 的配置 (config) 不是單檔案載入,而是多層疊加:config.toml 來自 system / user / project / cloud bundle / session flags 多個來源,按 precedence 合併成 effective config,再疊加 ConfigRequirements 做約束校驗。config crate 負責層疊與合併,codex-home 提供 CODEX_HOME 解析與全域 AGENTS.md 載入,core/src/config/mod.rs 把合併結果裝進 Config 供 Agent 主迴圈使用,core/src/config_lock.rs 用 lockfile 保證可重現執行。cli/src/login.rs 寫 auth.json,登入態也是配置層的一部分。

職責

  1. 定位 codex home:find_codex_homeCODEX_HOME,未設定則回退 ~/.codex(codex-rs/core/src/config/mod.rs:4440-4442)。
  2. 多層載入:load_config_layers_state 順序裝 system / managed / cloud bundle / user / project / session flags 各層,產出 ConfigLayerStack(codex-rs/config/src/loader/mod.rs:116-168)。
  3. 合併產出 effective config:ConfigLayerStack::effective_config 按 precedence 從低到高 merge TOML(codex-rs/config/src/state.rs:483-492)。
  4. 裝配執行時 Config:ConfigBuilder 把 codex_home、cli_overrides、harness_overrides、cloud bundle 拼到一起 build().await(codex-rs/core/src/config/mod.rs:1258-1297)。
  5. 寫入登入態:login_with_chatgpt / run_login_with_api_key 跑完登入流程,把憑證落到 auth.json(codex-rs/cli/src/login.rs:137-165)。

設計動機

單檔案 config.toml 簡單,但企業部署要求多來源疊加:MDM 推下來的強制策略不能被使用者改、專案 .codex/config.toml 要覆蓋使用者全域、CLI flag 又要壓過專案配置。codex 把每層抽象成 ConfigLayerEntry,用 ConfigLayerSource::precedence 回傳數字決定合併順序——Session flags(30)壓過 Project(25)壓過 User(20)壓過 System(10)壓過 MDM(0)。新增來源只需加 enum variant + 回傳數字,不用改合併邏輯。cloud bundle 是後加的層,從 ChatGPT 後端拉 enterprise-managed config 和 requirements,在 load_config_layers_state 裡透過 CloudConfigBundleLayers::from_bundle 轉成普通 layer 塞進 stack,跟本地 TOML 走同一條合併路徑。config_lock.rs 為可重現性加:把合併出來的 ConfigToml + codex version 序列化成 ConfigLockfileToml,重放時 validate_config_lock_replay 對比 expected vs actual,版本或欄位不一致就報錯,避免同一 prompt 在不同機器上跑出不同結果。

關鍵檔案

codex-rs/config/src/config_layer_source.rs:6-49ConfigLayerSource enum 與 precedence(),定義 8 種來源與合併順序。codex-rs/config/src/loader/mod.rs:116-168load_config_layers_state,把 system / managed / cloud bundle / user / project 各層按序裝入 stack。codex-rs/config/src/state.rs:483-492effective_config,按 precedence 從低到高 merge_toml_valuescodex-rs/core/src/config/mod.rs:614-673Config 結構,執行時拿到的「最終配置」物件,含 model_provider、permissions、enforce_residency 等。codex-rs/core/src/config/mod.rs:1258-1297ConfigBuilder,裝配 codex_home、cli_overrides、harness_overrides、cloud bundle 後 build().awaitcodex-rs/core/src/config/mod.rs:1721-1728Config::load_with_cli_overrides,最常用入口。codex-rs/core/src/config_lock.rs:38-74config_lockfilevalidate_config_lock_replay,鎖檔案生成與重放校驗。codex-rs/codex-home/src/instructions/mod.rs:14-68CodexHomeUserInstructionsProvider,從 ~/.codex/AGENTS.md 載入全域使用者指令。

ConfigLayerSource 把 8 種來源壓成 enum,precedence 數字決定合併順序:

rust
// config/src/config_layer_source.rs:6-48 — 来源 + 优先级
pub enum ConfigLayerSource {
    Mdm { domain: String, key: String },            // 0
    System { file: AbsolutePathBuf },               // 10
    EnterpriseManaged { id: String, name: String }, // 15
    User { file: AbsolutePathBuf, profile: Option<String> }, // 20 或 21
    Project { dot_codex_folder: AbsolutePathBuf },  // 25
    SessionFlags,                                     // 30
    LegacyManagedConfigTomlFromFile { .. },          // 40
    LegacyManagedConfigTomlFromMdm,                  // 50
}

impl ConfigLayerSource {
    pub fn precedence(&self) -> i16 {
        match self {
            ConfigLayerSource::Mdm { .. } => 0,
            ConfigLayerSource::System { .. } => 10,
            ConfigLayerSource::SessionFlags => 30,
            // ...
        }
    }
}

effective_config 按 precedence 從低到高逐層 merge,後寫的覆蓋先寫的:

rust
// config/src/state.rs:483-492 — 合并层叠
pub fn effective_config(&self) -> TomlValue {
    let mut merged = TomlValue::Table(toml::map::Map::new());
    for layer in self.get_layers(
        ConfigLayerStackOrdering::LowestPrecedenceFirst,
        /*include_disabled*/ false,
    ) {
        merge_toml_values(&mut merged, &layer.config);
    }
    merged
}

config_lock 把當時合併結果鎖住,下次重放時對比 TOML 欄位差異:

rust
// core/src/config_lock.rs:46-74 — 锁文件重放校验
pub(crate) fn validate_config_lock_replay(
    expected_lock: &ConfigLockfileToml,
    actual_lock: &ConfigLockfileToml,
    options: ConfigLockReplayOptions,
) -> io::Result<()> {
    validate_config_lock_metadata_shape(expected_lock)?;
    validate_config_lock_metadata_shape(actual_lock)?;
    if !options.allow_codex_version_mismatch
        && expected_lock.codex_version != actual_lock.codex_version
    {
        return Err(config_lock_error(format!(
            "config lock Codex version mismatch: lock was generated by {}, current version is {}; ...",
            expected_lock.codex_version, actual_lock.codex_version
        )));
    }
    // ...继续 TOML 字段对比,不一致时用 similar 算 diff 报错
}

資料流

邊界與失敗

小結

配置系統把多來源(system / user / project / cloud / session flags)按 precedence() 數字合併成 Config,cloud bundle 跟本地 TOML 走同一條 merge_toml_values 路徑,登入態寫在 auth.jsonModel ProviderAuthManager 讀取。ConfigLockfileToml 把合併結果鎖住以保證重放一致性。雲端任務用到的 enterprise 策略由 Cloud Tasks 路徑裡的 cloud-config 服務定期刷新,落到本地 cache 後再被這裡讀進 effective config。