# Session Vault & Agent Resume

> The restorable-agent index that scans agent stores, groups sessions by folder or agent, uses SQL for Codex state when available, and supports drag-to-resume workflows.

- Repository: manaflow-ai/cmux
- GitHub: https://github.com/manaflow-ai/cmux
- Human wiki: https://grok-wiki.com/public/wiki/manaflow-ai-cmux-5a511656cb1a
- Complete Markdown: https://grok-wiki.com/public/wiki/manaflow-ai-cmux-5a511656cb1a/llms-full.txt

## Source Files

- `Sources/RestorableAgentTypes.swift`
- `Sources/SessionIndexStore.swift`
- `Sources/SessionIndexStore+CodexSQL.swift`
- `Sources/SessionIndexView.swift`
- `Sources/SessionIndexModels.swift`
- `Sources/SessionAgentPresentation.swift`
- `cmuxTests/RestorableAgentSessionIndexTests.swift`
- `cmuxTests/SessionIndexViewTests.swift`

---

<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [Sources/RestorableAgentTypes.swift](Sources/RestorableAgentTypes.swift)
- [Sources/RestorableAgentSession.swift](Sources/RestorableAgentSession.swift)
- [Sources/SessionIndexStore.swift](Sources/SessionIndexStore.swift)
- [Sources/SessionIndexStore+CodexSQL.swift](Sources/SessionIndexStore+CodexSQL.swift)
- [Sources/SessionIndexView.swift](Sources/SessionIndexView.swift)
- [Sources/SessionIndexModels.swift](Sources/SessionIndexModels.swift)
- [Sources/SessionAgentPresentation.swift](Sources/SessionAgentPresentation.swift)
- [Sources/SessionIndexRegisteredAgents.swift](Sources/SessionIndexRegisteredAgents.swift)
- [Sources/VaultAgentRegistry.swift](Sources/VaultAgentRegistry.swift)
- [Sources/RightSidebarToolPanel.swift](Sources/RightSidebarToolPanel.swift)
- [Sources/Workspace.swift](Sources/Workspace.swift)
- [docs/vault.md](docs/vault.md)
- [docs/agent-hooks.md](docs/agent-hooks.md)
- [cmuxTests/RestorableAgentSessionIndexTests.swift](cmuxTests/RestorableAgentSessionIndexTests.swift)
- [cmuxTests/SessionIndexViewTests.swift](cmuxTests/SessionIndexViewTests.swift)
- [cmuxTests/PiVaultAgentPersistenceTests.swift](cmuxTests/PiVaultAgentPersistenceTests.swift)
</details>

# Session Vault & Agent Resume

Session Vault is cmux's restorable-agent index: a sidebar workflow that scans local agent history stores, normalizes the results into `SessionEntry` rows, groups them by folder or agent, and turns a selected row back into the agent's native resume command. It matters because it treats agent state as portable local data, not as a dependency on one model provider or hosted control plane.

The central product idea is simple: users can find an old Claude, Codex, Grok, OpenCode, Rovo Dev, Hermes, or registered Vault agent session, preview enough context to recognize it, then resume it by menu action, new tab, or drag-to-pane. The implementation keeps the repository code as source of truth; the requested Compound Engineering wiki recipe was used only as page-shape guidance. No `STRATEGY.md` or `docs/solutions/**` source was found in the focused scan.

Sources: [Sources/SessionIndexStore.swift:187-259](), [Sources/SessionIndexModels.swift:255-266](), [Sources/SessionIndexView.swift:49-96](), [docs/vault.md:1-5]()

## Product Workflow

The Vault appears in the right sidebar's sessions mode. `RightSidebarToolPanelView` mounts `SessionIndexView` and wires row resume actions to `SessionEntryResumeCoordinator.resume`, which either opens a terminal surface in the focused pane when the cwd matches or creates a new workspace with the resume command typed and submitted.

Sources: [Sources/RightSidebarToolPanel.swift:265-275](), [Sources/SessionIndexView.swift:8-46]()

```text
Right sidebar: Sessions
  -> group By folder / By agent
  -> optionally scope to current folder
  -> inspect rows, open preview, or Show more
  -> Resume in New Tab or drag row into a pane/split
  -> terminal runs the agent-native resume command
```

The control bar exposes grouping, current-folder scoping, and reload. The list is sectioned, capped at five visible rows per section, and uses a "Show more" popover for deeper search and pagination. Rows support double-click preview, drag, context actions, file reveal/copy, resume command copy, cwd opening, and PR opening when available.

Sources: [Sources/SessionIndexView.swift:98-138](), [Sources/SessionIndexView.swift:362-414](), [Sources/SessionIndexView.swift:542-599](), [Sources/SessionIndexView.swift:650-707]()

## Data Model

`SessionEntry` is the normalized row model. It records the agent, native session id, display title, cwd, git branch, optional pull request, modified time, backing file URL, and agent-specific resume metadata. `SessionAgent` separates built-in agents from registered Vault agents, while `SessionAgentPresentation` maps agents to localized display names and brand icons.

Sources: [Sources/SessionIndexModels.swift:37-75](), [Sources/SessionIndexModels.swift:197-206](), [Sources/SessionIndexModels.swift:255-266](), [Sources/SessionAgentPresentation.swift:3-29]()

| Concept | Implementation | Why it matters |
| --- | --- | --- |
| Built-in session agent | `SessionAgent.builtInCases` | Stable UI ordering for first-party integrations. |
| Registered agent | `SessionAgent.registered(RegisteredSessionAgent)` | BYOC/BYOK-friendly extension point for local or project config. |
| Resume metadata | `AgentSpecifics` | Preserves model, sandbox, approval, config, and agent-specific flags. |
| Section key | `SectionKey.agent` / `SectionKey.directory` | Lets the same entries render by agent or by working folder. |

Registered agents are intentionally portable. `CmuxVaultAgentRegistration` validates an id, display name, detect rule, session id source, resume command, cwd policy, and optional session directory. Config can come from global or project-local `cmux.json`, and built-in Pi, Antigravity, and Grok registrations are loaded through the same registry path.

Sources: [Sources/VaultAgentRegistry.swift:12-88](), [Sources/VaultAgentRegistry.swift:116-152](), [Sources/VaultAgentRegistry.swift:349-365](), [docs/vault.md:30-60]()

## Scan and Search Architecture

`SessionIndexStore` owns the index state: entries, loading, grouping, current-directory scoping, persisted section order, and cached section projections. Reload runs a detached scan, merges agent entries, sorts by modification time, then backfills agent and directory order outside SwiftUI body computations to avoid feedback loops.

Sources: [Sources/SessionIndexStore.swift:187-259](), [Sources/SessionIndexStore.swift:507-523](), [Sources/SessionIndexStore.swift:315-334](), [Sources/SessionIndexStore.swift:336-370]()

```mermaid
flowchart LR
  subgraph UI["UI"]
    SessionIndexView["SessionIndexView"]
    Popover["SectionPopoverView / Show more"]
  end

  subgraph Store["SessionIndexStore"]
    Sections["sectionsForCurrentGrouping"]
    Search["searchSessions"]
    LoadAgents["loadAgents task group"]
  end

  subgraph Sources["Agent stores"]
    Claude["Claude JSONL projects"]
    CodexSQL["Codex state_5.sqlite"]
    CodexDisk["Codex JSONL fallback"]
    OpenCode["OpenCode SQLite snapshot"]
    Registered["Vault registered JSONL/history"]
  end

  SessionIndexView --> Sections
  Popover --> Search
  Search --> LoadAgents
  LoadAgents --> Claude
  LoadAgents --> CodexSQL
  CodexSQL --> CodexDisk
  LoadAgents --> OpenCode
  LoadAgents --> Registered
```

Search is deliberately multi-source. Agent loads run in a task group, then merge into a global modified-time order for directory scopes. `ripgrep` is used when available for fixed-string transcript prefiltering, with a Foundation fallback and cancellation path that terminates active `rg` work when the user changes the query.

Sources: [Sources/SessionIndexStore.swift:1111-1178](), [Sources/SessionIndexStore.swift:1180-1208](), [Sources/SessionIndexStore.swift:1276-1369]()

## Codex SQL First, Disk Fallback

Codex is the most explicit example of "use structured state when available." `loadCodexEntriesViaSQL` snapshots `~/.codex/state_5.sqlite` into a temporary read-only copy, queries the `threads` table for unarchived records, and maps thread rows into `SessionEntry` values with title, cwd, model, branch, approval, sandbox, reasoning effort, rollout path, and update time.

Sources: [Sources/SessionIndexStore+CodexSQL.swift:25-55](), [Sources/SessionIndexStore+CodexSQL.swift:57-83](), [Sources/SessionIndexStore+CodexSQL.swift:90-132](), [Sources/SessionIndexStore+CodexSQL.swift:158-190]()

When SQL is absent or unsupported, Codex falls back to scanning `~/.codex/sessions` JSONL files. The fallback uses `rg` when possible, peeks `session_meta` for cwd rejection before streaming larger files, and caps candidate inspection with `searchMaxFiles`.

Sources: [Sources/SessionIndexStore.swift:1536-1554](), [Sources/SessionIndexStore.swift:1565-1641]()

`SessionIndexViewTests` includes a behavioral test that creates a Codex state database, writes a rollout transcript, and verifies SQL search still matches content found in the rollout file path. That protects the mixed SQL-plus-transcript search path from becoming metadata-only.

Sources: [cmuxTests/SessionIndexViewTests.swift:154-187](), [cmuxTests/SessionIndexViewTests.swift:313-360]()

## Resume Command Construction

Resume is owned by `SessionEntry`, not by the view. The command builder injects agent-specific flags: Claude uses `claude --resume`, Codex uses `codex resume`, Grok uses `grok -r`, OpenCode uses `opencode --session`, Rovo Dev uses `acli rovodev run --restore`, Hermes has its own helper, and registered agents delegate to `AgentResumeCommandBuilder` with the Vault registration.

Sources: [Sources/SessionIndexModels.swift:300-343](), [Sources/SessionIndexModels.swift:344-399]()

```swift
// Sources/SessionIndexModels.swift
var resumeCommandWithCwd: String? {
    guard let command = resumeCommandWithoutWorkingDirectory else { return nil }
    guard let cwd = resumeWorkingDirectory else {
        return command
    }
    return "cd \(Self.shellQuote(cwd)) && \(command)"
}
```

`resumeWorkingDirectory` respects registered-agent cwd policy: a registration with `.ignore` will not force a `cd`, while the default preserves cwd. Shell quoting is centralized, and tests cover Claude config preservation and Grok flag preservation.

Sources: [Sources/SessionIndexModels.swift:268-275](), [Sources/SessionIndexModels.swift:307-313](), [Sources/SessionIndexModels.swift:438-445](), [cmuxTests/SessionIndexViewTests.swift:59-87](), [cmuxTests/SessionIndexViewTests.swift:121-138]()

## Drag-to-Resume

Drag-to-resume is implemented as a bridge into Bonsplit's existing external tab drop path. A row drag registers the `SessionEntry` in a process-wide `SessionDragRegistry`, encodes a synthetic tab-transfer payload with a UUID, and writes only the custom `com.splittabbar.tabtransfer` type so terminal text drop targets do not intercept the gesture.

Sources: [Sources/SessionIndexStore.swift:94-120](), [Sources/SessionIndexView.swift:2527-2604]()

On drop, `Workspace.handleExternalTabDrop` first checks `SessionDragRegistry`. If the UUID belongs to a session row, the workspace spawns a new terminal in the target insert or split destination and submits the resume command. This makes "resume here" a spatial workflow: the user chooses both the session and the pane layout by dragging.

Sources: [Sources/Workspace.swift:15662-15670](), [Sources/Workspace.swift:15366-15390]()

## Restorable Agent Index

Separate from the visible Vault list, `RestorableAgentSessionIndex` loads hook-session stores from `~/.cmuxterm/<agent>-hook-sessions.json` and maps saved records back to workspace/panel keys. It includes built-in restorable kinds plus custom registered agent ids, so project or user registrations participate without changing the enum for every new provider.

Sources: [Sources/RestorableAgentTypes.swift:3-19](), [Sources/RestorableAgentTypes.swift:111-142](), [Sources/RestorableAgentSession.swift:679-808]()

Claude has a stricter restorable check: the hook record must have an explicit transcript path or a discoverable non-empty transcript file. Tests cover records that should restore, records missing transcripts that must not restore, startup-only records with transcripts, and a panel fallback that picks the latest hook record for a moved panel.

Sources: [Sources/RestorableAgentSession.swift:815-891](), [cmuxTests/RestorableAgentSessionIndexTests.swift:11-136](), [cmuxTests/RestorableAgentSessionIndexTests.swift:138-200]()

## Performance and UI Boundaries

The Session Vault code is shaped around SwiftUI invalidation control. `SessionIndexView` builds closure bundles above the lazy-list boundary so row and gap views do not observe `SessionIndexStore` directly. Sections, rows, and gaps are `Equatable` where possible, and drag state lives in a separate `SessionDragCoordinator` to avoid forcing the whole index to re-render on drag transitions.

Sources: [Sources/SessionIndexView.swift:165-251](), [Sources/SessionIndexView.swift:297-330](), [Sources/SessionIndexView.swift:333-360](), [Sources/SessionIndexView.swift:469-539]()

The store also has directory snapshot caching for the "Show more" empty-query path. It loads a large merged snapshot once, sorts it, stores it behind an LRU cache, and discards stale results if a reload races with a snapshot build.

Sources: [Sources/SessionIndexStore.swift:525-586](), [Sources/SessionIndexStore.swift:588-614]()

## Provider-Neutral Extension Pattern

Session Vault is BYOC/BYOK-friendly because the index treats agents as local stores plus resumable commands. Built-ins are conveniences, not a closed architecture. Registered agents can be discovered from `cmux.json`, specify where session ids come from, provide a resume command template, opt into cwd preservation or ignore, and expose their own session directory. The UI falls back to a neutral system icon when no registered brand asset exists.

Sources: [Sources/VaultAgentRegistry.swift:46-88](), [Sources/VaultAgentRegistry.swift:200-309](), [Sources/VaultAgentRegistry.swift:334-365](), [Sources/SessionAgentPresentation.swift:25-37](), [docs/vault.md:53-60]()

For a Grok-Wiki or similar integration, the portable design is to read file, repository, or catalog skill sources as configuration inputs and emit Vault registrations or scan adapters that still resolve to local session ids and local resume commands. Do not bind the feature to a specific hosted model vendor; bind it to stable local artifacts: session directories, SQLite state, JSONL histories, and command templates.

Sources: [Sources/SessionIndexRegisteredAgents.swift:369-464](), [cmuxTests/PiVaultAgentPersistenceTests.swift:80-150]()

## What To Demo or Productize

| Feature | Demo hook | Code path |
| --- | --- | --- |
| SQL-backed Codex search | Search for text only present in a rollout transcript while Codex SQL exists. | `loadCodexEntriesViaSQL` plus rollout content matching. |
| Folder-first recovery | Toggle "This folder only" and group by folder. | `scopeToCurrentDirectory`, `filteredEntriesForCurrentScope`, `SectionKey.directory`. |
| Drag-to-resume | Drag an old row into a split destination. | `sessionDragItemProvider`, `SessionDragRegistry`, `handleSessionDrop`. |
| Registered-agent Vault | Add a `cmux.json` Vault agent with `sessionDirectory` and `resumeCommand`. | `CmuxVaultAgentRegistry.load`, `loadRegisteredAgentEntries`. |
| Safe relaunch resume | Relaunch with hook stores present and stale Claude records missing transcripts. | `RestorableAgentSessionIndex.load`, Claude transcript eligibility tests. |

Sources: [Sources/SessionIndexStore.swift:382-390](), [Sources/SessionIndexStore+CodexSQL.swift:110-132](), [Sources/SessionIndexView.swift:2584-2604](), [Sources/Workspace.swift:15366-15390](), [Sources/RestorableAgentSession.swift:815-832]()

## Summary

Session Vault is a compact but high-leverage pattern: scan agent-owned local state, normalize it into provider-neutral session rows, keep UI grouping and pagination responsive, and resume through each agent's native command rather than replacing the agent runtime. The code already supports built-ins, SQL-backed Codex state, disk fallbacks, registered custom agents, and drag-to-resume workflows, making it a strong candidate for reuse anywhere cmux wants restorable local agent work without assuming a particular model provider or cloud service.

Sources: [Sources/SessionIndexStore.swift:633-649](), [Sources/SessionIndexStore.swift:1243-1274](), [Sources/SessionIndexModels.swift:315-399]()
