Repository navigation
fix(agent-resume): resume from launch directory, not drifted cwd - #5029
TravelThePath wants to merge 3 commits into
Conversation
Resuming an agent (e.g. Claude Code) after the app reopens generated a `cd <dir> && <agent> --resume <id>` command that changed into the agent's *drifted* current working directory instead of the directory it was launched in. Claude keys its session transcript to the launch directory, so resuming elsewhere fails with "No conversation found with session ID". This commit adds the regression test only; it fails against the current behavior. The fix follows in the next commit.
The resume/fork command builders resolved the `cd` target as
`workingDirectory ?? launchCommand?.workingDirectory`, preferring the
agent's recorded (drifted) cwd over the directory it was launched in.
Claude Code keys its session transcript to the launch directory, so
resuming from a drifted cwd fails with "No conversation found with
session ID".
Flip the precedence to `launchCommand?.workingDirectory ?? workingDirectory`
in both the app-side builder (AgentResumeCommandBuilder.shellCommand and
the custom-resume {{cwd}} template) and the CLI auto-resume binding
(agentSurfaceResumeCommand + the binding cwd metadata). This matches the
precedence already used by AgentForkSupport.openCodeProbeWorkingDirectory.
Behavior is unchanged when the launch dir and recorded cwd agree (the
common case) or when launchCommand is absent (falls back to the recorded
cwd); it only differs under cwd drift, where launch dir is correct for
every agent kind. Makes the regression test from the previous commit pass.
|
@TravelThePath is attempting to deploy a commit to the Manaflow Team on Vercel. A member of the Team first needs to authorize it. |
📝 WalkthroughWalkthroughThis PR changes resume-command cwd resolution to prefer ChangesWorking Directory Precedence for Resume Commands
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 17 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (17 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR updates resume command generation to prefer the launch command’s captured working directory over a potentially drifted session working directory, and adds a regression test to lock in the behavior.
Changes:
- Prefer
launchCommand.workingDirectoryoverworkingDirectorywhen building resume commands and related parameter maps. - Update CLI resume hook parameter construction to align with the new cwd precedence.
- Add a test ensuring Claude resume commands
cdinto the launch directory rather than a nested/drifted cwd.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| cmuxTests/RestorableAgentHookProviderResumeTests.swift | Adds a regression test for cwd precedence in Claude resume command generation. |
| Sources/RestorableAgentSession.swift | Changes resume/fork command cwd resolution to prioritize launchCommand.workingDirectory. |
| CLI/cmux.swift | Aligns CLI hook payload and resume command building with updated cwd precedence. |
Comments suppressed due to low confidence (1)
cmuxTests/RestorableAgentHookProviderResumeTests.swift:10
- This test appears to be placed under
extension SocketListenerAcceptPolicyTests, which doesn’t match the file name (RestorableAgentHookProviderResumeTests.swift) or the behavior under test (resume command cwd precedence). Moving it into the most relevantXCTestCase(e.g., the resume/hook provider test case) will make test organization clearer and reduce the chance of future misclassification when browsing or running focused test suites.
extension SocketListenerAcceptPolicyTests {
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Greptile SummaryFixes the session-resume bug where the
Confidence Score: 5/5Safe to merge. The fix is a pure precedence swap applied consistently across all four resume/fork command-building sites, with no new state, no new branches, and no observable effect when launchCommand is absent or when the two directories are equal. All four changed sites perform an identical, trivially correct operand swap. The zero-drift path is byte-identical to the old code, the no-launchCommand path falls back to the existing value, and the drift path (the only new behavior) is now covered by three new regression tests that document the before/after contract. No files require special attention. The test for cwd: .ignore uses slightly imprecise assertions, but this is limited to the test file and does not affect production behavior. Important Files Changed
Sequence DiagramsequenceDiagram
participant Hook as Agent Hook / Snapshot
participant Builder as AgentResumeCommandBuilder
participant CLI as CLI (cmux.swift)
participant Shell as Terminal
Hook->>Builder: resumeShellCommand(kind, sessionId, launchCommand, workingDirectory)
Note over Builder: OLD: workingDirectory ?? launchCommand?.workingDirectory<br/>NEW: launchCommand?.workingDirectory ?? workingDirectory
Builder->>Builder: shellCommand() resolves cwd
Builder-->>CLI: shell command string (cd to launch dir)
Hook->>CLI: agentSurfaceResumeCommand(launchCommand, workingDirectory)
Note over CLI: OLD: workingDirectory ?? launchCommand?.workingDirectory<br/>NEW: launchCommand?.workingDirectory ?? workingDirectory
CLI->>CLI: publishAgentSurfaceResumeBinding (params["cwd"])
Note over CLI: OLD: normalizedHookValue(cwd) ?? normalizedHookValue(launchCommand?.workingDirectory)<br/>NEW: normalizedHookValue(launchCommand?.workingDirectory) ?? normalizedHookValue(cwd)
CLI-->>Shell: "cd '/launch/dir' && claude --resume session-id"
Reviews (2): Last reviewed commit: "fix(agent-resume): respect cwd: .ignore ..." | Re-trigger Greptile |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 11478591de
ℹ️ About Codex in GitHub
Your team has set up Codex to 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 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@Sources/RestorableAgentSession.swift`:
- Line 673: The resume template currently backfills {{cwd}} using
launchCommand?.workingDirectory ?? workingDirectory which ignores registrations
that set cwd: .ignore; update the resolution to consult
SessionEntry.resumeWorkingDirectory (the source of truth) instead of falling
back to launchCommand or workingDirectory so registrations that explicitly
ignore cwd suppress cwd usage in resume flows—i.e., use
SessionEntry.resumeWorkingDirectory (and treat its "ignored" value as nil/empty)
when computing the normalized cwd for RestorableAgentSession template
substitution.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 57af8d87-5750-4e28-83c6-226b1c86b089
📒 Files selected for processing (3)
CLI/cmux.swiftSources/RestorableAgentSession.swiftcmuxTests/RestorableAgentHookProviderResumeTests.swift
customResumeArguments backfilled {{cwd}} from launchCommand?.workingDirectory
even when the registration set cwd: .ignore, bypassing the explicit directive
that shellCommand already honored. Compute the cwd up front and suppress it for
.ignore registrations, matching shellCommand's guard.
Move the new resume regression test to a Swift Testing suite per AGENTS.md and
add coverage for the customResumeArguments {{cwd}} path (launch-dir precedence
and .ignore suppression).
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 511cdaec32
ℹ️ About Codex in GitHub
Your team has set up Codex to 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 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| let resolvedCwd = registration.cwd == .ignore | ||
| ? nil | ||
| : normalized(launchCommand?.workingDirectory ?? workingDirectory) |
There was a problem hiding this comment.
Don't blank {{cwd}} when only cd-prefix is ignored
For custom Vault agents, cwd is documented as controlling whether Vault should cd before running resumeCommand, not whether the {{cwd}} template value is available. With cwd: .ignore and a template like tool --resume {{sessionId}} --dir {{cwd}}, this makes the replacement empty; the later empty-token guard returns [], so snapshot.resumeCommand becomes nil. Agents that must avoid a shell cd but still need the saved project path as an argv flag can no longer resume; keep suppressing the prefix in shellCommand but continue filling {{cwd}} from the launch/working directory.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@cmuxTests/RestorableAgentHookProviderResumeTests.swift`:
- Around line 726-730: The test should explicitly assert the nil contract for
resumeCommand when cwd: .ignore and the template contains {{cwd}}; locate the
test that sets cwd: .ignore and currently checks let command =
snapshot.resumeCommand ?? "" and replace or augment that check with an explicit
nil assertion against snapshot.resumeCommand (e.g., XCTAssertNil or the
project’s `#expect` nil form) so the contract that resumeCommand must be nil in
this case is enforced rather than only checking that the string doesn’t contain
paths.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 8e116bf1-01e5-4996-908c-d3753121420c
📒 Files selected for processing (2)
Sources/RestorableAgentSession.swiftcmuxTests/RestorableAgentHookProviderResumeTests.swift
There was a problem hiding this comment.
2 issues found across 3 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
Summary
When the cmux app is closed and reopened, it restores agent sessions by generating a shell command like:
The
cdtarget was the agent's drifted current working directory, not the directory the agent was launched in. Claude Code keys its session transcript to the launch directory, so resuming from a drifted cwd fails hard:This PR makes resume (and fork)
cdback to the launch directory.Root cause
Both resume-command builders resolved the working directory as
workingDirectory ?? launchCommand?.workingDirectory— i.e. they preferred the drifted cwd and only fell back to the launch dir:workingDirectory= the agent's hook-reported current cwd (can drift mid-session).launchCommand?.workingDirectory=CMUX_AGENT_LAUNCH_CWD= the dir the agent was launched in (set by theclaudewrapper to$PWD).For Claude this is fatal because
claude --resume <id>only finds the session in the project directory it was created in (the launch dir). The fork-probe path (AgentForkSupport.openCodeProbeWorkingDirectory) already used the correct precedence — the resume builders were the inconsistent ones.The fix
Flip the precedence to
launchCommand?.workingDirectory ?? workingDirectoryin:Sources/RestorableAgentSession.swiftAgentResumeCommandBuilder.shellCommand(used by bothresumeShellCommandandforkShellCommand)Sources/RestorableAgentSession.swiftcustomResumeArguments{{cwd}}templatecli/cmux.swiftagentSurfaceResumeCommand(thecdin the auto-resume binding)cli/cmux.swiftpublishAgentSurfaceResumeBindingparams["cwd"]metadataScope / blast radius
launchCommand.workingDirectory == workingDirectory→ byte-identical output, zero change. This is why all existing resume tests (gemini/cursor/copilot/codex/…), which set both values equal, pass unchanged.launchCommandabsent (older snapshots / process-scan snapshots): falls back toworkingDirectory→ identical to old behavior, no regression.Tests
testClaudeResumeCommandChangesToLaunchDirectoryNotDriftedCwd) that reproduces the bug (launch dir≠drifted cwd) and asserts the resume commandcds to the launch dir.Verified locally with Xcode 26.5:
(Two-commit red/green structure per the repo's regression-test policy.)
Need help on this PR? Tag
@codesmithwith what you need. Autofix is disabled.Summary by cubic
Resuming and forking now cd into the agent’s launch directory instead of a drifted cwd, fixing failed resumes (e.g., Claude Code “No conversation found”). Custom resume templates also honor
cwd: .ignoreby omitting the cwd.Bug Fixes
launchCommand.workingDirectoryover driftedworkingDirectoryin resume/fork builders and the{{cwd}}template.cdinto the launch dir and publish that ascwdmetadata.{{cwd}}when a custom registration setscwd: .ignore.cwd: .ignore.Tests
claudeResumeCommandChangesToLaunchDirectoryNotDriftedCwd.cwd: .ignore, moved into a Swift Testing suite.Written for commit 511cdae. Summary will update on new commits.
Summary by CodeRabbit
Bug Fixes
Tests