Skip to main content

Persistence and volumes

A sandbox's /workspace lives on local disk and disappears with the sandbox. A persistence mode decides what else survives, on a shared volume of your account backed by object storage.

Persistence modes​

ModeWhat survivesPauseBest for
EPHEMERALNothing.Not available (terminate instead).One-shot code execution, untrusted snippets, warm pools.
DIRECTORYEvery file written under the mount path (default /workspace/persist), as soon as it is closed.Instant; nothing to copy.Long-lived work that must survive any timeout: repositories, artifacts, conversation workspaces.
SNAPSHOTThe whole workspace, archived at pause and restored at resume.Packs the workspace (minus snapshotExclude) into one archive.Restoring a full environment (installed packages, build caches) between sessions.
BOTHA live directory plus a whole-workspace snapshot at pause, on the same volume.Packs the workspace.Interactive agents that pause between turns and keep important files in the directory.

The template revision sets the default; each create call can override it with persistenceMode.

Timeouts terminate, they do not pause. When a sandbox hits its idle timeout or maximum lifetime, DIRECTORY data is already safe, but SNAPSHOT/BOTH changes made since the last pause are lost. If losing work on a timeout is not acceptable, keep it under the mount path (DIRECTORY or BOTH), or pause explicitly before you stop using the sandbox.

Where the volume comes from​

  • Created for you. In a volume mode without volumeName, Quave ONE creates a volume named sbvol-<sandboxId> on an object storage point the account can use in the sandbox's region: your own bucket when you connected one there, otherwise the Quave ONE platform point of the region. If neither exists, the create call answers 409.
  • Reused by name. Pass volumeName to attach an existing active shared volume of the account in the same region. This is how a new sandbox continues the work of a previous one.

Terminating or pausing a sandbox never removes its volume. Volumes appear on the Shared Storage page with the sandbox as their origin, and in GET /shared-volumes (MCP: list-shared-volumes) with origin.kind: "sandbox".

One workspace per conversation​

A common pattern is one volume per conversation (or project, or user), reused by every sandbox that works on it:

  1. Create the volume once:

    curl -X POST "$API/shared-volume/create" \
    -H "Authorization: $TOKEN" -H 'Content-Type: application/json' \
    -d '{"accountId": "ACCOUNT_ID", "region": "us-5", "name": "conv-42", "size": "10Gi", "storageClassName": "STORAGE_SERVER_NAME"}'

    Pick storageClassName from GET /storage-servers?accountId=ACCOUNT_ID&region=us-5 (MCP: list-storage-servers), an object storage (volobj) server.

  2. Create every sandbox for that conversation with "persistenceMode": "DIRECTORY" and "volumeName": "conv-42", and keep files under /workspace/persist.

  3. Terminate sandboxes freely; the next one sees the same files.

  4. When the conversation is deleted, remove the volume (POST /shared-volume/remove, MCP: remove-shared-volume). It stays restorable for purgeAfterDays (default 7); POST /shared-volume/restore brings it back.

Only one sandbox should write a given volume at a time. With lockOnWrite (the default on your own bucket), a second writer of the same file gets EBUSY.

File ownership and modes​

Sandbox commands run as uid/gid 1001. Volumes created for a sandbox (sbvol-…) report every file as owned by 1001, so tar -x, cp -p, git, and package managers work on the mount.

The volume keeps file contents, names and directories. It does not keep file modes or times you set:

  • Every file reports mode 0664 and every directory 2775. chmod succeeds but is not stored, so chmod 600 and chmod +x have no effect, now or in a later sandbox on the same volume.
  • A file's modification time is the time it was last written to the volume; touch -d succeeds but is not stored.
  • The gateway file API refuses a write with an explicit mode under the mount (422 mode_not_kept) instead of writing the file with a different mode.

Keep files that need a mode (SSH keys, credential files, executable scripts) outside the mount, in /workspace. To carry them across sandboxes, use SNAPSHOT or BOTH: the snapshot archives /workspace with modes and times, and resume restores them. Otherwise store the content on the volume and set the mode after copying it out, for example install -m 600 /workspace/persist/id_ed25519 ~/.ssh/id_ed25519.

A volume you create yourself reports the owner configured on its storage point. When sandboxes will use it, connect your bucket with uid and gid 1001, or update the point before creating the volume (POST /storage-server/object-storage/update, MCP: update-object-storage-server).

Use your own bucket​

To keep sandbox data in your own S3-compatible bucket (AWS S3, Cloudflare R2, OCI Object Storage, MinIO, and others), connect it once per region:

curl -X POST "$API/storage-server/object-storage/create" \
-H "Authorization: $TOKEN" -H 'Content-Type: application/json' \
-d '{
"accountId": "ACCOUNT_ID",
"region": "us-5",
"endpoint": "s3.us-east-1.amazonaws.com",
"bucket": "my-sandbox-data",
"accessKey": "AKIA...",
"secretKey": "...",
"uid": 1001,
"gid": 1001
}'

Credentials are write-only and never returned. Data is encrypted with a master key that is generated for you (or supplied as masterKey); a member with the Secrets Access role can reveal it on the Shared Storage page. From then on, volumes created for sandboxes in that region land in your bucket. MCP: create-object-storage-server. Full field list in the Shared Volumes API.

Snapshots​

In SNAPSHOT and BOTH:

  • Pausing writes one archive of the workspace to the volume, skipping snapshotExclude patterns, up to snapshotMaxMb (default 2048 MB uncompressed). The pause request can override both for that pause only. The pause answers once the archive is written, which can take minutes for a large workspace. A snapshot that does not finish in time answers 504, leaves the sandbox running, and is safe to retry.
  • After a pause, persistence.lastSnapshotAt and persistence.lastSnapshotBytes describe the archive; persistence.lastSnapshotError is set when the last snapshot or restore failed.
  • Resume restores the latest archive before the sandbox serves commands.
  • If the restore at start failed, a later pause is refused unless you pass force: true, so a near-empty workspace never overwrites the last good snapshot.

Costs​

Volumes are billed as shared storage, for what they hold. Paused sandboxes are not billed for compute. See Pricing and Storage.