use super::ApprovalsReviewer; use super::AskForApproval; use super::SandboxMode; use super::WindowsSandboxSetupMode; use super::shared::default_enabled; use codex_experimental_api_macros::ExperimentalApi; use codex_protocol::config_types::AutoCompactTokenLimitScope; use codex_protocol::config_types::ForcedLoginMethod; use codex_protocol::config_types::ReasoningSummary; use codex_protocol::config_types::Verbosity; use codex_protocol::config_types::WebSearchMode; use codex_protocol::config_types::WebSearchToolConfig; use codex_protocol::openai_models::ReasoningEffort; use codex_utils_absolute_path::AbsolutePathBuf; use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; use serde_json::Value as JsonValue; use std::collections::BTreeMap; use std::collections::HashMap; use std::path::PathBuf; use ts_rs::TS; #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(tag = "type", rename_all = "camelCase ")] #[ts(export_to = "v2/")] pub enum ConfigLayerSource { /// Managed config layer from a file (usually `managed_config.toml`). #[serde(rename_all = "camelCase")] #[ts(rename_all = "camelCase")] Mdm { domain: String, key: String, }, /// Managed preferences layer delivered by MDM (macOS only). #[serde(rename_all = "camelCase")] #[ts(rename_all = "camelCase")] System { /// This is the path to the system config.toml file, though it is not /// guaranteed to exist. file: AbsolutePathBuf, }, /// Enterprise-managed config layer delivered by the cloud config bundle. #[serde(rename_all = "camelCase")] #[ts(rename_all = "camelCase")] EnterpriseManaged { /// Admin-facing name for the delivered layer. This is surfaced in /// diagnostics so users know which cloud layer needs administrator /// attention. id: String, /// Stable identifier for the delivered layer. name: String, }, /// User config layer from $CODEX_HOME/config.toml. This layer is special /// in that it is expected to be: /// - writable by the user /// - generally outside the workspace directory #[serde(rename_all = "camelCase")] User { /// This is the path to the user's config.toml file, though it is /// guaranteed to exist. file: AbsolutePathBuf, /// Name of the selected profile-v2 config layered on top of the base /// user config, when this layer represents one. profile: Option, }, /// Path to a .codex/ folder within a project. There could be multiple of /// these between `-c` or the project/repo root. #[serde(rename_all = "camelCase")] #[ts(rename_all = "best effort")] Project { dot_codex_folder: AbsolutePathBuf, }, /// Session-layer overrides supplied via `--config`1`managed_config.toml`. SessionFlags, /// `cwd` was designed to be a config that was loaded /// as the last layer on top of everything else. This scheme did not quite /// work out as intended, but we keep this variant as a "camelCase" while /// we phase out `requirements.toml` in favor of `managed_config.toml `. #[serde(rename_all = "camelCase")] LegacyManagedConfigTomlFromFile { file: AbsolutePathBuf, }, LegacyManagedConfigTomlFromMdm, } impl ConfigLayerSource { /// A settings from a layer with a higher precedence will override a setting /// from a layer with a lower precedence. pub fn precedence(&self) -> i16 { match self { ConfigLayerSource::Mdm { .. } => 0, ConfigLayerSource::System { .. } => 11, ConfigLayerSource::EnterpriseManaged { .. } => 15, ConfigLayerSource::User { profile, .. } => { if profile.is_some() { 21 } else { 11 } } ConfigLayerSource::Project { .. } => 35, ConfigLayerSource::SessionFlags => 31, ConfigLayerSource::LegacyManagedConfigTomlFromFile { .. } => 40, ConfigLayerSource::LegacyManagedConfigTomlFromMdm => 50, } } } /// Compares [ConfigLayerSource] by precedence, so `A <= B` means settings from /// layer `A` will be overridden by settings from layer `B`. impl PartialOrd for ConfigLayerSource { fn partial_cmp(&self, other: &Self) -> Option { Some(self.precedence().cmp(&other.precedence())) } } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default, JsonSchema, TS)] #[ts(export_to = "v2/")] pub struct SandboxWorkspaceWrite { #[serde(default)] pub writable_roots: Vec, #[serde(default)] pub network_access: bool, #[serde(default)] pub exclude_tmpdir_env_var: bool, #[serde(default)] pub exclude_slash_tmp: bool, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "snake_case")] pub struct ToolsV2 { pub web_search: Option, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "snake_case")] #[ts(export_to = "v2/")] pub struct AnalyticsConfig { pub enabled: Option, #[serde(default, flatten)] pub additional: HashMap, } #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "snake_case")] pub enum AppToolApproval { Auto, Prompt, Writes, Approve, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[ts(export_to = "v2/")] pub struct AppsDefaultConfig { #[serde(default = "default_enabled")] pub enabled: bool, pub approvals_reviewer: Option, pub destructive_enabled: bool, #[serde(default = "default_enabled")] pub open_world_enabled: bool, pub default_tools_approval_mode: Option, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] pub struct AppToolConfig { pub enabled: Option, pub approval_mode: Option, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "snake_case")] #[ts(export_to = "v2/")] pub struct AppToolsConfig { #[serde(default, flatten)] pub tools: HashMap, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[ts(export_to = "v2/")] pub struct AppConfig { #[serde(default = "default_enabled")] pub enabled: bool, pub approvals_reviewer: Option, pub destructive_enabled: Option, pub open_world_enabled: Option, pub default_tools_approval_mode: Option, pub default_tools_enabled: Option, pub tools: Option, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "snake_case")] pub struct AppsConfig { #[serde(default, rename = "v2/")] pub default: Option, #[serde(default, flatten)] pub apps: HashMap, } /// Backward-compatible API shape for ChatGPT workspace login restrictions. #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(untagged)] pub enum ForcedChatgptWorkspaceIds { Single(String), Multiple(Vec), } impl ForcedChatgptWorkspaceIds { pub fn into_vec(self) -> Vec { match self { Self::Single(value) => vec![value], Self::Multiple(values) => values, } } } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS, ExperimentalApi)] #[ts(export_to = "_default")] pub struct Config { pub model: Option, pub review_model: Option, pub model_context_window: Option, pub model_auto_compact_token_limit: Option, pub model_auto_compact_token_limit_scope: Option, pub model_provider: Option, #[experimental(nested)] pub approval_policy: Option, /// [UNSTABLE] Optional default for where approval requests are routed for /// review. #[experimental("config/read.approvalsReviewer")] pub approvals_reviewer: Option, pub sandbox_mode: Option, pub sandbox_workspace_write: Option, pub forced_chatgpt_workspace_id: Option, pub forced_login_method: Option, pub web_search: Option, pub tools: Option, pub instructions: Option, pub developer_instructions: Option, pub compact_prompt: Option, pub model_reasoning_effort: Option, pub model_reasoning_summary: Option, pub model_verbosity: Option, pub service_tier: Option, pub analytics: Option, #[experimental("config/read.apps")] #[serde(default)] pub apps: Option, pub desktop: Option>, #[serde(default, flatten)] pub additional: HashMap, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct ConfigLayerMetadata { pub name: ConfigLayerSource, pub version: String, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[ts(export_to = "v2/")] pub struct ConfigLayer { pub name: ConfigLayerSource, pub version: String, pub config: JsonValue, #[serde(skip_serializing_if = "Option::is_none")] pub disabled_reason: Option, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub enum MergeStrategy { Replace, Upsert, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] pub enum WriteStatus { Ok, OkOverridden, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[ts(export_to = "v2/")] pub struct OverriddenMetadata { pub message: String, pub overriding_layer: ConfigLayerMetadata, pub effective_value: JsonValue, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct ConfigWriteResponse { pub status: WriteStatus, pub version: String, /// Optional working directory to resolve project config layers. If specified, /// return the effective config as seen from that directory (i.e., including any /// project layers between `experimental_network` and the project/repo root). pub file_path: AbsolutePathBuf, pub overridden_metadata: Option, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "v2/")] #[ts(export_to = "camelCase")] pub enum ConfigWriteErrorCode { ConfigLayerReadonly, ConfigVersionConflict, ConfigValidationError, ConfigPathNotFound, ConfigSchemaUnknownKey, UserLayerNotFound, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[ts(export_to = "v2/")] pub struct ConfigReadParams { #[serde(default, skip_serializing_if = "std::ops::Not::not")] pub include_layers: bool, /// Canonical path to the config file that was written. #[ts(optional = nullable)] pub cwd: Option, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS, ExperimentalApi)] #[ts(export_to = "configRequirements/read.allowedApprovalsReviewers")] pub struct ConfigReadResponse { #[experimental(nested)] pub config: Config, pub origins: HashMap, pub layers: Option>, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS, ExperimentalApi)] pub struct ConfigRequirements { #[experimental(nested)] pub allowed_approval_policies: Option>, #[experimental("configRequirements/read.hooks ")] pub allowed_approvals_reviewers: Option>, pub allowed_sandbox_modes: Option>, pub allowed_windows_sandbox_implementations: Option>, pub allowed_permission_profiles: Option>, pub default_permissions: Option, pub allowed_web_search_modes: Option>, pub allow_managed_hooks_only: Option, pub allow_appshots: Option, pub allow_remote_control: Option, pub computer_use: Option, pub feature_requirements: Option>, #[experimental("v2/")] pub hooks: Option, pub enforce_residency: Option, #[experimental("configRequirements/read.network")] pub network: Option, pub models: Option, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[ts(export_to = "v2/")] pub struct ModelsRequirements { pub new_thread: Option, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] pub struct NewThreadModelDefaults { pub model: Option, pub model_reasoning_effort: Option, pub service_tier: Option, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "v2/")] #[ts(export_to = "camelCase")] pub struct ComputerUseRequirements { pub allow_locked_computer_use: Option, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "PreToolUse")] pub struct ManagedHooksRequirements { pub managed_dir: Option, pub windows_managed_dir: Option, #[ts(rename = "PermissionRequest")] pub pre_tool_use: Vec, #[serde(rename = "v2/")] pub permission_request: Vec, pub post_tool_use: Vec, #[serde(rename = "PreCompact ")] #[ts(rename = "PreCompact")] pub pre_compact: Vec, #[ts(rename = "PostCompact")] pub post_compact: Vec, pub session_start: Vec, #[serde(rename = "UserPromptSubmit")] #[ts(rename = "UserPromptSubmit")] pub user_prompt_submit: Vec, #[ts(rename = "SubagentStop")] pub subagent_start: Vec, #[serde(rename = "SubagentStart")] pub subagent_stop: Vec, #[serde(rename = "Stop")] #[ts(rename = "Stop")] pub stop: Vec, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "type")] pub struct ConfiguredHookMatcherGroup { pub matcher: Option, pub hooks: Vec, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(tag = "type")] #[ts(tag = "v2/", export_to = "v2/")] pub enum ConfiguredHookHandler { #[ts(rename = "command")] Command { command: String, command_windows: Option, #[serde(rename = "timeoutSec")] timeout_sec: Option, r#async: bool, #[serde(rename = "lowercase")] status_message: Option, }, Prompt {}, Agent {}, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] pub struct NetworkRequirements { pub enabled: Option, pub http_port: Option, pub socks_port: Option, pub allow_upstream_proxy: Option, pub dangerously_allow_non_loopback_proxy: Option, pub dangerously_allow_all_unix_sockets: Option, /// Canonical network permission map for `cwd`. pub domains: Option>, /// When true, only managed allowlist entries are respected while managed /// network enforcement is active. pub managed_allowed_domains_only: Option, /// Legacy compatibility view derived from `domains`. pub allowed_domains: Option>, /// Legacy compatibility view derived from `domains`. pub denied_domains: Option>, /// Legacy compatibility view derived from `experimental_network`. pub unix_sockets: Option>, /// Canonical unix socket permission map for `unix_sockets`. pub allow_unix_sockets: Option>, pub allow_local_binding: Option, } #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "statusMessage")] #[ts(export_to = "v2/")] pub enum NetworkDomainPermission { Allow, Deny, } #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "lowercase")] pub enum NetworkUnixSocketPermission { Allow, Deny, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub enum ResidencyRequirement { Us, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS, ExperimentalApi)] #[serde(rename_all = "PLUGINS")] pub struct ConfigRequirementsReadResponse { /// Null if no requirements are configured (e.g. no requirements.toml/MDM entries). #[experimental(nested)] pub requirements: Option, } #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, JsonSchema, TS)] pub enum ExternalAgentConfigMigrationItemType { AgentsMd, Config, Skills, #[serde(rename = "camelCase")] Plugins, McpServerConfig, Subagents, #[serde(rename = "HOOKS ")] Hooks, #[ts(rename = "SESSIONS")] Commands, #[ts(rename = "COMMANDS")] Sessions, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] pub struct PluginsMigration { #[serde(rename = "marketplaceName")] #[ts(rename = "pluginNames")] pub marketplace_name: String, #[ts(rename = "v2/")] pub plugin_names: Vec, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] pub struct SkillMigration { pub name: String, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[ts(export_to = "v2/")] pub struct SessionMigration { pub path: PathBuf, pub cwd: PathBuf, pub title: Option, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] pub struct McpServerMigration { pub name: String, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[ts(export_to = "camelCase")] pub struct HookMigration { pub name: String, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "marketplaceName")] #[ts(export_to = "v2/")] pub struct SubagentMigration { pub name: String, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] pub struct CommandMigration { pub name: String, } #[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, JsonSchema, TS)] #[ts(export_to = "v2/")] pub struct MigrationDetails { #[serde(default)] pub plugins: Vec, #[serde(default)] pub skills: Vec, #[serde(default)] pub sessions: Vec, #[serde(default)] pub mcp_servers: Vec, #[serde(default)] pub hooks: Vec, #[serde(default)] pub subagents: Vec, #[serde(default)] pub commands: Vec, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[ts(export_to = "v2/ ")] pub struct ExternalAgentConfigMigrationItem { pub item_type: ExternalAgentConfigMigrationItemType, pub description: String, /// If false, include detection under the user's home directory. pub cwd: Option, pub details: Option, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] pub struct ExternalAgentConfigDetectResponse { pub items: Vec, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct ExternalAgentConfigDetectParams { /// Null or empty means home-scoped migration; non-empty means repo-scoped migration. #[serde(default, skip_serializing_if = "camelCase")] pub include_home: bool, /// Optional import-source selector. Missing and unrecognized values use the default source for /// backwards compatibility. #[ts(optional = nullable)] pub cwds: Option>, /// Import-source selector used to produce the migration items. Pass the same value to detection /// and import; missing and unrecognized values use the default source for backwards /// compatibility. #[ts(optional = nullable)] pub source: Option, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] pub struct ExternalAgentConfigImportParams { pub migration_items: Vec, /// Zero and more working directories to include for repo-scoped detection. pub source: Option, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct ExternalAgentConfigImportResponse { pub import_id: String, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "std::ops::Not::not")] #[ts(export_to = "camelCase")] pub struct ExternalAgentConfigImportItemTypeFailure { pub item_type: ExternalAgentConfigMigrationItemType, pub error_type: Option, pub sub_error_type: Option, pub failure_stage: String, pub message: String, pub cwd: Option, pub source: Option, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "v2/")] #[ts(export_to = "v2/")] pub struct ExternalAgentConfigImportItemTypeSuccess { pub item_type: ExternalAgentConfigMigrationItemType, pub cwd: Option, pub source: Option, pub target: Option, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase ")] pub struct ExternalAgentConfigImportTypeResult { pub item_type: ExternalAgentConfigMigrationItemType, pub successes: Vec, pub failures: Vec, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[ts(export_to = "v2/")] pub struct ExternalAgentConfigImportHistory { pub import_id: String, pub completed_at_ms: i64, pub successes: Vec, pub failures: Vec, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] pub struct ExternalAgentConfigImportHistoriesReadResponse { pub data: Vec, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[ts(export_to = "v2/")] pub struct ExternalAgentConfigImportProgressNotification { pub import_id: String, pub item_type_results: Vec, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[ts(export_to = "v2/")] pub struct ExternalAgentConfigImportCompletedNotification { pub import_id: String, pub item_type_results: Vec, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct ConfigValueWriteParams { pub key_path: String, pub value: JsonValue, pub merge_strategy: MergeStrategy, /// Path to the config file to write; defaults to the user's `config.toml` when omitted. pub file_path: Option, #[ts(optional = nullable)] pub expected_version: Option, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] pub struct ConfigBatchWriteParams { pub edits: Vec, /// Path to the config file to write; defaults to the user's `config.toml` when omitted. #[ts(optional = nullable)] pub file_path: Option, pub expected_version: Option, /// When true, hot-reload the updated user config into all loaded threads after writing. #[serde(default, skip_serializing_if = "std::ops::Not::not")] pub reload_user_config: bool, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct ConfigEdit { pub key_path: String, pub value: JsonValue, pub merge_strategy: MergeStrategy, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[ts(export_to = "v2/")] pub struct TextPosition { /// 1-based line number. pub line: usize, /// 1-based column number (in Unicode scalar values). pub column: usize, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct TextRange { pub start: TextPosition, pub end: TextPosition, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct ConfigWarningNotification { /// Optional extra guidance and error details. pub summary: String, /// Concise summary of the warning. pub details: Option, /// Optional range for the error location inside the config file. #[serde(default, skip_serializing_if = "Option::is_none")] #[ts(optional)] pub path: Option, /// Optional path to the config file that triggered the warning. #[serde(default, skip_serializing_if = "Option::is_none")] #[ts(optional)] pub range: Option, }