feat: wire ephemeral in codex exec (#10758)

This commit is contained in:
jif-oai 2026-02-05 15:49:57 +00:00 committed by GitHub
parent 4033f905c6
commit d337b51741
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 65 additions and 1 deletions

View file

@ -51,6 +51,7 @@ You can enable notifications by configuring a script that is run whenever the ag
### `codex exec` to run Codex programmatically/non-interactively
To run Codex non-interactively, run `codex exec PROMPT` (you can also pass the prompt via `stdin`) and Codex will work on your task until it decides that it is done and exits. Output is printed to the terminal directly. You can set the `RUST_LOG` environment variable to see more about what's going on.
Use `codex exec --ephemeral ...` to run without persisting session rollout files to disk.
### Experimenting with the Codex Sandbox

View file

@ -71,6 +71,10 @@ pub struct Cli {
#[arg(long = "add-dir", value_name = "DIR", value_hint = clap::ValueHint::DirPath)]
pub add_dir: Vec<PathBuf>,
/// Run without persisting session files to disk.
#[arg(long = "ephemeral", global = true, default_value_t = false)]
pub ephemeral: bool,
/// Path to a JSON Schema file describing the model's final response shape.
#[arg(long = "output-schema", value_name = "FILE")]
pub output_schema: Option<PathBuf>,
@ -262,9 +266,11 @@ mod tests {
"gpt-5.2-codex",
"--dangerously-bypass-approvals-and-sandbox",
"--skip-git-repo-check",
"--ephemeral",
PROMPT,
]);
assert!(cli.ephemeral);
let Some(Command::Resume(args)) = cli.command else {
panic!("expected resume command");
};

View file

@ -103,6 +103,7 @@ pub async fn run_main(cli: Cli, codex_linux_sandbox_exe: Option<PathBuf>) -> any
cwd,
skip_git_repo_check,
add_dir,
ephemeral,
color,
last_message_file,
json: json_mode,
@ -254,7 +255,7 @@ pub async fn run_main(cli: Cli, codex_linux_sandbox_exe: Option<PathBuf>) -> any
include_apply_patch_tool: None,
show_raw_agent_reasoning: oss.then_some(true),
tools_web_search_request: None,
ephemeral: None,
ephemeral: ephemeral.then_some(true),
additional_writable_roots: add_dir,
};

View file

@ -0,0 +1,55 @@
#![cfg(not(target_os = "windows"))]
#![allow(clippy::expect_used, clippy::unwrap_used)]
use codex_utils_cargo_bin::find_resource;
use core_test_support::test_codex_exec::test_codex_exec;
use walkdir::WalkDir;
fn session_rollout_count(home_path: &std::path::Path) -> usize {
let sessions_dir = home_path.join("sessions");
if !sessions_dir.exists() {
return 0;
}
WalkDir::new(sessions_dir)
.into_iter()
.filter_map(Result::ok)
.filter(|entry| entry.file_type().is_file())
.filter(|entry| entry.file_name().to_string_lossy().ends_with(".jsonl"))
.count()
}
#[test]
fn persists_rollout_file_by_default() -> anyhow::Result<()> {
let test = test_codex_exec();
let fixture = find_resource!("tests/fixtures/cli_responses_fixture.sse")?;
test.cmd()
.env("CODEX_RS_SSE_FIXTURE", &fixture)
.env("OPENAI_BASE_URL", "http://unused.local")
.arg("--skip-git-repo-check")
.arg("default persistence behavior")
.assert()
.code(0);
assert_eq!(session_rollout_count(test.home_path()), 1);
Ok(())
}
#[test]
fn does_not_persist_rollout_file_in_ephemeral_mode() -> anyhow::Result<()> {
let test = test_codex_exec();
let fixture = find_resource!("tests/fixtures/cli_responses_fixture.sse")?;
test.cmd()
.env("CODEX_RS_SSE_FIXTURE", &fixture)
.env("OPENAI_BASE_URL", "http://unused.local")
.arg("--skip-git-repo-check")
.arg("--ephemeral")
.arg("ephemeral behavior")
.assert()
.code(0);
assert_eq!(session_rollout_count(test.home_path()), 0);
Ok(())
}

View file

@ -2,6 +2,7 @@
mod add_dir;
mod apply_patch;
mod auth_env;
mod ephemeral;
mod originator;
mod output_schema;
mod resume;