Skip to content

Sistema de configuración

源码版本rust-v0.145.0

La configuración (config) de codex no se carga de un único archivo: se apila en múltiples capas. El config.toml viene de varias fuentes — system / user / project / cloud bundle / session flags — y se fusiona por precedence hasta formar el effective config, sobre el que después se aplican los ConfigRequirements para validar restricciones. El crate config se ocupa del apilado y la fusión; codex-home ofrece la resolución de CODEX_HOME y la carga del AGENTS.md global; core/src/config/mod.rs envuelve el resultado de la fusión en un Config que usa el bucle principal del Agent; core/src/config_lock.rs usa un lockfile para garantizar ejecución reproducible. cli/src/login.rs escribe auth.json, así que el estado de login también es una capa de configuración.

Responsabilidades

  1. Localizar codex home: find_codex_home lee CODEX_HOME; si no está fijado, retrocede a ~/.codex (codex-rs/core/src/config/mod.rs:4440-4442).
  2. Carga multi-capa: load_config_layers_state carga en orden system / managed / cloud bundle / user / project / session flags y produce un ConfigLayerStack (codex-rs/config/src/loader/mod.rs:116-168).
  3. Fusionar y producir effective config: ConfigLayerStack::effective_config mergea TOML por precedence de baja a alta (codex-rs/config/src/state.rs:483-492).
  4. Ensamblar el Config de runtime: ConfigBuilder pega codex_home, cli_overrides, harness_overrides y cloud bundle y luego build().await (codex-rs/core/src/config/mod.rs:1258-1297).
  5. Escribir el estado de login: login_with_chatgpt / run_login_with_api_key, tras completar el flujo de login, vuelcan las credenciales a auth.json (codex-rs/cli/src/login.rs:137-165).

Motivación de diseño

Un único config.toml sería simple, pero el despliegue enterprise exige apilar varias fuentes: las políticas obligatorias bajadas por MDM no deben poder cambiarse por el usuario; el .codex/config.toml del proyecto debe sobrescribir el global del usuario; y los flags del CLI tienen que prevalecer sobre la configuración del proyecto. codex abstrae cada capa como ConfigLayerEntry, y ConfigLayerSource::precedence devuelve un número que decide el orden de fusión — Session flags (30) prevalece sobre Project (25) prevalece sobre User (20) prevalece sobre System (10) prevalece sobre MDM (0). Añadir un origen nuevo es añadir una variante al enum y devolver el número, sin tocar la lógica de fusión. El cloud bundle es una capa añadida después: tira del backend de ChatGPT para traer config y requirements gestionados por enterprise, y en load_config_layers_state se convierte en una capa normal vía CloudConfigBundleLayers::from_bundle para que entre al stack por la misma ruta de fusión que los TOML locales. config_lock.rs se añadió por reproducibilidad: serializa el ConfigToml resultante + la versión de codex en un ConfigLockfileToml, y al reproducir, validate_config_lock_replay compara expected vs actual; si la versión o los campos no coinciden, suelta error, evitando que el mismo prompt corra resultados distintos en máquinas distintas.

Archivos clave

codex-rs/config/src/config_layer_source.rs:6-49 — enum ConfigLayerSource y precedence(), define 8 orígenes y el orden de fusión.codex-rs/config/src/loader/mod.rs:116-168load_config_layers_state, carga system / managed / cloud bundle / user / project en orden en el stack.codex-rs/config/src/state.rs:483-492effective_config, hace merge_toml_values por precedence de baja a alta.codex-rs/core/src/config/mod.rs:614-673 — struct Config, el objeto «configuración final» que ve el runtime, con model_provider, permissions, enforce_residency, etc.codex-rs/core/src/config/mod.rs:1258-1297ConfigBuilder, ensambla codex_home, cli_overrides, harness_overrides y cloud bundle y luego build().await.codex-rs/core/src/config/mod.rs:1721-1728Config::load_with_cli_overrides, la entrada más usada.codex-rs/core/src/config_lock.rs:38-74config_lockfile y validate_config_lock_replay, generación del lockfile y validación de replay.codex-rs/codex-home/src/instructions/mod.rs:14-68CodexHomeUserInstructionsProvider, carga las instrucciones globales del usuario desde ~/.codex/AGENTS.md.

ConfigLayerSource comprime los 8 orígenes en un enum; el número de precedence decide el orden de fusión:

rust
// config/src/config_layer_source.rs:6-48 — origen + prioridad
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 o 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 mergea por precedence de baja a alta; lo que se escribe después sobrescribe a lo anterior:

rust
// config/src/state.rs:483-492 — fusión del apilado
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 congela el resultado de la fusión del momento; al reproducir, compara las diferencias de los campos TOML:

rust
// core/src/config_lock.rs:46-74 — validación de replay del lockfile
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
        )));
    }
    // ...sigue comparando campos TOML; si hay inconsistencia, usa similar para hacer diff y reporta
}

Flujo de datos

Bordes y fallos

  • CODEX_HOME tiene que ser un directorio: si la variable de entorno está fijada pero no existe o no es un directorio, suelta error directo, no retrocede silenciosamente a ~/.codex (codex-rs/core/src/config/mod.rs:4436-4442).
  • Configuración inválida no es fatal: Config::load_default_with_cli_overrides, si falla el parseo del archivo de configuración del usuario, retrocede a default + cli overrides, para que la CLI siga arrancando (codex-rs/core/src/config/mod.rs:1731-1740).
  • config_lock por defecto rechaza mismatch de versión: si la versión de codex no coincide, rechaza el replay; hay que fijar explícitamente debug.config_lockfile.allow_codex_version_mismatch=true para permitirlo (codex-rs/core/src/config_lock.rs:54-61).
  • Prioridad de AGENTS.md: en el mismo directorio, AGENTS.override.md prevalece sobre AGENTS.md, y solo se lee el primer archivo no vacío para evitar ambigüedades por apilado (codex-rs/codex-home/src/instructions/mod.rs:26-67).
  • cloud bundle solo se tira para cuentas enterprise: cloud_config_eligible_auth exige uses_codex_backend y que el plan sea Business/Enterprise/Edu (codex-rs/cloud-config/src/service.rs:47-54).

Resumen

El sistema de configuración fusiona múltiples fuentes (system / user / project / cloud / session flags) por número de precedence() en un Config; el cloud bundle va por la misma ruta merge_toml_values que los TOML locales, y el estado de login se escribe en auth.json y lo lee el AuthManager de Model Provider. ConfigLockfileToml congela el resultado de la fusión para garantizar consistencia al reproducir. Las políticas enterprise usadas por las tareas en la nube se refrescan periódicamente por el servicio cloud-config en la ruta de Cloud Tasks y, tras caer a la caché local, se leen aquí dentro del effective config.