codex exec resume overrides persisted cwd when -C is omitted
What version of Codex is running?
Current source at 725b3a44f8d13c8d2f019e1ecbc8ab686466b950; reproduced with standalone Codex 0.149.1.
What happened?
A thread created with an explicit managed-worktree cwd can silently rebind to the caller's current repository workspace when it is resumed without -C.
The app-server protocol already supports the desired behavior: ThreadResumeParams.cwd is optional, and cold resume falls back to the persisted SessionMeta.cwd. However, codex-rs/exec/src/lib.rs currently builds the resume request with:
cwd: Some(config.cwd.to_string_lossy().to_string()),
runtime_workspace_roots: Some(config.workspace_roots.clone()),
After configuration resolution, this no longer distinguishes an explicit -C from the process cwd used as a default. The resume request therefore overrides the persisted checkout even when the user did not request a rebind.
This becomes especially visible after a proxy disconnect or app-server restart, when the thread is cold-resumed from history.
Reproduction
codex exec -C /path/to/managed-worktree "start a task and print pwd"
# Save the thread id, then reconnect or restart app-server.
cd /path/to/repository-workspace
codex exec resume <thread-id> "print pwd"
Expected: the resumed task remains in /path/to/managed-worktree.
Observed: the resume request supplies /path/to/repository-workspace and the task rebinds there.
Suggested correction
Retain whether -C was explicitly supplied when constructing the exec resume request:
- omit
ThreadResumeParams.cwdwhen-Cwas not supplied; - omit the implicit
runtimeWorkspaceRootsoverride in the same case; - preserve explicit
-Cas an intentional rebind; - apply the same rule to any Desktop remote-resume request builder.
The remote TUI path already follows this model by omitting cwd unless there is an explicit remote override.
Acceptance coverage
- Implicit
codex exec resumeemits no cwd or workspace-root override. - Explicit
-Cemits both and still intentionally rebinds. - Cold resume after app-server restart preserves the persisted checkout.
- Warm reconnect to an idle loaded thread preserves the checkout.
- Sandboxed Git and built-in
apply_patchcontinue in the original managed worktree after reconnect.
1 Comment
Confirmed still present on current
main(2764e8362). While tracing it Imapped every affected call site — one more than described in this report:
codex-rs/exec/src/lib.rs:1220—thread_resume_params_from_configforcescwd: Some(config.cwd…)andruntime_workspace_roots: Some(…)on everyresume.
codex-rs/exec/src/lib.rs:879— theThreadForkParamsbuilder repeats thesame pattern, so
codex exec fork <thread-id>rebinds the copy to thecaller's directory under the same conditions. The suggested correction
should cover fork alongside resume.
codex-rs/exec/src/lib.rs:1190(ThreadStartParams) is correct as-is —thread creation must supply a cwd.
Supporting details for whoever picks this up:
thread_cwd_from_config(
codex-rs/tui/src/app_server_session.rs:1979) returnsOption<String>and yieldsNonefor remote threads unless an explicitoverride was supplied. The exec builders just need to adopt the same
omit-unless-explicit rule.
ThreadResumeParams.cwd: Option<String>is optional-nullable(
codex-rs/app-server-protocol/src/protocol/v2/thread.rs), and cold resumereads the persisted thread cwd back server-side
(
thread_from_stored_threadincodex-rs/app-server/src/request_processors/thread_processor.rs).Natural home for the acceptance coverage listed above: the existing app-server
resume/fork suites (
codex-rs/app-server/tests/suite/v2/thread_resume.rs,thread_fork.rs) plus an exec-level test asserting that an implicitcodex exec resumeemits no cwd/workspace-root override while an explicit-Cstill does.