Skip to content

Commit 6d4baff

Browse files
committed
feat: add support for -c/--config to override individual config items
1 parent 29d154c commit 6d4baff

File tree

20 files changed

+523
-98
lines changed

20 files changed

+523
-98
lines changed

codex-rs/Cargo.lock

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

codex-rs/cli/src/debug_sandbox.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::path::PathBuf;
22

3+
use codex_common::CliConfigOverrides;
34
use codex_common::SandboxPermissionOption;
45
use codex_core::config::Config;
56
use codex_core::config::ConfigOverrides;
@@ -20,12 +21,14 @@ pub async fn run_command_under_seatbelt(
2021
let SeatbeltCommand {
2122
full_auto,
2223
sandbox,
24+
config_overrides,
2325
command,
2426
} = command;
2527
run_command_under_sandbox(
2628
full_auto,
2729
sandbox,
2830
command,
31+
config_overrides,
2932
codex_linux_sandbox_exe,
3033
SandboxType::Seatbelt,
3134
)
@@ -39,12 +42,14 @@ pub async fn run_command_under_landlock(
3942
let LandlockCommand {
4043
full_auto,
4144
sandbox,
45+
config_overrides,
4246
command,
4347
} = command;
4448
run_command_under_sandbox(
4549
full_auto,
4650
sandbox,
4751
command,
52+
config_overrides,
4853
codex_linux_sandbox_exe,
4954
SandboxType::Landlock,
5055
)
@@ -60,16 +65,22 @@ async fn run_command_under_sandbox(
6065
full_auto: bool,
6166
sandbox: SandboxPermissionOption,
6267
command: Vec<String>,
68+
config_overrides: CliConfigOverrides,
6369
codex_linux_sandbox_exe: Option<PathBuf>,
6470
sandbox_type: SandboxType,
6571
) -> anyhow::Result<()> {
6672
let sandbox_policy = create_sandbox_policy(full_auto, sandbox);
6773
let cwd = std::env::current_dir()?;
68-
let config = Config::load_with_overrides(ConfigOverrides {
69-
sandbox_policy: Some(sandbox_policy),
70-
codex_linux_sandbox_exe,
71-
..Default::default()
72-
})?;
74+
let config = Config::load_with_cli_overrides(
75+
config_overrides
76+
.parse_overrides()
77+
.map_err(anyhow::Error::msg)?,
78+
ConfigOverrides {
79+
sandbox_policy: Some(sandbox_policy),
80+
codex_linux_sandbox_exe,
81+
..Default::default()
82+
},
83+
)?;
7384
let stdio_policy = StdioPolicy::Inherit;
7485
let env = create_env(&config.shell_environment_policy);
7586

codex-rs/cli/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ mod exit_status;
33
pub mod proto;
44

55
use clap::Parser;
6+
use codex_common::CliConfigOverrides;
67
use codex_common::SandboxPermissionOption;
78

89
#[derive(Debug, Parser)]
@@ -14,6 +15,9 @@ pub struct SeatbeltCommand {
1415
#[clap(flatten)]
1516
pub sandbox: SandboxPermissionOption,
1617

18+
#[clap(skip)]
19+
pub config_overrides: CliConfigOverrides,
20+
1721
/// Full command args to run under seatbelt.
1822
#[arg(trailing_var_arg = true)]
1923
pub command: Vec<String>,
@@ -28,6 +32,9 @@ pub struct LandlockCommand {
2832
#[clap(flatten)]
2933
pub sandbox: SandboxPermissionOption,
3034

35+
#[clap(skip)]
36+
pub config_overrides: CliConfigOverrides,
37+
3138
/// Full command args to run under landlock.
3239
#[arg(trailing_var_arg = true)]
3340
pub command: Vec<String>,

codex-rs/cli/src/main.rs

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use clap::Parser;
22
use codex_cli::LandlockCommand;
33
use codex_cli::SeatbeltCommand;
44
use codex_cli::proto;
5+
use codex_common::CliConfigOverrides;
56
use codex_exec::Cli as ExecCli;
67
use codex_tui::Cli as TuiCli;
78
use std::path::PathBuf;
@@ -19,6 +20,9 @@ use crate::proto::ProtoCli;
1920
subcommand_negates_reqs = true
2021
)]
2122
struct MultitoolCli {
23+
#[clap(flatten)]
24+
pub config_overrides: CliConfigOverrides,
25+
2226
#[clap(flatten)]
2327
interactive: TuiCli,
2428

@@ -73,28 +77,34 @@ async fn cli_main(codex_linux_sandbox_exe: Option<PathBuf>) -> anyhow::Result<()
7377

7478
match cli.subcommand {
7579
None => {
76-
codex_tui::run_main(cli.interactive, codex_linux_sandbox_exe)?;
80+
let mut tui_cli = cli.interactive;
81+
prepend_config_flags(&mut tui_cli.config_overrides, cli.config_overrides);
82+
codex_tui::run_main(tui_cli, codex_linux_sandbox_exe)?;
7783
}
78-
Some(Subcommand::Exec(exec_cli)) => {
84+
Some(Subcommand::Exec(mut exec_cli)) => {
85+
prepend_config_flags(&mut exec_cli.config_overrides, cli.config_overrides);
7986
codex_exec::run_main(exec_cli, codex_linux_sandbox_exe).await?;
8087
}
8188
Some(Subcommand::Mcp) => {
8289
codex_mcp_server::run_main(codex_linux_sandbox_exe).await?;
8390
}
84-
Some(Subcommand::Proto(proto_cli)) => {
91+
Some(Subcommand::Proto(mut proto_cli)) => {
92+
prepend_config_flags(&mut proto_cli.config_overrides, cli.config_overrides);
8593
proto::run_main(proto_cli).await?;
8694
}
8795
Some(Subcommand::Debug(debug_args)) => match debug_args.cmd {
88-
DebugCommand::Seatbelt(seatbelt_command) => {
96+
DebugCommand::Seatbelt(mut seatbelt_cli) => {
97+
prepend_config_flags(&mut seatbelt_cli.config_overrides, cli.config_overrides);
8998
codex_cli::debug_sandbox::run_command_under_seatbelt(
90-
seatbelt_command,
99+
seatbelt_cli,
91100
codex_linux_sandbox_exe,
92101
)
93102
.await?;
94103
}
95-
DebugCommand::Landlock(landlock_command) => {
104+
DebugCommand::Landlock(mut landlock_cli) => {
105+
prepend_config_flags(&mut landlock_cli.config_overrides, cli.config_overrides);
96106
codex_cli::debug_sandbox::run_command_under_landlock(
97-
landlock_command,
107+
landlock_cli,
98108
codex_linux_sandbox_exe,
99109
)
100110
.await?;
@@ -104,3 +114,14 @@ async fn cli_main(codex_linux_sandbox_exe: Option<PathBuf>) -> anyhow::Result<()
104114

105115
Ok(())
106116
}
117+
118+
/// Prepend root-level overrides so they have lower precedence than
119+
/// CLI-specific ones specified after the subcommand (if any).
120+
fn prepend_config_flags(
121+
subcommand_config_overrides: &mut CliConfigOverrides,
122+
cli_config_overrides: CliConfigOverrides,
123+
) {
124+
subcommand_config_overrides
125+
.raw_overrides
126+
.splice(0..0, cli_config_overrides.raw_overrides);
127+
}

codex-rs/cli/src/proto.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::io::IsTerminal;
22
use std::sync::Arc;
33

44
use clap::Parser;
5+
use codex_common::CliConfigOverrides;
56
use codex_core::Codex;
67
use codex_core::config::Config;
78
use codex_core::config::ConfigOverrides;
@@ -13,9 +14,12 @@ use tracing::error;
1314
use tracing::info;
1415

1516
#[derive(Debug, Parser)]
16-
pub struct ProtoCli {}
17+
pub struct ProtoCli {
18+
#[clap(skip)]
19+
pub config_overrides: CliConfigOverrides,
20+
}
1721

18-
pub async fn run_main(_opts: ProtoCli) -> anyhow::Result<()> {
22+
pub async fn run_main(opts: ProtoCli) -> anyhow::Result<()> {
1923
if std::io::stdin().is_terminal() {
2024
anyhow::bail!("Protocol mode expects stdin to be a pipe, not a terminal");
2125
}
@@ -24,7 +28,12 @@ pub async fn run_main(_opts: ProtoCli) -> anyhow::Result<()> {
2428
.with_writer(std::io::stderr)
2529
.init();
2630

27-
let config = Config::load_with_overrides(ConfigOverrides::default())?;
31+
let ProtoCli { config_overrides } = opts;
32+
let overrides_vec = config_overrides
33+
.parse_overrides()
34+
.map_err(anyhow::Error::msg)?;
35+
36+
let config = Config::load_with_cli_overrides(overrides_vec, ConfigOverrides::default())?;
2837
let ctrl_c = notify_on_sigint();
2938
let (codex, _init_id) = Codex::spawn(config, ctrl_c.clone()).await?;
3039
let codex = Arc::new(codex);

codex-rs/common/Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ workspace = true
99
[dependencies]
1010
clap = { version = "4", features = ["derive", "wrap_help"], optional = true }
1111
codex-core = { path = "../core" }
12+
toml = { version = "0.8", optional = true }
13+
serde = { version = "1", optional = true }
1214

1315
[features]
1416
# Separate feature so that `clap` is not a mandatory dependency.
15-
cli = ["clap"]
17+
cli = ["clap", "toml", "serde"]
1618
elapsed = []

0 commit comments

Comments
 (0)