Docs · Guides

Concepts

How sandboxes behave: what is inside one, how pausing works, and how network rules, secrets and previews keep work contained.

ConceptsMenu

Sandboxes

A sandbox is a Linux virtual machine of its own, with its own kernel, memory and disk. It runs Debian with Python 3, Node.js 24, git, build tools, curl, jq, ripgrep and Chromium. There is no systemd.

  • Commands run as the user agent in /workspace by default, with a clean environment and no standard input. agent can use sudo without a password, so apt-get install and pip install work.
  • Files persist across pauses and restarts until you delete the sandbox.
  • Docker can be installed and run inside a sandbox: sudo apt-get install -y docker.io, then start dockerd yourself.
  • A sandbox has an ID like sb-4f1c9e27a0b3d5c86e12. It stays on the host it was created on.

Sandbox states

Sandbox states
StatusMeaning
creatingBeing placed on a host and booted.
runningRunning. Billed as compute.
pausingIts memory is being written to disk.
pausedMemory and files are saved on its host; nothing runs. Billed as storage. The next use resumes it.
resumingIts memory is being loaded back.
stoppedIts machine stopped without being deleted, for example when its host restarted. Billed as storage. The next use boots it fresh from its files.
deletingBeing deleted. If the host does not confirm at once, we keep trying.
deletedGone, with its files, memory and snapshots.
failedCreation failed. Nothing runs and nothing is billed.

Sizes

Pick a size when you create a sandbox. It cannot be changed later.

Sandbox sizes
SizevCPUsMemoryDisk
small12 GiB10 GiB
medium (default)24 GiB20 GiB
large48 GiB40 GiB

vCPUs are shared with other sandboxes on the host, in proportion to size. A sandbox that keeps its vCPUs busy for minutes, such as a long build, gets a smaller share until it calms down, so shells and short tasks stay quick. Disk and network throughput are limited per vCPU; see Limits.

Pause, resume and the idle policy

Pausing writes a sandbox's memory to its host's disk and stops it. Nothing runs and it uses no memory or CPU. Resuming loads the memory back: processes, open files and everything in memory continue where they were. The clock is corrected. Outside servers may have closed connections during a long pause, so programs should be ready to reconnect.

You never have to resume by hand. Running a command, moving a file, opening a shell, the browser or a preview, or reading the credential inventory resumes a paused sandbox first. Reading its status never does.

When a sandbox counts as idle

A running sandbox is active while any of these is true:

  • a command's output is being streamed, a file is moving, or a shell, browser or preview connection is open;
  • it sent or received network traffic recently;
  • it used CPU recently;
  • a program in it is waiting for a reply through our network proxy, such as an agent waiting on its model (for up to 30 minutes).

When none of these has been true for its idle timeout, it is paused. The timeout is 10 minutes by default, and 1 to 1440 minutes when you set it:

terminal
mat create --idle-minutes 30mat set $ID --idle-minutes 5

A command left running with no client attached keeps running while it uses CPU or the network. If it goes quiet, the sandbox may pause; the command continues when it resumes.

Pausing to make room

A host may pause sandboxes before their timeout when it needs room for another sandbox: only ones idle for at least 30 seconds, and first those of accounts using more than their share of the host. When a host runs short of memory, it may pause active sandboxes too, because a paused sandbox loses nothing. Kept-awake sandboxes are never paused this way.

Restarts and cold boots

If a host restarts or a sandbox's machine crashes, the sandbox shows stopped. Its next use boots it fresh from its files: files are kept, running processes are not. The same happens if a saved memory snapshot cannot be restored. cold_booted_at in the API, and restarted in mat ls, say when it happened.

Keep-awake

A kept-awake sandbox is never paused automatically: not when idle and not to make room. It is billed as running the whole time. You can still pause it yourself.

terminal
mat create --keep-awakemat set $ID --keep-awake truemat set $ID --keep-awake false

Network rules (egress)

Every connection a sandbox opens goes through a proxy on its host. Each sandbox has one of three presets:

Egress presets
PresetWhat the sandbox can reach
open (default)The internet.
restrictedHTTPS and HTTP to the domains you allow, plus the essentials unless you turn them off, and DNS. Nothing else.
noneNothing.
terminal
mat create --egress restricted --allow example.com --allow '*.example.org'mat set $ID --egress restricted --no-essentials --allow api.anthropic.commat set $ID --egress open
  • example.com allows exactly that name. *.example.com allows its subdomains at any depth, but not example.com itself.
  • Under restricted, the proxy reads the name from the TLS server name or the HTTP Host header, without decrypting. It looks the name up itself and connects to its own answer, so an allowed name cannot be paired with another address.
  • Protocols that carry no name, such as SSH or database connections, need open.
  • Refused connections are rejected at once, so programs fail fast instead of hanging.
  • A change applies to new connections; open ones are not cut. egress_pending is true until the host confirms it enforces the new rules. mat set --egress restricted replaces the whole list, so name every domain each time.

The essentials

Under restricted, these are allowed unless you pass --no-essentials (or "essentials": false):

Essential domains
ForDomains
Debian packagesdeb.debian.orgsecurity.debian.org
Pythonpypi.orgfiles.pythonhosted.org
JavaScriptregistry.npmjs.orgregistry.yarnpkg.com
Rustcrates.ioindex.crates.iostatic.crates.iostatic.rust-lang.org
Goproxy.golang.orgsum.golang.org
GitHubgithub.com*.github.com*.githubusercontent.comghcr.io
Model APIsapi.anthropic.comapi.openai.comgenerativelanguage.googleapis.com

Always blocked

Whatever the preset, a sandbox can never reach private networks, link-local and cloud metadata addresses, loopback, other sandboxes or our hosts. This is a security boundary, not a setting.

Abuse controls

Outbound mail on port 25 is blocked; send through a mail provider on port 465 or 587. Each sandbox has a limit on new connections per second and on open connections, set well above what installs, git, model APIs and browsing need: 20 per second sustained, with bursts of 400. Accounts without an active subscription get a quarter of that. A sandbox whose connections fail to 200 different destinations within a minute looks like a port scan: its new connections are refused, and it is paused and held for review. A held sandbox keeps its files and memory but cannot run until we clear it; we email you when it happens, and its status shows held.

The egress log

mat egress shows recent connections, oldest first: the name asked for, the address, whether it was allowed, and why not. Repeated entries are folded with a count. The host keeps the last 1000 per sandbox in memory, so the log is lost if the host agent restarts.

Brokered secrets

A brokered secret is an API key or token that never enters the sandbox. Inside, the variable holds a worthless placeholder. When a program sends an HTTPS request to a domain the secret is bound to, the proxy on the host replaces the placeholder with the real value in the request headers.

terminal
mat secret set ANTHROPIC_API_KEY --domain api.anthropic.comPaste the secret value and press Enter:mat create --secret ANTHROPIC_API_KEYmat exec $ID -- sh -c 'echo $ANTHROPIC_API_KEY'

The last command prints the placeholder, not your key.

  • The value is swapped in only in request headers, and only when both the TLS server name and the Host header match a bound domain. The proxy verifies the real server's certificate before sending anything.
  • To read those requests, the proxy decrypts HTTPS to bound domains, and only to them. The sandbox trusts a certificate authority of its own for this; its key stays on the host. SSL_CERT_FILE, REQUESTS_CA_BUNDLE and NODE_EXTRA_CA_CERTS point to it, so curl, Python and Node trust it.
  • Under restricted, the secret's domain must also be allowed. Model APIs are in the essentials.
  • Secrets belong to your account. Replacing a value updates every sandbox it is attached to. New commands and shells get newly attached secrets; running ones keep the environment they started with.
  • Values can be written and replaced, never read back.
  • Not supported yet: secrets in request bodies or URLs, and WebSocket connections to bound domains. Bound domains are offered HTTP/1.1 only.

Credential inventory

Agents leave credentials behind: a gh login, an .env file, browser cookies. mat credentials lists what a sandbox holds and where, never the values:

terminal
mat credentials $IDaws_profile	default	-	/home/agent/.aws/credentialsgithub_cli	octocat	github.com	/home/agent/.config/gh/hosts.yml

It looks in well-known places: tool credential files in /home/agent and /root (AWS, gh, git, netrc, npm, PyPI, Docker, SSH keys, kubeconfig, gcloud, Claude Code and Codex logins), .env files in /workspace, running programs' environments, and Chromium cookie stores (sites and counts). It is a best-effort scan, not a guarantee. Scanning runs inside the sandbox, so it resumes a paused one.

Shell and browser

mat shell opens an interactive login shell. mat browser prints a single-use URL for the sandbox's Chromium over the Chrome DevTools Protocol, valid for 60 seconds. Pass it to a CDP client:

python, with playwright
from playwright.sync_api import sync_playwright url = "wss://…"  # from mat browserwith sync_playwright() as p:    browser = p.chromium.connect_over_cdp(url)    page = browser.contexts[0].new_page()    page.goto("https://example.com")

Chromium in the sandbox runs with Google's background services turned off, so it does not call out on its own. Your API key never appears in these URLs. See Connecting a shell or browser.

Previews

A preview shows a web server running in a sandbox, at https://PORT-SANDBOX_ID. followed by our preview domain. Open one from the sandbox's page in the dashboard. Previews are never public: only you, signed in to the dashboard, can open them. An API key or a mat session cannot. Signing out ends access. HTTP and WebSockets both work, and a paused sandbox resumes when its preview is opened.

Previews need our preview domain; where it is not set up yet, the dashboard cannot open one.