Skip to content

[codex] simplify shell snapshot ownership#27756

Merged
pakrym-oai merged 3 commits into
mainfrom
pakrym/shell-snapshot-ownership
Jun 15, 2026
Merged

[codex] simplify shell snapshot ownership#27756
pakrym-oai merged 3 commits into
mainfrom
pakrym/shell-snapshot-ownership

Conversation

@pakrym-oai

Copy link
Copy Markdown
Contributor

Why

Shell snapshot lifecycle state was split between Shell and SessionServices: Shell carried the receiver while session code exposed and forwarded the raw sender. That coupled shell identity to mutable snapshot state and made refresh, inheritance, and file lifetime harder to reason about.

What changed

  • make each Arc<ShellSnapshot> represent one cwd-specific snapshot generation
  • store the active generation in SessionServices with ArcSwapOption
  • have construction start the background build and expose only a cwd-validated snapshot path
  • use ShellSnapshotFile ownership to delete snapshot files automatically
  • pass snapshot paths explicitly to shell runtimes instead of storing snapshot state on Shell
  • preserve inherited and in-flight generations by pinning their Arc while they are in use

Test plan

  • cargo check -p codex-core --lib
  • just test -p codex-core 'shell_snapshot::tests'
  • just test -p codex-core shell_command_snapshot_still_intercepts_apply_patch
  • just test -p codex-core shell_snapshot_deleted_after_shutdown_with_skills

@pakrym-oai
pakrym-oai marked this pull request as ready for review June 12, 2026 04:30
@pakrym-oai
pakrym-oai requested a review from a team as a code owner June 12, 2026 04:30

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 75b42ead5b

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +1411 to +1412
if self.services.shell_snapshot.load().is_some() {
self.services.shell_snapshot.store(Some(ShellSnapshot::new(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Add integration coverage for snapshot refresh

This replaces the stored shell snapshot on cwd updates, but the integration suite has no coverage for cwd refresh or child inheritance. Because this is agent-visible behavior, the repo guidance requires an integration test/list of behaviors. guidance

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not worth it.

Comment on lines +267 to +270
let shell_snapshot = ctx.session.services.shell_snapshot.load_full();
let shell_snapshot_location = shell_snapshot
.as_ref()
.and_then(|snapshot| snapshot.location(&req.cwd));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep snapshot alive for background unified exec

When a local unified exec is still starting and the session cwd is changed, the refresh path replaces services.shell_snapshot and drops the old snapshot file immediately. This local Arc is dropped as soon as run() returns, while the live UnifiedExecProcess does not retain it, so the wrapper can silently skip sourcing the snapshot and run with a bare environment. Keep the loaded snapshot alive with the process or spawn lifecycle.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do not update cwd mid turn.

Comment thread codex-rs/core/src/shell_snapshot.rs Outdated
}
session_telemetry.counter("codex.shell_snapshot", /*inc*/ 1, &counter_tags);
let _ = shell_snapshot_tx.send(snapshot.ok());
if let Ok(snapshot) = snapshot {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It leaves failed generations looking inheritable... On an err, load_full() still returns Some. So child init skips its own capture but this receiver can never produce a file. This is low frequency but it looks like a regression. Can we represent failure separately? Or fall back to a child capture? (no strong opinion)

Comment thread codex-rs/core/src/agent/control.rs Outdated
.session
.services
.shell_snapshot
.load_full()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn’t this also inherit failed generations? load_full() stays Some($) after capture fails, so the child skips its own attempt and never retries.

Could we only inherit a ready snapshot?

@pakrym-oai

Copy link
Copy Markdown
Contributor Author

Updated

@jif-oai jif-oai left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@pakrym-oai
pakrym-oai merged commit 1aa3e43 into main Jun 15, 2026
31 checks passed
@pakrym-oai
pakrym-oai deleted the pakrym/shell-snapshot-ownership branch June 15, 2026 15:18
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 15, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants