Skip to content

feat(chat): optional background rollback checkpoint at agent-run start#91

Merged
Zeus-Deus merged 2 commits into
mainfrom
feature/80-feature-optional-background-rollback-checkpoint-at-agent
Jun 10, 2026
Merged

feat(chat): optional background rollback checkpoint at agent-run start#91
Zeus-Deus merged 2 commits into
mainfrom
feature/80-feature-optional-background-rollback-checkpoint-at-agent

Conversation

@Zeus-Deus

Copy link
Copy Markdown
Owner

Closes #80

Summary

When an agent-chat session starts, take an opt-in, background snapshot of the workspace working tree so the user can roll back everything the run changed. The snapshot adds zero latency to the first token and does not disturb the user's index, worktree, or stash list.

How it works

Snapshot (non-destructive, shadow ref)git stash create ignores untracked files, so git_checkpoint_create instead stages the worktree (tracked + untracked, .gitignore respected) into a temporary GIT_INDEX_FILE, runs write-tree + commit-tree onto HEAD (plumbing — no hooks fire), and anchors the commit at refs/codemux/checkpoints/<thread> so gc can't reap it. The user's real index/worktree/stash are byte-identical afterwards. Non-repos and unborn-HEAD repos are silently skipped.

Background, never on the first-token pathagent_chat_start_session spawns tauri::async_runtime::spawn + spawn_blocking after the provider session is up and the session row is persisted; even the settings-cache read happens inside the spawned task. Failures are logged, never surfaced — a checkpoint must not break (or slow) the chat it protects.

Recorded per run — new agent_chat_checkpoints table (schema v7, FK cascade with agent_chat_sessions) stores snapshot commit, pre-run HEAD, branch, repo path, ref name. On success the backend emits agent_chat_checkpoint so the pane header reveals the restore affordance without polling.

Restore — confirm dialog → agent_chat_restore_checkpoint:

  1. refuses if the snapshot/base commits are gone or the repo is now on a different branch
  2. safety-snapshots the current state to refs/codemux/pre-restore/<thread> (keeps even run-made commits reachable)
  3. read-tree --reset -u <snapshot> + clean -fd (ignored files spared) + reset --mixed <pre-run HEAD>

Result: run commits undone, run-created files deleted, pre-run changes back as unstaged edits, formerly-untracked files untracked again. Known, documented loss: the pre-run staged/unstaged split flattens to unstaged.

Opt-in — Settings → Agent → "Checkpoint before agent runs" (agent_chat.checkpoints_enabled, synced settings, default off; legacy settings blobs deserialize to off).

Pruning — each create prunes both refs/codemux/ namespaces to the 20 newest refs and drops the matching bookkeeping rows, so shadow refs can't grow unboundedly.

UI

  • Restore button (history icon) in the chat pane header — hover-reveal, hidden when no checkpoint exists, disabled while a turn is running
  • Confirm dialog spelling out exactly what restore does, incl. the safety ref
  • Settings toggle in the Agent section (shown with the Agent Chat beta)

Acceptance criteria (issue #80)

  • Starting an agent run adds no latency to the first token (checkpoint is async; nothing git-related on the command path)
  • A rollback point is recorded and restorable
  • The user's existing staged/unstaged state is not disturbed by checkpointing (pinned by test: git status --porcelain byte-identical before/after)
  • The feature is opt-in / clearly controllable (default off)

Testing

  • git helpers (real repos): create doesn't disturb index/worktree/stash; full restore round trip (edits, deletions, new files, run commit undone); linked-worktree round trip (refs shared with main repo, main checkout untouched); branch-mismatch + pruned-snapshot refusal; prune ordering; ref-component sanitization
  • DB: upsert/fetch/replace, FK cascade with session delete, repo-scoped prune deletes
  • Settings: serde round trip + legacy-blob default-off
  • Integration (tests/agent_chat_commands.rs): create→restore round trip through the same blocking helpers the commands call, against real temp repos + in-memory DB; mock-Tauri-runtime e2e of the actual background spawn path (async spawn → blocking pool → real git snapshot → DB write through managed state → agent_chat_checkpoint event), plus the gate-off no-op case
  • Frontend: 1831 vitest tests pass incl. new header restore-flow suite (button visibility, confirm-gated mutation, error toast, disabled mid-turn); tsc clean
  • Live UI smoke (codemux browser + dev mock): restore button renders on the seeded chat, confirm dialog shows branch info, confirming invokes the command with the right thread id and toasts success; settings toggle flips and persists through update_setting
  • Full-suite failures observed are pre-existing environment artifacts of running on a machine with Codemux installed (system agent-browser binary, codemux MCP entry in the real ~/.claude.json, flaky port-reuse test) — none in files this PR touches; each passes with a clean HOME / re-run

Docs

  • Design note: docs/plans/agent-run-checkpoint.md (incl. follow-ups: checkpoint continuity across silent restarts, socket/MCP exposure, per-turn history — out of scope per the issue)
  • docs/features/agent-chat.md § Run checkpoints, docs/core/STATUS.md, docs/INDEX.md

Zeus-Deus added 2 commits June 9, 2026 23:14
Snapshot the working tree when an agent-chat session starts so the
user can roll back everything the run changed (issue #80).

- Checkpoint runs in a spawned background task AFTER the provider
  session is up — no git work (or even the settings-cache read) sits
  on the latency-to-first-token path
- Non-destructive snapshot: stage tracked + untracked changes into a
  temporary GIT_INDEX_FILE, write-tree + commit-tree onto HEAD, anchor
  at refs/codemux/checkpoints/<thread>; the user's index, worktree,
  and stash list stay untouched and no hooks fire
- Record per thread in agent_chat_checkpoints (FK cascade with the
  session row) and emit agent_chat_checkpoint so the pane header can
  reveal the restore affordance without polling
- Restore: pre-restore safety snapshot, read-tree --reset -u, clean
  -fd (ignored files spared), reset --mixed to the pre-run HEAD —
  undoes run commits, deletes run-created files, brings pre-run
  changes back as unstaged edits; refuses on branch mismatch or a
  pruned snapshot
- Opt-in via Settings → Agent → "Checkpoint before agent runs"
  (synced agent_chat.checkpoints_enabled, default off)
- Prune both refs/codemux namespaces to the 20 newest refs per create
  and drop the matching bookkeeping rows
- Restore button (history icon) in the chat pane header with confirm
  dialog, disabled while a turn is running; dev-mock handlers for the
  browser-pane smoke flow
- Tests: git helper round trips incl. linked-worktree case, DB CRUD +
  cascade, settings serde defaults, integration create/restore against
  real repos, mock-runtime background-spawn e2e (event + DB), header
  component tests for the restore flow
…tional-background-rollback-checkpoint-at-agent

# Conflicts:
#	src-tauri/src/lib.rs
#	src/tauri/commands.ts
#	src/tauri/events.ts
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.

[feature] Optional background rollback checkpoint at agent-run start

1 participant