Skip to content

Restoring a remote workspace terminal hands it this machine's working directory - #9855

Open
austinywang wants to merge 34 commits into
mainfrom
fix/remote-restore-local-cwd
Open

austinywang wants to merge 34 commits into
mainfrom
fix/remote-restore-local-cwd

Conversation

@austinywang

@austinywang austinywang commented Aug 9, 2026 •

Copy link
Copy Markdown
Contributor

Supersedes #8634 because that PR's head is fork-owned and cannot be advanced from the required origin branch. Its review history is preserved there.

Review comment closeout

Rechecked at 06985525eeb9859d1aa2d4ed4ad67351b4af7837: all 51 inline review threads have explicit austinywang replies; none is unresolved. Older resolved findings were rechecked against the implementation, and the fork, generic-retargeting, provider-aware shell-sanitization, and final remote-snapshot-policy findings required follow-up fixes and replies. Top-level CodeRabbit, Cubic, Cursor, and Greptile bodies were checked; no Codex review body exists in the complete queried history. The single audit comment records each ask and its disposition.

Summary

  • Fail closed when a remote-workspace agent restore has no trusted remote cwd: only authoritative restored remote provenance may select the far-host directory.
  • Preserve an exact nil cwd through built-in, custom-agent, and relaunch command construction instead of silently consulting the agent or launch snapshot again.
  • Keep generic directory reports rejected for trust-required remote panels. Generic restore/transfer retargeting cannot create remote provenance or overwrite an exact policy.
  • Preserve unavailable policy during ordinary replay. A new independently authenticated binding follows a separate update path; a later cwd value alone does not revive a matching unavailable recipe.
  • Add behavior regressions and a non-tolerant focused CI invocation so Swift Testing assertion failures in this security boundary cannot be masked by the broad sharded wrapper.

Current-HEAD verification

  • Red proof: hosted run 34570948675, test-only commit c1c4d1b90fd5fc1dcdf469f55e8ab8932e808c18, compiled and executed seven tests and failed on 24 intended behavioral assertion issues.
  • Green proof: hosted run 34656327498 checked out 06985525eeb9859d1aa2d4ed4ad67351b4af7837 and passed all seven intended tests, including exact-nil/unavailable fork argv, generic retargeting, Kimi/Qoder cwd flags, and Claude Teams worktree preservation.
  • Hosted standalone verification: run 34663834210 checked out exact SHA 06985525eeb9859d1aa2d4ed4ad67351b4af7837 and passed the unchanged GhosttyTerminalViewVisibilityPolicyTests suite. This independently disproved the first shard's portal-visibility assertion as a deterministic PR regression.
  • Full current-HEAD CI: run 34656298316 completed successfully. All required jobs are green, including six app-host shards, Release, and final tests.
  • Static guards pass: Swift file budgets (68 changed files), diff whitespace, pbxproj normalization, test wiring (879 files), strict test determinism, package lockfile policy, and workspace package grouping. No budget TSV was modified.
  • origin/main at c006e64ae30c2a33fbe1abf337eb848f1f240743 is included in HEAD. The branch and existing clone were preserved; no worktree was created.

Trade-offs and remaining dogfood

  • Fail closed instead of guessing: exact-nil never uses a captured/local cwd, generic cwd does not confer remote trust, and unavailable replay stays unavailable. Independently authenticated registration and explicit fork-destination selection remain distinct actions.
  • Custom Vault names may match native provider names; ambiguous profile flags are preserved without matching native provenance. Native snapshots use provider-specific cwd rules.
  • Existing coupled XCTest suites were not broadly migrated; new pure policy coverage uses Swift Testing. Lifecycle helpers were extracted unchanged into small companions to meet existing Swift budgets.
  • The browser install was slow, not a proven code failure. It completed as a cancellation landed; interrupted downstream jobs were rerun without weakening checks or repeating successful preflight work.
  • CI failure disclosure: app-host shard 6 initially failed at the unchanged portal-visibility regression, but the exact suite passed in standalone hosted verification. A single authenticated rerun of shard 6 (103474014046) passed, followed by green aggregate tests/ci-status; no assertion was weakened and no source change was needed.
  • No local Xcode/Swift compilation or tests ran. The mandated cloud reload was attempted behind the queue lock, but the helper rejects the required full branch tag: invalid tag 'fix/remote-restore-local-cwd'; use letters, numbers, dot, underscore, hyphen. No tagged app launched. Interactive relaunch/SSH dogfood at this HEAD is not personally verified; older-head dogfood is not current-HEAD evidence. This is not a visual redesign, and no new screenshot/demo is claimed.
  • No user-facing strings or shortcuts were added in the fixes. Localization audit: notification help text is unchanged from main, and localization catalogs/shortcut settings are not changed by this PR.
CMUX_SKIP_ZIG_BUILD=1 /Users/austinwang/manaflow/cmuxterm-hq/scripts/reload-cloud.sh --tag fix/remote-restore-local-cwd --launch

This PR touches iOS/shared mobile code and is left open for Austin to dogfood and merge. Current-HEAD device/Simulator dogfood of the iOS provider-absence behavior was not performed in this continuation. No issue was closed; GitHub currently returns no closing-issue references for this PR.

Checklist

  • Current-HEAD interactive relaunch/SSH dogfood completed (blocked by the required full-tag validation above).
  • Hosted behavioral regression red/green proof completed with seven intended tests executed.
  • No user-facing strings were added; localization catalogs require no changes.
  • Docs and changelog changes are not needed for this internal correctness fix.
  • Required CI green at 06985525ee (run 34656298316).
  • All 51 inline threads explicitly replied to; top-level review bodies addressed.
  • CLA checks passed.
  • Austin approval and merge (iOS/shared-mobile no-self-merge exception).

Note

High Risk
Changes security-sensitive session restore and remote SSH resume paths where incorrect cwd replay could launch agents in the wrong directory; broad touch across binding persistence, sanitization, and deferred auto-resume.

Overview
Fixes remote and persistent-SSH agent restores replaying this machine’s captured cwd instead of an authenticated remote directory.

The PR introduces AgentRestoreWorkingDirectorySelection (recorded fallback, exact, unavailable) and persists it on surface resume bindings and restorable agent snapshots. Resume, relaunch, fork, control-surface records, and startup input now fail closed when policy is unavailable or unscoped on remote agent hooks, and exact nil cwd no longer falls back to snapshot/launch captures. When policy is exact, captured argv cwd flags are stripped using a new per-built-in-agent AgentWorkingDirectoryOptionPolicy (Codex -C, Kimi/Qoder -w, Cursor vs Qoder --workspace, conservative behavior for custom agents).

Dock/workspace binding updates inherit or refresh cwd policy across execution locations (local vs persistent-SSH PTY identity), block restore claims across mismatched launchFlavor, and gate deferred remote auto-resume on exact remote selection. Persistent-SSH attach only embeds agent startup when cwd is exact; legacy hook bindings without policy invalidate the restore recipe. Smaller related fixes: terminal hibernation before a native Ghostty surface exists, mobile terminal lanes failing without a provider, and CI adding non-tolerant regressions for these restore boundaries.

Reviewed by Cursor Bugbot for commit 0698552. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by CodeRabbit

  • Bug Fixes

    • Improved agent session restoration with trusted working-directory handling.
    • Fixed resume, relaunch, fork, hibernation, and remote SSH restores when directories are unavailable or reconstructed.
    • Preserved valid worktree options while removing stale or duplicate directory arguments.
    • Prevented unsafe remote auto-resumes and duplicate restoration attempts.
    • Preserved restoration settings across saved sessions and remote binding updates.
  • Tests

    • Added coverage for local and remote restoration, agent-specific options, persistence, SSH reattachment, and auto-resume behavior.

@coderabbitai

coderabbitai Bot commented Aug 9, 2026 •

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

We couldn't safely recover the incremental review. No full review was started, and the last reviewed checkpoint was preserved. Retry later, or explicitly request a full review by commenting @coderabbitai full review.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR adds persisted working-directory selection policies for agent restore. It updates launch-option sanitization, resume and fork command generation, remote session restoration, persistent SSH reattachment, auto-resume, hibernation, and regression tests.

Changes

Remote restore working-directory flow

Layer / File(s) Summary
Selection and launch-option sanitization
Packages/macOS/CMUXAgentLaunch/..., CLI/...
Adds agent-specific option policies, restore selection states, directory resolution, and sanitization for split, attached, missing-value, and post--- options.
Resume and fork command generation
Sources/RestorableAgentSession.swift, Sources/AgentRelaunchCommandBuilder.swift, Sources/AgentForkSupport.swift, Sources/RestorableAgentTypes.swift, Sources/SessionIndexModels.swift
Converts AgentResumeCommandBuilder to an instance-based builder. Resume and fork commands use resolved selections and can discard captured working-directory options.
Snapshot and binding policy persistence
Sources/SessionPersistence.swift, Sources/ControlSurfaceResumeTarget.swift, Sources/SessionRestorableAgentSnapshot+Commands.swift, Sources/SurfaceResumeCommandCanonicalizer+PortableAgentExecutable.swift, Sources/SurfaceResumeBindingSnapshot+Remote.swift
Persists working-directory selections and applies them to resume arguments, inline startup input, surface bindings, and remote binding migration.
Remote restore and resume integration
Sources/Workspace.swift, Sources/Workspace+RemoteSurfaceResumeBinding.swift, Sources/TabManager.swift, cmuxTests/..., .github/workflows/ci.yml
Applies trusted remote directories to retained snapshots, controls auto-resume and hibernation, limits persistent SSH startup input, updates snapshot hashing, and adds focused app-host regression coverage.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

  • manaflow-ai/cmux#8441: Extends remote resume-binding and SSH restore infrastructure used by this change.

Suggested reviewers: lawrencecchen, azooz2003-bit

Sequence Diagram(s)

sequenceDiagram
  participant Workspace
  participant RestoreSnapshot
  participant ResumeBuilder
  participant RemoteBinding
  Workspace->>RestoreSnapshot: retain trusted working-directory selection
  RestoreSnapshot->>ResumeBuilder: resolve directory and sanitize launch options
  ResumeBuilder->>RemoteBinding: provide constrained startup input
  RemoteBinding-->>Workspace: restore or suppress remote resume
Loading

Merge Risk: 🔵 Low · up to f38a4

The change is mergeable with owner follow-up for a bounded localization issue: the notification command still hardcodes one label and does not provide the new help text in all supported locales, which can cause inconsistent user-facing output.


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.41% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 111 functions across 19 files. (3 skipped… Write docstrings for the functions missing them to satisfy the coverage threshold.
Cmux No Ambient Global State ❓ Inconclusive Investigation in progress; no final assessment yet. Awaiting code and diff inspection.
✅ Passed checks (23 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Swift Actor Isolation ✅ Passed No changed production code matches the actor-isolation failure conditions. The new AgentRestoreWorkingDirectorySelection and AgentWorkingDirectoryOptionPolicy types are immutable value types that …
Cmux Swift Blocking Runtime ✅ Passed PASS. The aggregate PR diff from merge-base ba47b1dc0 to f38a4286f adds no production Swift use of DispatchSemaphore, blocking waits, sleeps, delayed dispatch, timers, polling, main-queue sync, …
Cmux Browser Automation Off-Main ✅ Passed PASS: The pull request does not change browser socket automation routing. The diff against origin/main contains no browser, WebKit, TerminalController, or ControlCommandExecutionPolicy implement…
Cmux Expensive Synchronous Load ✅ Passed PASS: The PR does not add or move an expensive synchronous agent-history load. The only RestorableAgentSessionIndex.load() calls in Sources/Workspace.swift and Sources/TabManager.swift are uncha…
Cmux Cache Substitution Correctness ✅ Passed No cache-substitution failure is introduced. The snapshot path still reads the current RestorableAgentSessionIndex observation and only reapplies a retained working-directory policy after matching a…
Cmux No Hacky Sleeps ✅ Passed PASS: The pull request changes Swift production code and one .github/workflows/ci.yml workflow. The rule explicitly excludes GitHub Actions YAML, and the diff contains no changed TypeScript, JavaScr…
Cmux Algorithmic Complexity ✅ Passed PASS. The diff does not introduce a stated algorithmic-complexity failure. AgentLaunchSanitizer makes one linear pass over argv; its first(where:) checks scan only the fixed agent-option policy. `…
Cmux Swift Concurrency ✅ Passed PASS: The PR does not introduce a listed legacy Swift concurrency pattern. The changed restore and command-builder code is synchronous. The added-line audit for the summarized PR paths found no new Di…
Cmux Swift @Concurrent ✅ Passed PASS: The PR diff introduces no @concurrent annotation, no new nonisolated async function, and no changed async declaration. The changed calls in AgentForkSupport remain synchronous builder prob…
Cmux Swift Package Boundaries ✅ Passed PASS: The changed reusable working-directory policy is isolated in the existing CMUXAgentLaunch SwiftPM target. AgentRestoreWorkingDirectorySelection, AgentWorkingDirectoryOptionPolicy, and the …
Cmux Swiftpm Lockfiles ✅ Passed PASS: The PR changes only the workflow and Swift source/tests. The diff contains no Package.swift, Package.resolved, .gitignore, or Xcode project/workspace package-reference changes. The new workflow …
Cmux Swift Logging ✅ Passed PASS — The PR diff from the pre-change main parent adds no print, debugPrint, dump, NSLog, Logger, os_log, or ad hoc stdout/file diagnostic logging in Swift. It only changes working-direct…
Cmux User-Facing Error Privacy ✅ Passed The pull request does not add or materially change user-facing error text, alerts, command output, API error bodies, or recovery copy. The production diff adds restore-policy and argv-sanitization log…
Cmux Full Internationalization ✅ Passed PASS — The diff from ba47b1dc0 to f38a4286f adds restore-policy and command-sanitization logic. It does not add or change user-facing text. New literals are agent command/config tokens such as `--…
Cmux Swiftui State Layout ✅ Passed PASS: The PR does not introduce or materially expand SwiftUI state or layout patterns covered by the rule. The added lines contain no @Observable, @Published, ObservableObject, @StateObject, `…
Cmux Architecture Rethink ✅ Passed PASS: The diff does not introduce the architectural failure patterns in the rule. Added production code has no new sleeps, delayed dispatch, polling, locks, notification observers, singleton coordinat…
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PASS. The PR does not add or materially change a standalone user-visible cmux auxiliary window. The only added NSWindow-related code is test-only fixture setup in cmuxTests, including main workspace t…
Cmux Source Artifacts ✅ Passed PASS. The PR changes only CI configuration, Swift source, and Swift test files. The three added paths are two hand-written source files and one test file. No changed path is an artifact, cache, build-…
Cmux No Test Or Debug Seam In Production Source ✅ Passed PASS. The PR changes production Swift restore and sanitization logic, but the production-only diff adds no #if DEBUG/test-build seam and no member named debug…, …ForTesting, …ForTests, `testOn…
Title check ✅ Passed The title clearly identifies the primary fix: preventing remote workspace restoration from using the local machine's working directory.
Description check ✅ Passed The description provides a detailed summary, testing evidence, review status, checklist, risks, and known limitations. It omits the template's explicit Demo Video and Review Trigger sections, but the …
Full details: Docstring Coverage

Explanation

Docstring coverage is 14.41% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 111 functions across 19 files. (3 skipped: 1 unsupported, 2 too large.)

✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
⚔️ Resolve merge conflicts 💡
  • Resolve merge conflict in branch fix/remote-restore-local-cwd
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/remote-restore-local-cwd

Comment @coderabbitai help to get the list of available commands.

Comment thread Sources/Workspace.swift

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 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/AgentSessionAutoResumeSwiftTests.swift`:
- Around line 2259-2268: Update the remote command validation around
TerminalStartupWorkingDirectoryPrefix.shellWordRanges so each required step uses
test failure semantics rather than optional branching: require the --command-b64
token index, its following argument, successful base64 decoding, and UTF-8
conversion. Keep the existing assertions that the decoded remoteCommand excludes
unsafeStartupPayload and capturedDirectory, ensuring any malformed or missing
payload fails the test.
- Around line 2453-2536: The withRestoredRemoteSurface helper must stop mutating
UserDefaults.standard for
AgentSessionAutoResumeSettings.autoResumeAgentSessionsKey. Inject or expose a
test-scoped defaults store through Workspace and the restore path so
AgentSessionAutoResumeSettings.isEnabled(defaults:) reads the helper’s value
without affecting other tests; retain the existing AppDelegate.shared and active
tab-manager scoping.

In
`@Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentWorkingDirectoryOptionPolicy.swift`:
- Around line 26-37: Normalize the trimmed agent kind to lowercase before the
switch in the working-directory option policy. Update the policy logic around
AgentWorkingDirectoryOptionPolicy and its agentKind handling so case variants
such as Codex, Kimi, and Qoder select the same -C or -w options as their
lowercase identifiers, while preserving the generic fallback for other kinds.
🪄 Autofix

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 Plus

Run ID: 3c6316e0-98e6-4498-89dc-4c333439d0c5

📥 Commits

Reviewing files that changed from the base of the PR and between f9a29b4 and c587a05.

📒 Files selected for processing (23)
  • .github/workflows/ci.yml
  • CLI/CMUXCLI+SessionsListForkStartupInput.swift
  • CLI/cmux.swift
  • Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchSanitizer.swift
  • Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentRestorePlanner.swift
  • Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentRestoreWorkingDirectorySelection.swift
  • Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentWorkingDirectoryOptionPolicy.swift
  • Packages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentLaunchSanitizerTests.swift
  • Packages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentRestoreWorkingDirectorySelectionTests.swift
  • Sources/AgentForkSupport.swift
  • Sources/AgentRelaunchCommandBuilder.swift
  • Sources/ControlSurfaceResumeTarget.swift
  • Sources/RestorableAgentSession.swift
  • Sources/RestorableAgentTypes.swift
  • Sources/SessionIndexModels.swift
  • Sources/SessionRestorableAgentSnapshot+Commands.swift
  • Sources/TabManager.swift
  • Sources/Workspace+RemoteSurfaceResumeBinding.swift
  • Sources/Workspace.swift
  • cmuxTests/AgentSessionAutoResumeSettingsTests.swift
  • cmuxTests/AgentSessionAutoResumeSwiftTests.swift
  • cmuxTests/PiVaultAgentPersistenceTests.swift
  • cmuxTests/SessionPersistenceTests.swift

Comment thread cmuxTests/AgentSessionAutoResumeSwiftTests.swift Outdated
Comment thread cmuxTests/AgentSessionAutoResumeSwiftTests.swift Outdated
@austinywang

Copy link
Copy Markdown
Contributor Author

Review closeout on 861d4e0: the cache-substitution finding is fixed in a53848c by persisting the authoritative cwd trust selection directly on SurfaceResumeBindingSnapshot. persistentSSHResumeCommand now consults that persisted binding policy rather than restoredAgentSnapshotsByPanelId: unavailable selections issue only a require-existing PTY reattach with no reconstructed agent startup payload, while exact selections embed the constrained, cwd-sanitized startup input. Focused behavior tests cover both paths and binding Codable persistence. The docstring item is intentionally limited to public policy APIs and non-obvious trust-boundary helpers, which are documented; adding boilerplate to private test helpers and straightforward app composition would not improve the API contract.

Comment thread Sources/ControlSurfaceResumeTarget.swift Outdated
Comment thread cmuxTests/RemoteResumeBindingTests.swift
Comment thread cmuxTests/SessionPersistenceTests.swift Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Sources/TabManager.swift (1)

5933-5933: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Hash restoreWorkingDirectorySelection on the resume binding too.

Line 5933 adds the selection to the restorable-agent fingerprint. hashSurfaceResumeBindingSnapshot does not hash the equivalent field, yet SurfaceResumeBindingSnapshot now persists restoreWorkingDirectorySelection, and SessionPersistenceResumeBindingTests.restoreWorkingDirectorySelectionRoundTripsAndFailsClosed asserts it round-trips.

A binding can change only its selection while kind, checkpointId, command, cwd, and launchCommand stay equal. Workspace.setSurfaceResumeBinding produces exactly that case: inheritingRestoreWorkingDirectorySelection(from:) copies command, cwd, and launchCommand from the previous binding and changes only the selection. The autosave fingerprint then does not move, and the autosave timer skips the write. The persisted binding keeps the stale trust policy, so the next restore can replay an untrusted local working directory.

🐛 Proposed fix
         hashOptionalString(snapshot.permissionMode, into: &hasher)
         hasher.combine(snapshot.allowsAutomaticResume)
         hasher.combine(snapshot.launchFlavor)
+        hasher.combine(snapshot.restoreWorkingDirectorySelection)
         if snapshot.isProcessDetected {

Also applies to: 5979-6005

🤖 Prompt for 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.

In `@Sources/TabManager.swift` at line 5933, Update
hashSurfaceResumeBindingSnapshot to include restoreWorkingDirectorySelection in
the resume binding fingerprint, matching the existing restorable-agent hashing.
Ensure selection-only changes produced by
inheritingRestoreWorkingDirectorySelection and setSurfaceResumeBinding alter the
autosave fingerprint so the updated binding is persisted.
🤖 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/SessionRestorableAgentSnapshot`+Commands.swift:
- Around line 238-276: Update
SurfaceResumeBindingSnapshot.applyingRestoreWorkingDirectorySelection to clear
constrained.command alongside constrained.cwd and constrained.launchCommand in
both early-return paths: when selection.permitsResume is false and when
constrainedAgent.resumeCommand(...) returns nil. Preserve the existing command
assignment on the successful path.

---

Outside diff comments:
In `@Sources/TabManager.swift`:
- Line 5933: Update hashSurfaceResumeBindingSnapshot to include
restoreWorkingDirectorySelection in the resume binding fingerprint, matching the
existing restorable-agent hashing. Ensure selection-only changes produced by
inheritingRestoreWorkingDirectorySelection and setSurfaceResumeBinding alter the
autosave fingerprint so the updated binding is persisted.
🪄 Autofix

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 Plus

Run ID: df2bcb69-0dc4-4750-9faf-667309bed2ac

📥 Commits

Reviewing files that changed from the base of the PR and between c587a05 and 9b67c73.

📒 Files selected for processing (15)
  • Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentRestoreWorkingDirectorySelection.swift
  • Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentWorkingDirectoryOptionPolicy.swift
  • Packages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentLaunchSanitizerTests.swift
  • Packages/macOS/CMUXAgentLaunch/Tests/CMUXAgentLaunchTests/AgentRestoreWorkingDirectorySelectionTests.swift
  • Sources/ControlSurfaceResumeTarget.swift
  • Sources/SessionPersistence.swift
  • Sources/SessionRestorableAgentSnapshot+Commands.swift
  • Sources/SurfaceResumeCommandCanonicalizer+PortableAgentExecutable.swift
  • Sources/TabManager.swift
  • Sources/Workspace+RemoteSurfaceResumeBinding.swift
  • Sources/Workspace.swift
  • cmuxTests/AgentSessionAutoResumeSwiftTests.swift
  • cmuxTests/RemoteResumeBindingTests.swift
  • cmuxTests/SessionPersistenceResumeBindingTests.swift
  • cmuxTests/SessionPersistenceTests.swift

Comment thread Sources/SessionRestorableAgentSnapshot+Commands.swift

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale Bugbot comment from a previous run.

Comment thread Sources/Workspace+RemoteSurfaceResumeBinding.swift Outdated
Comment thread Sources/SurfaceResumeBindingSnapshot+Remote.swift
@cursor

cursor Bot commented Aug 25, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@greptile-apps

greptile-apps Bot commented Aug 25, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR introduces a persisted trust policy for agent restore working directories so remote restores use only authoritative remote cwd provenance and otherwise fail closed.

  • Propagates exact, fallback, and unavailable cwd selections through snapshots, bindings, resume/fork construction, persistence, and persistent SSH reattachment.
  • Adds agent-specific cwd-option sanitization to prevent captured local directory flags from leaking into restored commands.
  • Adds focused regression coverage and a non-tolerant CI invocation for the remote restore boundary.

Confidence Score: 5/5

The PR appears safe to merge because no blocking failure remains in the reviewed remote restore and persistent SSH paths.

No blocking failure remains.

Important Files Changed

Filename Overview
Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentRestoreWorkingDirectorySelection.swift Defines the persisted fallback, exact, and unavailable cwd trust states and their restriction and refresh behavior.
Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchSanitizer.swift Extends cwd argument removal to support agent-specific options and unconditional removal at exact or unavailable trust boundaries.
Sources/SessionRestorableAgentSnapshot+Commands.swift Applies cwd trust selections consistently while constructing persisted resume, fork, and launch-command state.
Sources/Workspace.swift Derives authoritative remote cwd policy during restoration and gates auto-resume, binding retention, and continuation state accordingly.
Sources/SurfaceResumeBindingSnapshot+Remote.swift Registers authenticated persistent SSH bindings with constrained cwd provenance and supports safe transport-only reattachment.
Sources/ControlSurfaceResumeTarget.swift Constrains structured control-surface restore records and omits unsafe legacy command fallbacks.
Sources/SessionPersistence.swift Persists the cwd trust policy on both restorable agent snapshots and surface resume bindings.
.github/workflows/ci.yml Adds a focused non-tolerant test invocation for remote agent restore cwd regressions.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Persisted remote terminal snapshot] --> B{Authoritative remote cwd available?}
  B -->|Yes| C[Store exact cwd selection]
  B -->|No, cwd-independent agent| D[Store exact nil selection]
  B -->|No, directory-keyed agent| E[Store unavailable selection]
  C --> F[Strip captured cwd arguments]
  D --> F
  E --> G[Suppress agent startup replay]
  F --> H[Build constrained resume or fork command]
  G --> I[Retain authenticated SSH transport reattach only]
  H --> J[Restore remote agent]
Loading

Reviews (7): Last reviewed commit: "Keep binding authority through command r..." | Re-trigger Greptile

@cursor

cursor Bot commented Aug 25, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

2 similar comments
@cursor

cursor Bot commented Aug 28, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@cursor

cursor Bot commented Aug 28, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@vercel

vercel Bot commented Aug 28, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
cmux166 Ready Ready Preview Sep 11, 2026 11:12pm UTC
cmux41 Ready Ready Preview Sep 11, 2026 11:12pm UTC

@cursor

cursor Bot commented Aug 28, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@cursor

cursor Bot commented Sep 15, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@cursor

cursor Bot commented Sep 15, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@cursor

cursor Bot commented Sep 16, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@cursor

cursor Bot commented Sep 16, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@lawrencecchen

Copy link
Copy Markdown
Contributor

Mac fleet instructions for head ac8665577f785eb0b5b44f2a369a3173849bce1a. Planned tag: pr-9855-ac866557; this is not yet a published build.

JOB_JSON=$(~/.local/bin/cmux-ci submit --kind cmux --command 'CMUX_FLEET_BUILD_TAG=pr-9855-ac866557 /Users/Shared/cmux-build-fleet/recipes/cmux.sh https://github.com/manaflow-ai/cmux.git ac8665577f785eb0b5b44f2a369a3173849bce1a' --artifact artifacts/cmux.app.zip --workspace https://github.com/manaflow-ai/cmux/pull/9855 --source-digest ac8665577f785eb0b5b44f2a369a3173849bce1a --cache-key cmux:pr-9855 --min-free-bytes 268435456000 --label cmux --label ram48)
JOB_ID=$(python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])' <<<"$JOB_JSON")
~/.local/bin/cmux-ci wait "$JOB_ID" --receipt artifacts/fleet/$JOB_ID.json
~/.local/bin/cmux-ci publish-hq "$JOB_ID"

Use an existing campaign job ID if one is already posted; do not submit a duplicate. A wait timeout leaves the remote job running. Published results will include an exact-head artifact link and timing/disk receipt. This recipe validates the macOS app only, not iOS or tests. Never use maclease or put credentials in a PR comment.

This branch was successfully deployed

2 active (outdated) deployments
Preview – cmux166 — 06985525 Deployed Sep 11, 2026 by vercel[bot]
Preview – cmux41 — 06985525 Deployed Sep 11, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants