Skip to content

Système de configuration

源码版本rust-v0.145.0

La configuration (config) de codex n'est pas un fichier unique : c'est un empilement multi-couche. config.toml provient de system / user / project / cloud bundle / session flags — multiples sources combinées par precedence en effective config, puis soumises à ConfigRequirements pour validation. Le crate config gère l'empilement et la fusion, codex-home fournit la résolution de CODEX_HOME et le chargement du AGENTS.md global, core/src/config/mod.rs emballe le résultat fusionné dans un Config pour la boucle principale de l'Agent, et core/src/config_lock.rs garantit l'exécution reproductible via lockfile. cli/src/login.rs écrit auth.json, et l'état de login fait aussi partie de la couche de configuration.

Responsabilités

  1. Localiser codex home : find_codex_home lit CODEX_HOME, à défaut ~/.codex (codex-rs/core/src/config/mod.rs:4440-4442).
  2. Chargement multi-couche : load_config_layers_state charge dans l'ordre system / managed / cloud bundle / user / project / session flags, et produit un ConfigLayerStack (codex-rs/config/src/loader/mod.rs:116-168).
  3. Fusionner en effective config : ConfigLayerStack::effective_config merge les TOML du bas au haut selon la precedence (codex-rs/config/src/state.rs:483-492).
  4. Monter le Config runtime : ConfigBuilder assemble codex_home, cli_overrides, harness_overrides, cloud bundle puis build().await (codex-rs/core/src/config/mod.rs:1258-1297).
  5. Écrire l'état de login : login_with_chatgpt / run_login_with_api_key terminent le flux de login et écrivent les identifiants dans auth.json (codex-rs/cli/src/login.rs:137-165).

Motivations de conception

Un config.toml unique serait simple, mais le déploiement enterprise exige un empilement multi-source : une stratégie forcée poussée par MDM ne doit pas être modifiable par l'utilisateur ; un .codex/config.toml projet doit surpasser la config utilisateur globale ; un flag CLI doit primer sur la config projet. codex abstrait chaque couche en ConfigLayerEntry, et ConfigLayerSource::precedence renvoie un nombre qui décide de l'ordre de fusion — Session flags (30) > Project (25) > User (20) > System (10) > MDM (0). Ajouter une source, c'est ajouter une variante d'énum + un nombre, sans toucher à la logique de fusion. Le cloud bundle est une couche ajoutée plus tard : elle tire la config enterprise-managed et les requirements depuis le backend ChatGPT, et CloudConfigBundleLayers::from_bundle la convertit en layer ordinaire insérée dans le stack, qui suit le même chemin de fusion que le TOML local. config_lock.rs ajoute la reproductibilité : il sérialise le ConfigToml fusionné + la version codex en ConfigLockfileToml, et au replay validate_config_lock_replay compare expected vs actual ; en cas de divergence de version ou de champ, erreur — pour éviter que le même prompt ne donne des résultats différents d'une machine à l'autre.

Fichiers clés

codex-rs/config/src/config_layer_source.rs:6-49 — l'énum ConfigLayerSource et precedence(), définit 8 sources et l'ordre de fusion.codex-rs/config/src/loader/mod.rs:116-168load_config_layers_state, charge system / managed / cloud bundle / user / project dans le stack dans l'ordre.codex-rs/config/src/state.rs:483-492effective_config, merge_toml_values du bas vers le haut selon la precedence.codex-rs/core/src/config/mod.rs:614-673 — la structure Config, objet « config finale » runtime, avec model_provider, permissions, enforce_residency, etc.codex-rs/core/src/config/mod.rs:1258-1297ConfigBuilder, assemble codex_home, cli_overrides, harness_overrides, cloud bundle puis build().await.codex-rs/core/src/config/mod.rs:1721-1728Config::load_with_cli_overrides, l'entrée la plus courante.codex-rs/core/src/config_lock.rs:38-74config_lockfile et validate_config_lock_replay, génération du lockfile et validation au replay.codex-rs/codex-home/src/instructions/mod.rs:14-68CodexHomeUserInstructionsProvider, charge les instructions utilisateur globales depuis ~/.codex/AGENTS.md.

ConfigLayerSource comprime les 8 sources en une énum ; le nombre de precedence décide de l'ordre de fusion :

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 merge couche par couche du bas vers le haut selon la precedence ; ce qui vient après écrase ce qui était là avant :

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
}

Le config_lock fige le résultat de la fusion, et au replay compare les champs 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 报错
}

Flux de données

Limites et échecs

  • CODEX_HOME doit être un répertoire : si la variable existe mais n'est pas un répertoire, on remonte une erreur, sans repli silencieux sur ~/.codex (codex-rs/core/src/config/mod.rs:4436-4442).
  • Config invalide non fatale : Config::load_default_with_cli_overrides retombe sur défaut + cli overrides en cas d'échec de parsing du fichier utilisateur, pour que la CLI puisse encore démarrer (codex-rs/core/src/config/mod.rs:1731-1740).
  • config_lock : divergence de version = erreur par défaut : une divergence de version codex refuse le replay ; il faut debug.config_lockfile.allow_codex_version_mismatch=true pour passer (codex-rs/core/src/config_lock.rs:54-61).
  • Priorité d'AGENTS.md : dans un même répertoire, AGENTS.override.md prime sur AGENTS.md, et seul le premier fichier non vide est lu, pour éviter les ambiguïtés d'empilement (codex-rs/codex-home/src/instructions/mod.rs:26-67).
  • cloud bundle tiré seulement pour les comptes enterprise : cloud_config_eligible_auth exige uses_codex_backend et un plan Business/Enterprise/Edu (codex-rs/cloud-config/src/service.rs:47-54).

Récapitulatif

Le système de configuration fusionne multi-source (system / user / project / cloud / session flags) en Config selon un nombre precedence() ; le cloud bundle suit le même chemin merge_toml_values que le TOML local ; l'état de login est écrit dans auth.json et lu par l'AuthManager de Model Provider. ConfigLockfileToml fige le résultat fusionné pour garantir la cohérence au replay. La stratégie enterprise utilisée par les tâches cloud est rafraîchie périodiquement par le service cloud-config de Cloud Tasks, mis en cache local puis lu ici dans l'effective config.