Skip to content

Route Vault resume through cmux restore - #9924

Merged
austinywang merged 9 commits into
mainfrom
issue-9923-vault-resume-restore-verb
Aug 11, 2026
Merged

austinywang merged 9 commits into
mainfrom
issue-9923-vault-resume-restore-verb

Conversation

@austinywang

@austinywang austinywang commented Aug 11, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Vault resumes now use the same shell-free structured restore lifecycle as relaunch restoration from #9265.

  • Every Vault resume entry point (row menus, both popover variants, sidebar surfaces, drag insert, and drag split) builds one SessionEntryResumeLaunch.
  • Supported agents queue only the short cmux restore <kind> <session-id> selector.
  • The restore responder resolves argv, cwd, replay-safe environment, registration metadata, and permission mode from the same SessionRestorableAgentSnapshot used by session relaunch.
  • Existing working-directory placement is preserved: a matching local cwd opens a terminal tab in the focused pane; a different/missing cwd or remote selection creates a workspace.
  • Valid registered/custom agents use structured argv. A kind that cannot be represented by the restore protocol takes an explicit .legacyCommand compatibility strategy.
  • The rendered legacy command builder remains only for Copy Resume Command and that explicit unsupported-kind fallback.

Single lifecycle owner

RestoredAgentLifecycleCoordinator now owns the snapshot, resume phase, and resume working-directory rescue target for both Vault-originated and relaunch-originated restoration. Workspace restore, Dock restore, Vault-created workspaces/tabs/splits, clear, reset, and surface transfer all seed or remove those fields through the same lifecycle operation.

Vault state is seeded immediately after a workspace terminal, focused-pane tab, or split/drop terminal is successfully inserted. Session persistence therefore captures the restored chat before hooks or process scanning run. On close and reopen, the persisted snapshot produces the same short restore selector when automatic agent resume is enabled.

The same seed retains the local session directory while the restored agent owns the terminal, so a transient home/default cwd report cannot poison later split or new-tab inheritance (the #7155 rescue behavior). Registered agents whose cwd policy is .ignore deliberately seed no rescue directory.

The previous immutable TerminalPanel.startupRestoreAgent side channel and responder fallback were removed. Clearing lifecycle state removes responder availability, durable agent state, and cwd rescue together, so an old Vault session cannot resurface after the panel advances to another session.

Package boundary

The Vault adapter remains in the app target because it converts app-owned SessionEntry, AgentSpecifics, registration, and persistence snapshot types for one app consumer. Extracting that adapter alone into a CmuxVaultResume micro-package would duplicate those DTOs and violate cmux's whole-domain/multi-consumer package rule. Reusable shell-free argv and restore planning remains centralized in CMUXAgentLaunch.

Behavior coverage

The app-host behavior suite covers:

  • short restore-selector startup input and structured Codex settings;
  • registered-agent structured argv and cwd preservation;
  • explicit unsupported custom-kind fallback;
  • responder resolution from lifecycle state;
  • lifecycle clear removing responder, persisted state, and cwd metadata;
  • immediate JSON persistence plus close/reopen reconstruction with the same short selector and cwd rescue target;
  • workspace, tab, and split lifecycle seeding;
  • split inheritance from a Vault-restored pane whose tracked cwd was clobbered;
  • the real coordinator's matching-cwd tab placement and different-cwd workspace placement.

The regression tests are wired into the Xcode test target. Repository project, test-wiring, package-group, lockfile, diff, and budget guards pass. Per task constraints, no local xcodebuild tests or XCUITests were run; behavior tests run in CI.

Issue: #9923

Closes #9923

@coderabbitai

coderabbitai Bot commented Aug 11, 2026 •

Copy link
Copy Markdown

Review Change Stack

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

Vault session resume now uses structured restore launches for supported agents. Restore snapshots and startup input propagate through workspace and terminal creation. Unsupported agents use an explicit legacy fallback. Tests cover launch construction, persistence, placement, and copied-command access.

Changes

Structured session resume launch

Layer / File(s) Summary
Resume launch construction
Sources/SessionEntryResumeLaunch.swift, Sources/SessionIndexModels.swift, Sources/HermesAgentIndex.swift
Added structured restore payloads for supported Vault agents, Codex policy arguments, metadata normalization, and explicit legacy fallback. Renamed copied-command access to copyResumeCommand.
Restore-target snapshot resolution
Sources/ControlSurfaceResumeTarget.swift
Restore records retain the selected agent source and working directory.
Resume entry-point integration
Sources/SessionIndexView.swift, Sources/TabManager.swift, Sources/Workspace.swift
Resume and drag-and-drop flows pass structured launch input, working directories, and startup restore agents into workspace creation.
Terminal restore state propagation
Sources/Workspace.swift, Sources/TabManager.swift, cmuxTests/WorkspaceUnitTests.swift
Terminal creation paths accept and seed restorable-agent snapshots for initial terminals, tabs, and split panes.
Resume launch validation and project wiring
cmuxTests/SessionEntryResumeLaunchTests.swift, cmuxTests/*, cmux.xcodeproj/project.pbxproj
Added serialized coverage for structured launches, fallback behavior, persistence, placement, and copied commands. Registered the new source and test files in Xcode targets.

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

Possibly related PRs

Suggested reviewers: lawrencecchen

Sequence Diagram(s)

sequenceDiagram
  participant SessionIndexView
  participant SessionEntryResumeLaunch
  participant TabManager
  participant Workspace
  participant TerminalPanel
  SessionIndexView->>SessionEntryResumeLaunch: build resumeLaunch
  SessionEntryResumeLaunch-->>SessionIndexView: return startup input and restore snapshot
  SessionIndexView->>TabManager: create workspace with launch data
  TabManager->>Workspace: pass startup restore agent
  Workspace->>TerminalPanel: seed input and restored-agent state
Loading
🚥 Pre-merge checks | ✅ 24 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.31% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (24 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The implementation meets #9923 by routing Vault resume through structured restore, preserving placement, supporting fallbacks, and resolving Vault-originated sessions.
Out of Scope Changes check ✅ Passed The changes remain within #9923, including restore lifecycle coordination, workspace plumbing, command renaming, persistence, and related regression tests.
Cmux Swift Actor Isolation ✅ Passed New launch value types are explicitly nonisolated and Sendable; changed Workspace, TabManager, and resume coordinator access remains @MainActor, with no new service protocols or shared Sendable ref...
Cmux Swift Blocking Runtime ✅ Passed The PR production diff adds no semaphores, blocking waits, sleeps, delayed dispatch, polling, main-queue sync, or manual locks; synchronization-related additions are absent.
Cmux Browser Automation Off-Main ✅ Passed The PR adds no browser socket automation changes: neither rule-scoped policy/router files nor browser/WebKit command lines changed, so existing main-actor debt is not worsened.
Cmux Expensive Synchronous Load ✅ Passed The feature diff adds no synchronous history/file loader. resumeLaunch only builds in-memory argv/snapshots; existing RestorableAgentSessionIndex.load() calls remain cache-first fallbacks.
Cmux Cache Substitution Correctness ✅ Passed The PR does not replace a fresh persistence read with a cache; it seeds an explicit Vault restore snapshot, while existing index reads retain warm-cache plus fresh-load fallback logic.
Cmux No Hacky Sleeps ✅ Passed The PR changes only Swift files and Xcode project metadata; it introduces no covered non-Swift runtime files or fixed sleep/timer delays.
Cmux Algorithmic Complexity ✅ Passed The PR adds no nested or per-target scalable scans: the new adapter uses fixed agent cases and a 3-value Set lookup; Workspace changes add O(1) lifecycle seeding, and collection loops are test-only...
Cmux Swift Concurrency ✅ Passed The PR adds no legacy async patterns in production Swift; the only concurrency-related addition is @MainActor on serialized tests, which is valid test isolation.
Cmux Swift @Concurrent ✅ Passed The PR adds no async or @concurrent declarations. New resume planning and terminal-seeding code is synchronous; UI entry points remain @MainActor, with no new heavy async helper called from UI isol...
Cmux Swift Package Boundaries ✅ Passed The new adapter translates app-owned SessionEntry/Vault models into lifecycle snapshots for app resume/drop paths; reusable argv and restore planning remains in CMUXAgentLaunch.
Cmux Swiftpm Lockfiles ✅ Passed cmux.xcodeproj/project.pbxproj only adds source/test file references; no package-reference, manifest, .gitignore, or Package.resolved changes exist. The only ignore is vendored bonsplit policy.
Cmux Swift Logging ✅ Passed The PR adds no print, debugPrint, dump, NSLog, Logger, or ad hoc diagnostic logging in production Swift; existing logs and tabManagerLogger are unchanged, and test fixtures are allowed.
Cmux User-Facing Error Privacy ✅ Passed Production diff adds no user-facing errors, alerts, or recovery copy; searches found no new reporting calls or error text. Added strings are structured launch arguments and internal restore fields.
Cmux Full Internationalization ✅ Passed The PR adds no new user-facing copy or catalog entries; production additions are restore protocol/config data and lifecycle wiring, while the existing Copy Resume label remains localized via sessio...
Cmux Swiftui State Layout ✅ Passed The diff adds no SwiftUI state wrappers, GeometryReader, lazy-row store references, or render-time state writes; SessionIndexView changes only resume callbacks and copy-command handling.
Cmux Architecture Rethink ✅ Passed The launch is an immutable value snapshot; Vault menu and drag paths use resumeLaunch, and Workspace seeds the existing lifecycle coordinator after insertion. No new timing, observer, lock, or poll...
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed The PR adds no standalone window, panel, controller, SwiftUI Window, or close-shortcut workaround; changed NSWindow uses are test fixtures or pre-existing. No lint-relevant assignment appears in So...
Cmux Source Artifacts ✅ Passed All 17 changed paths are intentional Swift source/tests or Xcode project registration; no artifact directories, logs, caches, build output, or non-source artifact extensions appear.
Cmux No Test Or Debug Seam In Production Source ✅ Passed Production diff adds no test/debug guards or test-named members; controlSurfaceRestoreRecord is widened private-to-internal, retains a product caller, and tests use @testable directly without a wra...
Cmux No Ambient Global State ✅ Passed Production additions use constructable SessionEntryResumeLaunch data and SessionEntry methods; no new file-scope API function, mutable global, static-only namespace, or singleton was added.
Description check ✅ Passed The description clearly explains the change, rationale, implementation, behavior coverage, testing scope, and issue linkage, but omits the template checklist and demo video details.
Title check ✅ Passed The title clearly summarizes the primary change: routing Vault resume through the cmux restore lifecycle.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-9923-vault-resume-restore-verb

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.

❤️ Share

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

@austinywang
austinywang marked this pull request as ready for review August 11, 2026 00:03

@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

🤖 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/SessionEntryResumeLaunchTests.swift`:
- Line 140: Update the test setup around controlSurfaceRestoreRecord so it
supplies the Vault startup snapshot environment through the binding instead of
passing nil, allowing the CLAUDE_CONFIG_DIR assertion to validate propagated
state; if the restore contract intentionally excludes this environment, remove
the expectation instead.
🪄 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: dafd4033-eab4-4ca6-b090-a287ffb2f348

📥 Commits

Reviewing files that changed from the base of the PR and between 621164d and bfcfac8.

📒 Files selected for processing (2)
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/SessionEntryResumeLaunchTests.swift

Comment thread cmuxTests/SessionEntryResumeLaunchTests.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)
cmuxTests/SessionEntryResumeLaunchTests.swift (1)

80-91: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Assert the registered-agent working directory.

This test sets cwd to /tmp/custom-project and uses .preserve, but it does not verify launch.workingDirectory. Add the assertion so a regression in registered-agent working-directory propagation cannot pass this test. The PR objective requires this behavior.

Proposed assertion
         let launch = try `#require`(entry.resumeLaunch)
         `#expect`(launch.strategy == .restoreVerb)
+        `#expect`(launch.workingDirectory == "/tmp/custom-project")
         `#expect`(
🤖 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 `@cmuxTests/SessionEntryResumeLaunchTests.swift` around lines 80 - 91, Extend
the test around the existing launch assertions to verify that
launch.workingDirectory preserves the registered agent’s configured
/tmp/custom-project path when cwd is set with .preserve. Keep the existing
restore strategy, input, and resume-argument assertions unchanged.
🤖 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/SessionIndexModels.swift`:
- Around line 300-315: Replace all test references to SessionEntry.resumeCommand
with copyResumeCommand, while leaving unrelated resumeCommand APIs unchanged.
After no tests depend on the compatibility property, remove the resumeCommand
alias from SessionEntry and retain copyResumeCommand as the rendered
shell-command property.

---

Outside diff comments:
In `@cmuxTests/SessionEntryResumeLaunchTests.swift`:
- Around line 80-91: Extend the test around the existing launch assertions to
verify that launch.workingDirectory preserves the registered agent’s configured
/tmp/custom-project path when cwd is set with .preserve. Keep the existing
restore strategy, input, and resume-argument assertions unchanged.
🪄 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: 1365be8d-8099-4ad7-a512-d16a3caef6fe

📥 Commits

Reviewing files that changed from the base of the PR and between bfcfac8 and 63f31dc.

📒 Files selected for processing (10)
  • Sources/ControlSurfaceResumeTarget.swift
  • Sources/HermesAgentIndex.swift
  • Sources/Panels/TerminalPanel.swift
  • Sources/SessionEntryResumeLaunch.swift
  • Sources/SessionIndexModels.swift
  • Sources/SessionIndexView.swift
  • Sources/TabManager.swift
  • Sources/Workspace.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/SessionEntryResumeLaunchTests.swift

Comment thread Sources/SessionIndexModels.swift Outdated
Comment thread Sources/ControlSurfaceResumeTarget.swift
Comment thread cmuxTests/SessionEntryResumeLaunchTests.swift
@austinywang

Copy link
Copy Markdown
Contributor Author

Review follow-up for 78b2492:

  • The registered-agent behavior test now asserts the preserved /tmp/custom-project working directory.
  • SessionEntry.resumeCommand was removed after migrating only that model's test callers; unrelated restore-snapshot and registration APIs remain unchanged.
  • The panel-owned startup snapshot was removed. RestoredAgentLifecycleCoordinator is the sole responder/persistence owner, and tests prove clear-state prevents both socket resolution and later persistence.
  • The Vault adapter intentionally remains in the app target: it consumes app-owned SessionEntry, AgentSpecifics, registration, and persistence types for one consumer. A standalone CmuxVaultResume slice would duplicate those DTOs and conflict with the repository's whole-domain/multi-consumer package rule. The reusable argv and restore planner remains in CMUXAgentLaunch.
  • New non-obvious launch types and fields now have documentation, and the new Swift files remain below 500 lines.

All four inline AI threads have concrete replies and are resolved.

Comment thread Sources/Workspace.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.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 85f460a. Configure here.

Comment thread cmuxTests/SessionEntryResumeLaunchTests.swift
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.

Vault chat history resume bypasses the shell-free cmux restore verb and still types the legacy inline command

1 participant