How the Checkpoint Navigation System in Roo Code Works: Task History and Resumption
Roo Code’s checkpoint navigation system creates lightweight Git checkpoints in a hidden shadow repository, allowing you to save, navigate, and restore task states by rewinding both the workspace and message history without affecting your actual Git repository.
The checkpoint navigation system in Roo Code enables safe experimentation by capturing task states as recoverable snapshots. Implemented in the RooCodeInc/Roo-Code repository, this feature uses an isolated Git-based architecture defined in src/services/checkpoints/ShadowCheckpointService.ts to track changes without polluting your project's version control history, making task resumption reliable and transparent.
Architecture Overview
The system centers on the ShadowCheckpointService class, an abstract service that manages a per-task shadow Git repository. Concrete implementations like RepoPerTaskCheckpointService handle lifecycle instantiation through a static create method that accepts CheckpointServiceOptions (task ID, workspace path, and global storage location).
Key components include:
getCheckpointServiceinsrc/core/checkpoints/index.ts: Lazily initializes the service, handles Git availability checks, and manages UI warnings during initialization timeouts.checkpointSave,checkpointRestore, andcheckpointDiff: Public API functions insrc/core/checkpoints/index.tsthat coordinate between the UI and shadow repository, automatically handling logging and telemetry.- Event-driven updates: The service emits
"initialize","checkpoint", and"restore"events. Listeners registered inindex.ts(around lines 65-90) update the webview and emitcheckpoint_savedchat messages.
Shadow Repository Creation
Each task receives an isolated shadow repository stored in global storage at <globalStorage>/checkpoints/<hash>. The initialization process in ShadowCheckpointService.ts configures your workspace as a Git worktree while keeping metadata completely separate:
await fs.mkdir(this.checkpointsDir, { recursive: true })
const git = createSanitizedGit(this.checkpointsDir)
await git.init({ "--template": "" })
await git.addConfig("core.worktree", this.workspaceDir)
await this.stageAll(git)
const { commit } = await git.commit("initial commit", { "--allow-empty": null })
this.baseHash = commit
The service writes an exclusion file to .git/info/exclude (via writeExcludeFile) to keep Roo Code-specific files like .rooignore out of snapshots. This setup ensures all file operations occur on your actual workspace while Git data remains isolated in the shadow directory.
Saving Checkpoints
When you invoke checkpointSave() or when the system auto-saves, the service stages all workspace changes—including untracked files—and commits them to the shadow repository. The implementation maintains an internal ordered array _checkpoints to track commit hashes:
await this.stageAll(this.git)
const result = await this.git.commit(message, options?.allowEmpty ? { "--allow-empty": null } : undefined)
const fromHash = this._checkpoints.at(-1) ?? this.baseHash!
const toHash = result.commit ?? fromHash
this._checkpoints.push(toHash)
this.emit("checkpoint", { fromHash, toHash, duration, suppressMessage })
The allowEmpty option (exposed as the force argument in checkpointSave) permits creating checkpoints even when no files have changed, ensuring you can mark specific moments in the conversation history.
Restoring Checkpoints and Task Resumption
Restoration involves more than file reversion. The checkpointRestore function in src/core/checkpoints/index.ts coordinates three critical actions:
- Workspace reset: Forces the working tree back to the target commit using
git reset --hardandgit clean -f -d, removing any new files created since the checkpoint. - History truncation: Removes checkpoint entries newer than the restoration point from the internal
_checkpointsarray. - Message rewinding: Discards assistant messages generated after the checkpoint by manipulating
task.clineMessages.
await this.git.clean("f", ["-d", "-f"])
await this.git.reset(["--hard", commitHash])
const idx = this._checkpoints.indexOf(commitHash)
if (idx !== -1) this._checkpoints = this._checkpoints.slice(0, idx + 1)
this.emit("restore", { commitHash, duration })
This ensures that restoring a checkpoint rewinds both your files and the conversation context to that exact moment.
Navigating Task History
The checkpoint navigation system derives its history list from task chat messages rather than querying Git logs directly. Each successful save inserts a message with say: "checkpoint_saved" and text: <commitHash> into task.clineMessages.
To enumerate available checkpoints for the UI:
const checkpoints = task.clineMessages
.filter(m => m.say === "checkpoint_saved")
.map(m => m.text!); // each text is a commit hash
This design ensures the checkpoint history remains synchronized with the conversation timeline visible in the UI, using the message history as the single source of truth for navigation.
Diffing Checkpoints
The checkpointDiff function generates comparisons between any two checkpoints or between a checkpoint and the current workspace. ShadowCheckpointService.getDiff stages current changes temporarily to compute the diff using git.diffSummary and git.show, then presents results using VS Code's native diff view via vscode.changes, showing files side-by-side.
Error Handling and Safety Measures
The system includes several safeguards:
- Git availability: If Git isn't installed, checkpoints are disabled and the UI displays a warning via the webview.
- Nested repository detection: The
getNestedGitRepositorycheck disables checkpoints when nested Git repositories are detected to prevent corruption. - Initialization timeouts: Slow shadow repository creation triggers a
checkpointInitWarningmessage to the webview while the operation continues asynchronously.
Implementation Example
Here is a complete workflow demonstrating the checkpoint navigation system API:
import { checkpointSave, checkpointRestore, checkpointDiff } from "./core/checkpoints";
// Save a checkpoint (force empty commit if you want)
await checkpointSave(task, /*force=*/false, /*suppressMessage=*/false);
// List saved checkpoints (hashes) – UI typically does this:
const savedHashes = task.clineMessages
.filter(m => m.say === "checkpoint_saved")
.map(m => m.text!);
// Restore a previous checkpoint (e.g., the first one)
await checkpointRestore(task, {
ts: task.clineMessages[0].ts, // timestamp of the checkpoint_saved message
commitHash: savedHashes[0],
mode: "restore", // actually revert workspace & task state
});
// Show a diff between two checkpoints
await checkpointDiff(task, {
commitHash: savedHashes[1],
previousCommitHash: savedHashes[0],
mode: "checkpoint", // diff current → next checkpoint
});
All three functions are thin wrappers around the shadow-repo service; they handle service creation, logging, telemetry, and UI notifications automatically.
Summary
- Roo Code's checkpoint navigation system uses isolated shadow Git repositories to snapshot task states without affecting project history, stored under global storage at
<globalStorage>/checkpoints/<hash>. - The
ShadowCheckpointServiceclass insrc/services/checkpoints/ShadowCheckpointService.tsmanages repository initialization, commits, and restorations usingcore.worktreeto target your actual workspace. - High-level APIs in
src/core/checkpoints/index.tsprovidecheckpointSave,checkpointRestore, andcheckpointDifffunctions that handle UI integration and message history synchronization. - Checkpoint history is tracked via
checkpoint_savedmessages intask.clineMessages, enabling the UI to navigate the task timeline reliably. - Restoration rewinds both the file system (via Git hard reset and clean operations) and conversation history (via message truncation), ensuring complete state resumption.
Frequently Asked Questions
How does Roo Code's checkpoint system avoid modifying my project's Git history?
The system creates a separate shadow repository in VS Code's global storage and configures Git's core.worktree setting to point at your actual workspace directory. This ensures all commits, branches, and Git metadata live in the isolated shadow directory, leaving your project's .git directory and history completely untouched.
What happens to my conversation history when I restore a checkpoint?
The checkpointRestore function automatically truncates task.clineMessages to remove any assistant messages generated after the checkpoint's timestamp. This synchronizes the conversation view with the restored workspace state, effectively undoing any AI outputs and file modifications that occurred after the saved point.
Can I create a checkpoint when there are no file changes?
Yes. The checkpointSave function accepts a force parameter that maps to Git's --allow-empty flag. When enabled, the system creates a checkpoint commit even with no file modifications, allowing you to mark specific decision points or conversational milestones in the task history.
Where are the shadow repositories physically stored?
Shadow repositories are stored in your VS Code global storage directory under checkpoints/<hash>/, as defined in the CheckpointServiceOptions passed to the service factory. Each task receives its own isolated directory containing the full Git history for that specific session, completely separate from your workspace file system.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →