Système de configuration
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
- Localiser codex home :
find_codex_homelitCODEX_HOME, à défaut~/.codex(codex-rs/core/src/config/mod.rs:4440-4442). - Chargement multi-couche :
load_config_layers_statecharge dans l'ordre system / managed / cloud bundle / user / project / session flags, et produit unConfigLayerStack(codex-rs/config/src/loader/mod.rs:116-168). - Fusionner en effective config :
ConfigLayerStack::effective_configmerge les TOML du bas au haut selon la precedence (codex-rs/config/src/state.rs:483-492). - Monter le
Configruntime :ConfigBuilderassemble codex_home, cli_overrides, harness_overrides, cloud bundle puisbuild().await(codex-rs/core/src/config/mod.rs:1258-1297). - Écrire l'état de login :
login_with_chatgpt/run_login_with_api_keyterminent le flux de login et écrivent les identifiants dansauth.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-168 — load_config_layers_state, charge system / managed / cloud bundle / user / project dans le stack dans l'ordre.codex-rs/config/src/state.rs:483-492 — effective_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-1297 — ConfigBuilder, assemble codex_home, cli_overrides, harness_overrides, cloud bundle puis build().await.codex-rs/core/src/config/mod.rs:1721-1728 — Config::load_with_cli_overrides, l'entrée la plus courante.codex-rs/core/src/config_lock.rs:38-74 — config_lockfile et validate_config_lock_replay, génération du lockfile et validation au replay.codex-rs/codex-home/src/instructions/mod.rs:14-68 — CodexHomeUserInstructionsProvider, 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 :
// 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 :
// 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 :
// 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_HOMEdoit ê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_overridesretombe 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=truepour passer (codex-rs/core/src/config_lock.rs:54-61). - Priorité d'AGENTS.md : dans un même répertoire,
AGENTS.override.mdprime surAGENTS.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_authexigeuses_codex_backendet 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.