This page documents the Config API exposed by the app server for reading and writing configuration, and the layered config resolution system that determines effective config values. The Config API allows IDE extensions and other clients to inspect the current configuration, modify user settings, and receive warnings about overrides or conflicts.
For information about the config file schema itself, see the Configuration System overview. For details on feature flags, see Feature Flags and Stages.
The config system resolves values from multiple layers with strict precedence rules implemented in ConfigLayerStack. Higher-precedence layers override values from lower-precedence layers.
Config Loading Flow Diagram:
Layer precedence ordering (implemented via ConfigLayerSource::precedence()):
CFPreferences (macOS only)/etc/codex/config.toml$CODEX_HOME/config.toml.codex/config.toml (can stack between cwd and repo root)build_cli_overrides_layer()Sources:
The ConfigLayerStack struct (in codex-rs/core/src/config_loader/mod.rs) maintains the ordered sequence of config layers and merges them on demand.
ConfigLayerStack Structure:
| Field | Type | Description |
|---|---|---|
layers | Vec<ConfigLayer> | Ordered list of config layers (sorted by precedence) |
requirements | Option<ConfigRequirements> | Constraints from requirements.toml or MDM |
ConfigLayer Structure:
| Field | Type | Description |
|---|---|---|
source | Sourced<ConfigLayerSource> | Layer identity with provenance tracking |
value | TomlValue | Parsed TOML content |
version | String | SHA-256 hash of source file content |
disabled_reason | Option<String> | Parse/load errors that disabled this layer |
Wire Protocol Layer Metadata (ConfigLayerMetadata in app-server-protocol):
| Field | Type | Description |
|---|---|---|
name | ConfigLayerSource | Discriminated union (User/Project/SessionFlags/etc) |
version | String | SHA-256 hash for optimistic concurrency control |
Sources:
config/read RequestThe config/read endpoint (handled by ConfigApi::read()) fetches the effective configuration after applying all layers and requirements constraints. Optionally includes layer-by-layer introspection for debugging.
Request parameters:
Response structure:
Implementation Flow:
Sources:
The origins map tracks which layer set each configuration key via build_origins_map(). This enables clients to display "set by System config" or "overridden by CLI flag" annotations in settings UIs.
Origins Map Construction:
Example origins map:
Sources:
config/value/writeThe config/value/write endpoint (handled by ConfigApi::write_value()) writes a single configuration key to the user's config.toml (or another specified layer).
Request parameters:
Response:
Sources:
config/batchWriteThe config/batchWrite endpoint (handled by ConfigApi::write_batch()) applies multiple edits atomically to a single config file using ConfigEditsBuilder. If any edit fails validation, the entire batch is rejected.
Request parameters:
ConfigEditsBuilder Pattern:
The ConfigEditsBuilder in codex-rs/core/src/config/edit.rs provides a fluent API for applying multiple edits to a DocumentMut (parsed TOML document):
Supported Edit Operations (via ConfigEdit enum):
SetModel { model, effort } - Update model and reasoning effortSetModelPersonality { personality } - Update personality settingReplaceMcpServers(map) - Replace entire [mcp_servers] tableSetSkillConfig { path, enabled } - Toggle skill configSetProjectTrustLevel { path, level } - Update project trustSetPath { segments, value } - Generic key path writeClearPath { segments } - Remove key pathSources:
Config Write Implementation Flow:
Optimistic concurrency control:
config/read and captures the version (SHA-256 hash)expected_version set to that hashConfigVersionConflictAtomic Write Mechanism (write_atomically() in codex-rs/core/src/path_utils.rs):
Sources:
After a successful write, the server reloads the config layer stack and checks if a higher-precedence layer overrides the newly written value. If so, the response includes overridden_metadata and the app server emits a config/warning notification.
Override Detection Algorithm:
ConfigWarningNotification Structure:
Sources:
configRequirements/read RequestFetches constraints enforced by requirements.toml (or MDM) via CloudRequirementsLoader. This enables clients to show validation errors before attempting a write.
Response:
Sources:
Requirements are loaded via CloudRequirementsLoader from two sources (in precedence order):
CFPreferences)requirements.toml file (platform-agnostic)Requirements Application Flow:
Requirements act as allow-lists that constrain config values using the Constrained<T> wrapper type:
If a user tries to write a disallowed value (e.g., approval_policy = "untrusted"), ConfigEditsBuilder validates against requirements and returns a ConfigValidationError immediately without writing to disk.
Constrained Value Enforcement (in Config struct):
permissions.approval_policy: Constrained<AskForApproval> - Validates writes against allowed_approval_policiespermissions.sandbox_policy: Constrained<SandboxPolicy> - Validates against allowed_sandbox_modesweb_search_mode: Constrained<WebSearchMode> - Validates against allowed_web_search_modesmcp_servers: Constrained<HashMap<String, McpServerConfig>> - Filters servers per requirementsSources:
The profiles system allows users to define named config presets in config.toml that can be activated via --profile flag or profile config key.
ConfigProfile Structure:
Profile Resolution:
Example config.toml with profiles:
Usage: codex --profile fast or codex -c profile=fast
Wire Protocol Representation:
In the app-server protocol, profiles are exposed as part of the Config struct:
Sources:
ConfigLayerStack Merge Implementation:
merge_toml_values() Behavior (defined in codex-rs/core/src/config_loader/mod.rs):
Example:
Effective config after merge:
model = "gpt-5" (layer 2 replaces scalar)profiles.dev.model = "gpt-3.5-turbo" (layer 2 didn't set this key, layer 1 wins)profiles.dev.reasoning_effort = "medium" (layer 2 didn't set this key, layer 1 wins)profiles.dev.approval_policy = "never" (layer 2 adds new key to table)Deserialization to ConfigToml:
After merging, deserialize_config_toml_with_base() converts the TomlValue to a strongly-typed ConfigToml struct:
The AbsolutePathBufGuard ensures relative paths in the merged TOML are resolved against the appropriate base directory.
Sources:
The ConfigWriteErrorCode enum (in codex-rs/app-server-protocol/src/protocol/v2.rs) defines standardized error codes returned by config write APIs:
| Error Code | Description | When Returned |
|---|---|---|
ConfigLayerReadonly | Layer cannot be modified (e.g., MDM, System) | Client tries to write to read-only layer |
ConfigVersionConflict | expected_version mismatch (optimistic lock fail) | File changed between read and write |
ConfigValidationError | Invalid TOML or violates schema/requirements | Edit produces invalid config or violates requirements |
ConfigPathNotFound | Specified file_path does not exist | Client specifies non-existent file path |
ConfigSchemaUnknownKey | Key not recognized by schema | Client tries to set unknown config key |
UserLayerNotFound | No user config file and none was created | Write to user layer failed (permissions?) |
Error Response Structure:
Sources:
When a config file has invalid TOML, the ConfigWarningNotification includes precise line/column ranges for IDE integration. This is implemented via ConfigError in codex-rs/core/src/config_loader/error.rs.
ConfigWarningNotification with Location:
This design avoids disrupting in-flight turns while allowing config changes to take effect on subsequent turns. The McpServerRefreshConfig contains the updated server definitions, which are applied during the next turn/start.
Request/Response:
Sources:
| Method | Purpose | Key Params | Response |
|---|---|---|---|
config/read | Read effective config | include_layers, cwd | Config, origins, optional layers |
config/value/write | Write single key | key_path, value, merge_strategy | version, file_path, optional overridden_metadata |
config/batchWrite | Atomic multi-key write | edits[] | version, file_path |
configRequirements/read | Read constraints | (none) | requirements or null |
Sources:
Refresh this wiki