Skip to content

Filesystem Isolation

Every sandbox gets a versioned FUSE mount of your repository data. The mount operates on a session — a transactional workspace that isolates the sandbox's reads and writes from the committed state. Changes only become visible to others when the session is committed.

How It Works

  1. When a sandbox is created, Tilde opens a session — a transactional workspace over the current repository state
  2. The session's data is mounted into the container as a FUSE volume at the configured mountpoint (default: /sandbox)
  3. The sandbox reads files directly from this mount — they appear as regular files on disk
  4. Any files the sandbox creates, modifies, or deletes are staged in the session
  5. On successful exit (code 0), Tilde commits the session — recording all staged changes as a single new commit on the repository
  6. On failure (non-zero exit) or cancellation, the session is rolled back — all changes are discarded

This means sandboxes can never corrupt your committed data. Even if a sandbox writes garbage, deletes everything, or crashes halfway through, the repository remains untouched until a clean commit succeeds.

Mountpoint and Path Prefix

By default, the entire repository is mounted at /sandbox. You can customize both the mount location and which subset of the repository to expose:

  • mountpoint — the container path where data appears (e.g. /data, /workspace). Must be an absolute path.
  • path_prefix — only mount objects under this prefix. For example, datasets/ mounts only objects whose path starts with datasets/.
{
  "image": "python:3.11",
  "command": ["python", "train.py"],
  "mountpoint": "/data",
  "path_prefix": "datasets/training/"
}

In this example, the file datasets/training/labels.csv in the repository appears as /data/labels.csv inside the container.

Reading Files

Files are read on demand — the FUSE mount fetches data from object storage as the sandbox accesses it. From the sandbox's perspective, files behave like regular local files:

import os

# List files
files = os.listdir("/sandbox")

# Read a file
with open("/sandbox/data.csv") as f:
    content = f.read()

# Walk directory tree
for root, dirs, files in os.walk("/sandbox"):
    for name in files:
        path = os.path.join(root, name)
        size = os.path.getsize(path)
        print(f"{path}: {size} bytes")

Standard file operations like stat, open, read, seek, and readdir all work as expected. Tools like pandas.read_csv(), PIL.Image.open(), and cat work without modification.

Writing Files

Sandboxes can create, modify, and delete files. Writes are staged in the session and not visible outside the sandbox until the session is committed:

# Create a new file
with open("/sandbox/results/output.json", "w") as f:
    json.dump(results, f)

# Create directories (automatically created on write too)
os.makedirs("/sandbox/reports/2026", exist_ok=True)

# Delete a file
os.remove("/sandbox/old-data.csv")

Permission errors at write time

Writes that would fail the principal's RBAC policy are rejected with EACCES (Permission denied) at the open/create/unlink syscall itself, not silently dropped after the upload. For agents this means an open("/sandbox/other-repo/foo", "w") call against a path not permitted by the agent's inline policy fails immediately, bubbling up as PermissionError in Python or the equivalent in other languages. Applications can catch the error and fall back accordingly rather than discovering the missing change at commit time.

Session Lifecycle

The session lifecycle is fully managed by the sandbox orchestrator:

Sandbox exit Session outcome
Exit code 0 Session is committed (all staged changes recorded as a new commit)
Exit code 0 + approval required Session held for human review (awaiting_approval)
Non-zero exit code Session is rolled back (all changes discarded)
Cancelled Session is rolled back
Timeout Session is rolled back

No partial commits

Sessions are atomic. Either all changes from a sandbox are committed together, or none are. There is no way to commit some files and roll back others within a single sandbox run.

Commit Metadata

Each sandbox commit records structured metadata for audit:

  • Committer — the principal the sandbox ran as (user, agent, or role)
  • Image -- the container image used
  • Issuer — who created the sandbox (may differ from committer when using run_as)
  • Source"sandbox" (to distinguish from manual commits)
  • Trigger info — trigger name and ID, if the sandbox was fired by a trigger

This metadata appears in the commit log and is available via the API.

Conflict Resolution

If another commit lands on the repository while a sandbox is running, Tilde reconciles the sandbox's session against the new state at commit time:

  • No overlapping files — the sandbox's commit goes through cleanly
  • Conflicting changes on the same file — the commit fails and the sandbox is marked failed with commit_failed

In practice, conflicts are rare because each sandbox operates on its own session. Triggers that fire on the same commit run in parallel sessions, and their changes are committed sequentially.