Skip to main content

codex_runtime/runtime/client/
config.rs

1use std::collections::HashMap;
2use std::path::PathBuf;
3use std::sync::Arc;
4
5use crate::plugin::{PostHook, PreHook};
6use crate::runtime::hooks::RuntimeHookConfig;
7use crate::runtime::InitializeCapabilities;
8
9use super::CompatibilityGuard;
10
11#[derive(Clone, Debug, PartialEq, Eq)]
12pub struct ClientConfig {
13    pub cli_bin: PathBuf,
14    pub process_env: HashMap<String, String>,
15    pub process_cwd: Option<PathBuf>,
16    pub app_server_args: Vec<String>,
17    pub compatibility_guard: CompatibilityGuard,
18    pub initialize_capabilities: InitializeCapabilities,
19    pub hooks: RuntimeHookConfig,
20}
21
22impl Default for ClientConfig {
23    fn default() -> Self {
24        Self {
25            cli_bin: PathBuf::from("codex"),
26            process_env: HashMap::new(),
27            process_cwd: None,
28            app_server_args: Vec::new(),
29            compatibility_guard: CompatibilityGuard::default(),
30            initialize_capabilities: InitializeCapabilities::default(),
31            hooks: RuntimeHookConfig::default(),
32        }
33    }
34}
35
36impl ClientConfig {
37    /// Create config with default binary discovery.
38    pub fn new() -> Self {
39        Self::default()
40    }
41
42    /// Override CLI executable path.
43    pub fn with_cli_bin(mut self, cli_bin: impl Into<PathBuf>) -> Self {
44        self.cli_bin = cli_bin.into();
45        self
46    }
47
48    /// Replace process environment overrides for the spawned app-server child.
49    pub fn with_process_envs(
50        mut self,
51        process_env: impl IntoIterator<Item = (impl Into<String>, impl Into<String>)>,
52    ) -> Self {
53        self.process_env = process_env
54            .into_iter()
55            .map(|(key, value)| (key.into(), value.into()))
56            .collect();
57        self
58    }
59
60    /// Set one process environment override for the spawned app-server child.
61    pub fn with_process_env(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
62        self.process_env.insert(key.into(), value.into());
63        self
64    }
65
66    /// Override the working directory used to spawn the app-server child process.
67    pub fn with_process_cwd(mut self, process_cwd: impl Into<PathBuf>) -> Self {
68        self.process_cwd = Some(process_cwd.into());
69        self
70    }
71
72    /// Replace extra args appended after the fixed `app-server` subcommand.
73    pub fn with_app_server_args(
74        mut self,
75        args: impl IntoIterator<Item = impl Into<String>>,
76    ) -> Self {
77        self.app_server_args = args.into_iter().map(Into::into).collect();
78        self
79    }
80
81    /// Add one extra arg appended after the fixed `app-server` subcommand.
82    pub fn with_app_server_arg(mut self, arg: impl Into<String>) -> Self {
83        self.app_server_args.push(arg.into());
84        self
85    }
86
87    /// Override runtime compatibility guard policy.
88    pub fn with_compatibility_guard(mut self, guard: CompatibilityGuard) -> Self {
89        self.compatibility_guard = guard;
90        self
91    }
92
93    /// Disable compatibility guard checks at connect time.
94    pub fn without_compatibility_guard(mut self) -> Self {
95        self.compatibility_guard = CompatibilityGuard {
96            require_initialize_user_agent: false,
97            min_codex_version: None,
98        };
99        self
100    }
101
102    /// Override initialize capability switches.
103    pub fn with_initialize_capabilities(
104        mut self,
105        initialize_capabilities: InitializeCapabilities,
106    ) -> Self {
107        self.initialize_capabilities = initialize_capabilities;
108        self
109    }
110
111    /// Opt into Codex experimental app-server methods and fields.
112    pub fn enable_experimental_api(mut self) -> Self {
113        self.initialize_capabilities = self.initialize_capabilities.enable_experimental_api();
114        self
115    }
116
117    /// Replace runtime hook configuration.
118    pub fn with_hooks(mut self, hooks: RuntimeHookConfig) -> Self {
119        self.hooks = hooks;
120        self
121    }
122
123    /// Register one pre hook on client runtime config.
124    pub fn with_pre_hook(mut self, hook: Arc<dyn PreHook>) -> Self {
125        self.hooks.pre_hooks.push(hook);
126        self
127    }
128
129    /// Register one post hook on client runtime config.
130    pub fn with_post_hook(mut self, hook: Arc<dyn PostHook>) -> Self {
131        self.hooks.post_hooks.push(hook);
132        self
133    }
134
135    /// Register one pre-tool-use hook on client runtime config.
136    /// When at least one pre-tool-use hook is registered, the runtime manages the
137    /// approval channel internally and auto-escalates ApprovalPolicy → Untrusted.
138    /// Allocation: amortized O(1) push. Complexity: O(1).
139    pub fn with_pre_tool_use_hook(mut self, hook: Arc<dyn PreHook>) -> Self {
140        self.hooks.pre_tool_use_hooks.push(hook);
141        self
142    }
143}