Skip to content
All pages

Snapshots, restore and undo

How moatbox keeps a history of each space's disk, and how you restore, reset, undo, share and fork from it.

A snapshot is a copy of a space's disk at one moment. moatbox keeps them on the server that runs the space. You can browse a snapshot's files, compare a file with the space now, restore the whole space to it, start a new space from it, or share it with another team.

A space has three kinds of snapshot:

Kind Who takes it How long it stays
Automatic moatbox, while the space is awake Thinned over time, gone after your plan's automatic history days
Saved An owner or admin, with a name Until you delete it
Taken at delete moatbox, when you delete the space While the space sits in the trash

The Snapshots page of a space lists its history. The Team snapshots page lists every space, the team's saved snapshots, share codes and spaces in the trash.

Automatic history

While a space is awake, moatbox checks it every 15 seconds and takes a snapshot if the disk changed since the last one. It takes one more when the space goes to sleep. A sleeping space takes none. Spaces that run CI jobs, and spaces of a team with no active plan, skip the 15-second checks but still get the snapshot at sleep.

moatbox thins the history as it ages. It keeps:

  • every snapshot from the last 10 minutes
  • one a minute for the last hour
  • one an hour for the last day
  • one a day after that, up to your plan's automatic history days

If a space's snapshots hold more than 100 GiB of disk, moatbox drops its oldest automatic snapshot each time it thins the history and finds nothing old enough to drop. This size rule stops at the newest automatic snapshot and leaves saved ones alone, so a space can stay above 100 GiB. The age rules above still apply to the newest one.

Plan Automatic history Saved snapshots per team Undo window for restores and resets
Solo 7 days 5 30 days
Pro 14 days 20 90 days
Team 30 days 50 365 days

Saved snapshots

Owners and admins save snapshots. Press Save now on a space's Snapshots page, or open an automatic snapshot and press Save with a name.

  • A name is 1 to 64 ASCII letters, digits, spaces, dots, dashes or underscores, and starts with a letter or digit.
  • Names are unique across the team.
  • The limit counts saved snapshots across all of the team's spaces.
  • A saved snapshot has no expiry.

Unsave turns a saved snapshot back into an automatic one. From then on, moatbox thins it like any other automatic snapshot.

You cannot save or share while snapshots are off for the space or the team. See Privacy.

Snapshot taken at delete

When an owner or admin deletes a space, moatbox takes a final snapshot and moves the space to the trash for 72 hours. You cannot rename or delete that snapshot. If you restore the space from the trash, the final snapshot joins its history as an automatic one. After 72 hours, moatbox deletes the space and every snapshot it has. Trash and delete are covered in Spaces.

With snapshots off, moatbox takes no final snapshot. With zero data retention on, deleting a space also skips the trash.

Browse, download and compare files

Any team member can browse a snapshot. Open it from the space's Snapshots page with Browse files. moatbox reads files from the snapshot on the server, so browsing works while the space sleeps.

Browsing shows the home folders and the workspace. The rest of the disk, such as /root and /etc, holds the space's own state and stays hidden: restore the snapshot or start a new space from it to reach those files. moatbox refuses a path that goes through a link.

Pick a file to:

  • Download it. Files up to 64 MiB download. moatbox records each download in the audit log.
  • Compare with now. moatbox shows a line diff between the snapshot and the file in the space today. Both sides must be text and at most 512 KiB, and the space must be awake.

For a bigger file, restore the snapshot or start a new space from it.

Restore a snapshot

Restoring puts the space's whole disk back to a snapshot. Owners and admins restore, and the space must be awake.

  1. Open the snapshot on the space's Snapshots page.
  2. Press Restore and confirm.

The space stops, its disk goes back to the snapshot, and it starts again. Running agents and SSH sessions end. moatbox keeps the state from just before the restore as an undo point. Every snapshot in the history stays.

To go back, press Undo restore. Undo drops every change made since the restore. The undo point lasts for your plan's undo window (see the table above).

Reset to a fresh box, and undo it

Reset on a space's page gives it a fresh disk. You lose everything in /workspace and /home/agent, the agent timeline, integration logins and hosted databases. The network mode and allowed hosts stay. Owners and admins reset, and the space must be awake.

Tick Keep logins to carry these files over:

Tool Files kept
Claude Code ~/.claude/.credentials.json, and the account in ~/.claude.json
Codex ~/.codex/auth.json
opencode ~/.local/share/opencode/auth.json
GitHub CLI ~/.config/gh/hosts.yml

moatbox skips a login file over 1 MiB. If it cannot write a kept login back, it undoes the reset.

Before the reset, moatbox keeps the old disk as an undo point. Undo reset puts it back and drops every change made since. The undo point lasts for your plan's undo window.

Limits on undo

  • A space keeps at most 3 undo points from resets and restores together. At 3, undo one or wait for the oldest to expire before you reset or restore again.
  • Undo always goes back to the newest undo point.
  • If you forked the space after the reset or restore, delete those copies before you undo.
  • Undo fails if it would make the team host more apps than the plan allows. Remove an app first.

Start a new space from a snapshot

On a snapshot, press New space from it. When you create a space, you can also pick A saved snapshot or A share code from another team as the start. Owners and admins create spaces, and the team needs an active plan.

moatbox makes the new space on the server that holds the snapshot. If that server has no room, try again later.

Share codes

A share code lets another team start a space from a copy of one of your saved snapshots.

  1. Save the snapshot with a name.
  2. Open it and press Share code.
  3. Copy the code. It starts with mbs_ and is 47 characters long. moatbox stores only a hash of it, so you see the full code once.

Owners and admins create and revoke codes. A code lasts 7 days unless you pick another length, from 1 to 30 days. A team holds at most 5 live codes at a time; revoke one to make another.

Before the code works, moatbox checks a copy of the snapshot and removes from it:

  • moatbox's own state in the space, and Tailscale state
  • sign-in and key files in /root and each home folder: .claude/.credentials.json, .claude.json, .codex/auth.json, .local/share/opencode/auth.json, .config/gh/hosts.yml, .git-credentials, .netrc, .npmrc, .pypirc, .docker/config.json, .aws/credentials, .aws/config, .config/gcloud, .kube/config, .ssh
  • any file that holds one of your team's integration credential values, the space's own key, its AI token, or a secret variable, agent key or API key of its environment (values of 8 characters or more)

The Team snapshots page lists what moatbox removed. If a credential value stays somewhere moatbox cannot strip, such as file system metadata or the space's data pool, the code shows Blocked and never works.

The other team pays for the space it makes. Your Team snapshots page shows who used each code, and your audit log records each use. Revoke a code to stop new spaces from it; spaces already made from it keep working. The page lists codes from the last 90 days.

Fork a running space

A fork makes one or more copies of a space as it runs, memory included. moatbox pauses the space for a moment, copies its memory and disk, and resumes it. Each copy starts from that point on the same server.

Owners and admins fork. The space must be awake and not read-only. Each copy needs its own slug: 3 to 32 characters of a-z, 0-9 and -, starting and ending with a letter or digit.

Copies inherit the parent's network settings, environment, monitoring, snapshot and retention settings, and idle and awake limits. Always on starts off in a copy. Each copy counts toward your plan's limit on running boxes. moatbox refuses the fork if there aren't enough free boxes, if the server has no room for the copies, or if their hosted apps would pass your plan's limit.

curl -X POST https://app.moatbox.dev/api/v1/spaces/my-space/fork \
  -H "Authorization: Bearer $MOATBOX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"slugs": ["my-space-a", "my-space-b"]}'

Delete snapshots

Owners and admins delete snapshots. Delete removes one saved or automatic snapshot. Delete history removes every automatic snapshot of the space; you confirm by typing the space's name. Deleted snapshots cannot come back. Saved snapshots stay until you delete them one by one.

API

All routes live under https://app.moatbox.dev/api/v1. Send an API key as Authorization: Bearer <key>. Keys need snapshot.read or snapshot.write; forks need space.fork. Saving, unsaving, deleting, restoring, resetting and undoing also need one of run, exec or file.write. See API keys.

Method and path Does
GET /spaces/{space}/snapshots List the history, disk use, plan limits and the last restore
POST /spaces/{space}/snapshots Save now. Body: {"name": "..."}
PATCH /spaces/{space}/snapshots/{id} Save with a name ({"name": "..."}) or unsave ({"name": null})
DELETE /spaces/{space}/snapshots/{id} Delete one snapshot
DELETE /spaces/{space}/snapshots Delete the automatic history. Body: {"confirm": "<space>"}
POST /spaces/{space}/snapshots/{id}/restore Restore
GET /spaces/{space}/snapshots/{id}/files?path=/ List a folder
GET /spaces/{space}/snapshots/{id}/files/content?path=... Download a file
GET /spaces/{space}/snapshots/{id}/files/diff?path=... Compare a file with now
POST /spaces/{space}/snapshots/{id}/shares Create a share code. Body: {"days": 7}
DELETE /teams/{team}/shares/{id} Revoke a share code
POST /spaces/{space}/reset Reset. Body: {"keep_logins": true}
POST /spaces/{space}/reset/undo Undo the newest reset or restore
GET /spaces/{space}/resets List undo points and when they expire
POST /spaces/{space}/fork Fork. Body: {"slugs": ["..."]}
GET /teams/{team}/snapshots Team view: spaces, saved snapshots, share codes, trash

To start a space from a snapshot, send from to POST /teams/{team}/spaces:

{"slug": "from-snap", "from": {"snapshot": 1234}}

or with a share code:

{"slug": "from-code", "from": {"code": "mbs_..."}}