What It Does
A snapshot captures a workspace as a single tar file: mount configs, sessions, history, finished jobs, cache bytes, and one fingerprint per recorded remote read. Loading a snapshot reconstructs the workspace and verifies that the underlying sources have not drifted since capture. When the backend exposes a stable per-object revision marker (S3VersionId, Drive revisionId, Git commit SHA), the snapshot also records that revision. At load time, reads pin to the recorded revision and serve the exact bytes the original agent saw, even if the live object has since been overwritten.
The API
ws.snapshot() answers the tar as a Uint8Array, Workspace.load(snapshotBytes) takes it back, and Workspace.fromState(...) restores a state object; saving the bytes to a file or download target is the application’s responsibility.
Both snapshot and copy are async because they serialize workspace state and collect recorded fingerprints.
copy also keeps the workspace’s profiles, default profile, and command limits. Policy objects and the route policy are not copied; add them to the copy again if it needs them.
An S3-like store
A snapshot can go to an S3-like store instead of a file. Pass anS3Config, the one the S3 mount takes, so S3, R2, MinIO and other S3-compatible stores all work; the key becomes the object key, under the config’s key_prefix.
build_app(snapshot_store=...), buildApp({ snapshotStore })), named by a key.
What Is And Isn’t Captured
Captured
- Mount configs (creds redacted; restore via
mounts=override) - Sessions, history, finished jobs
- Cache bytes for touched paths
- One fingerprint per remote read (ETag-equivalent)
- Optional per-path
revisionwhen the backend exposes one
Not captured
- Live state of mounts with
supports_snapshot=False(Gmail, Slack, Linear, Notion, …) - Files the agent never touched
- Raw bytes of remote objects (recoverable only via revision pin)
Drift Detection
On the firstdispatch or shell after load, Mirage stats every fingerprinted path against the live source in parallel. If any path’s live fingerprint differs from the recorded one, the workspace raises ContentDriftError:
Drift Policies
Pass via
await Workspace.load(..., drift_policy=DriftPolicy.OFF).
How It Composes With Caching
Snapshots interact with two existing caches:
Only files the agent actually read are fingerprinted. Capture walks
ws._ops.records for op == "read" and dedups by path. Files that were listed but never opened, or touched only by stat / readdir, do not carry a fingerprint or a revision.
At load time, three pieces of restored state cooperate per read:
- Cache is consulted first. Snapshot bytes go back into
Workspace._cache; a warm read returns them with no network round-trip. - Fingerprint verifies the cache. Under STRICT, the eager drift check stats every recorded path against live and raises before any read fires if anything moved. The cache is therefore trusted as authoritative until proven stale.
- Revision pin is the cold-path recovery. When the cache misses and the backend supports pinning, reads fetch the exact recorded revision (S3
GetObject(VersionId=...)) so you still get original bytes, not the live head.
The cache is the optimization, the fingerprint is the verifier, and the pin is the recovery — three independent guarantees that “what you replay equals what you captured.”
VFS Support Matrix
Remote drift detection is opt-in per VFS throughsupports_snapshot in Python and supportsSnapshot in TypeScript. A working adapter must also attach a fingerprint to each read record; a revision is optional and enables pinned replay.
Legend: ✅ = implemented · 🟡 = VFS opts in, but recorded reads do not yet carry the fingerprint · ❌ = live-only · — = unavailable in that runtime.
Remote VFS
Local State
RAM, Disk, and Redis serialize their VFS state into the snapshot. They do not need a remote drift check or revision pin: replay restores the captured state directly. Credentials and connection details remain redacted and may require a VFS override at load time.Extending To A New Backend
Three steps in Python:record so the snapshot
captures whatever the backend served:
mount.revisions — no per-VFS hook required. If your backend
has no stable revision, skip steps 3 and 6; drift detection still
works on the fingerprint alone.
Caveats
- Revision longevity. Pinned reads only work as long as the source still retains the recorded revision. S3 bucket lifecycle rules can age out old versions; Drive keeps revisions for 30 days on non-Workspace files. Treat pins as best-effort.
- First read after load is slower than the rest.
Workspace.load()returns immediately, but the firstexecute()ordispatch()afterwards pauses while Mirage verifies that nothing has drifted upstream. Concretely, it asks the live source “is this path still the bytes I remember?” once per recorded read, in parallel. Tiny for short sessions (tens of milliseconds); a few hundred milliseconds to a couple of seconds for sessions with hundreds of recorded reads. The pause happens once per loaded workspace; subsequent calls are normal speed. Passdrift_policy=DriftPolicy.OFFif you want to skip the check entirely.