# div sandbox

> Reference for div sandbox, the command that creates, runs commands in, stops, resumes, forks and deletes sandboxes.

## Synopsis

```text
div sandbox <subcommand> [arguments] [flags]
```

`div sandbox` with no subcommand is `div sandbox ls`. It uses the API key that [`div login`](https://docs.divergentlabs.xyz/compute/cli/login.md) saves. If your key was created before sandboxes existed, run `div login` again.

`<sandbox>` is a sandbox's name or id. Every subcommand accepts `--json`, which prints the full API response instead of the usual output.

## Subcommands

| Subcommand | Description |
| --- | --- |
| [`create`](#create) | Create a sandbox and print its name. |
| [`ls`](#ls) | List the org's sandboxes. |
| [`exec`](#exec) | Run a command in a sandbox. |
| [`cp`](#cp) | Copy a file into or out of a sandbox. |
| [`ssh`](#ssh) | Open a shell on a sandbox. |
| [`set`](#set) | Change a sandbox's idle timeout, whether it stops when its agents finish, or its metadata. |
| [`stop`](#stop) | Stop a sandbox, keeping its files and processes. |
| [`resume`](#resume) | Resume a stopped sandbox. |
| [`fork`](#fork) | Create a new sandbox from another sandbox's files. |
| [`rm`](#rm) | Delete a sandbox permanently. |
| [`desktop`](#desktop) | Start, stop or check the desktop. |
| [`open`](#open) | Open URLs in the desktop's browser. |
| [`screenshot`](#screenshot) | Save the desktop's screen as a PNG. |
| [`input`](#input) | Send a click, keystroke or scroll to the desktop. |
| [`a11y`](#a11y) | Read the desktop's accessibility tree, or act on a node. |
| [`forward`](#forward) | Make a sandbox port available on your machine. |
| [`token`](#token) | Print a token that opens only this sandbox's desktop and screen. |
| [`tunnel`](#tunnel) | Make a port on your machine available in the sandbox, or send its traffic through your machine. |

## create

```text
div sandbox create [--size <size>] [--name <name>] [--secret <NAME>]... [--environment <env>] [--metadata <key>=<value>]... [--idle <duration>] [--stop-when-agents-finish] [--idempotency-key <key>]
```

Creates a sandbox and starts it. The sandbox is running when the command returns.

| Flag | Description | Default |
| --- | --- | --- |
| `--size <size>` | `small`, `standard`, `large` or `xl`. See [sizes and prices](https://docs.divergentlabs.xyz/sandboxes.md#sizes-and-prices). | `small` |
| `--name <name>` | Lower case letters, digits and dashes. Must start with a letter or digit. The org's slug and a dash are put in front: in org `acme`, `box` becomes `acme-box`, and a name that already starts with `acme-` is kept. The full name is at most 63 characters and unique across all orgs. Commands find the sandbox by either name. | the org's slug, `-sb-` and six hex digits |
| `--secret <NAME>` | A secret to set as an environment variable in the sandbox, read from `--environment`. The secret's products must include `sandboxes`. Repeat for each secret. A sandbox with secrets cannot have a [token](#token). | none |
| `--environment <env>` | The [secrets environment](https://docs.divergentlabs.xyz/compute/cli/secrets.md#environments-and-products) to read `--secret` from. `resume` reads from the same environment, and a fork keeps it. The environment cannot be deleted while the sandbox exists. | `default` |
| `--metadata <key>=<value>` | A label of your own, such as the user the sandbox is for. Repeat for each label, up to 16. Keys are 1 to 40 lowercase letters, digits, `_`, `.` or `-`. Values are up to 256 characters. | none |
| `--idle <duration>` | Stop the sandbox after this long without use: `90s`, `15m`, `2h`, `1d`, or `0` for never. Between 60 seconds and 7 days. A number without a unit is rejected. See [idle timeout](https://docs.divergentlabs.xyz/sandboxes/snapshots.md#stop-a-sandbox-automatically-when-idle). | `0` |
| `--stop-when-agents-finish` | Stop the sandbox once its [coding agents](https://docs.divergentlabs.xyz/sandboxes/agents.md) have finished a turn, no turn is running or queued, and nothing has used the sandbox for 2 minutes. | off |
| `--idempotency-key <key>` | A retry with the same key returns the sandbox the first attempt created instead of creating another. Up to 255 characters. | none |

**Output.** The name on stdout, alone, so `SB=$(div sandbox create)` captures it. A summary on stderr:

```text
sb-4c1e9a
sb-4c1e9a running · small, 1 vCPU, 2 GiB · $0.05/h · runs until stopped
```

For a sandbox created with `--environment` other than `default`, the summary also says `secrets from <env>`.

**Example**

```bash
SB=$(div sandbox create --size standard --secret GITHUB_TOKEN --idle 30m)
SB=$(div sandbox create --metadata user=42 --metadata team=support)
SB=$(div sandbox create --environment acme --secret ANTHROPIC_API_KEY --metadata customer=acme)
```

**Errors**

| Code | When |
| --- | --- |
| `unknown_environment` | No environment named by `--environment`. Create it with `div secrets env add`, or list environments with `div secrets env ls`. |
| `unknown_secrets` | A `--secret` is not in the environment, or its products do not include `sandboxes`. Set it with `div secrets set <name> --environment <env>`, or run `div secrets products <name> runs,sandboxes --environment <env>`. |

## ls

```text
div sandbox ls [--all] [--metadata <key>=<value>]...
```

Lists the org's sandboxes, newest first.

| Flag | Description | Default |
| --- | --- | --- |
| `--all` | Include deleted sandboxes. | off |
| `--metadata <key>=<value>` | List only sandboxes with this label. Repeat to require several; a sandbox must have all of them. | all sandboxes |

**Output.** One row per sandbox: name, status, size with vCPUs and memory, hourly price, and total spend. The name is the first column, so `div sandbox ls | cut -d' ' -f1` lists names. A summary line on stderr gives the number running and their combined hourly price.

```text
sb-4c1e9a  running  small 1×2G     $0.05/h  spent $0.14
base       stopped  standard 2×4G  $0.10/h  spent $0.52
1 sandbox running, $0.05/h
```

Status is one of `starting`, `running`, `stopping`, `stopped`, `resuming`, `destroyed` or `failed`.

With `--metadata` and no match, the output is `No sandboxes with that metadata.` on stderr. With `--json`, each sandbox includes its `metadata`.

**Example**

```bash
div sandbox ls --metadata user=42
```

## exec

```text
div sandbox exec <sandbox> [--cwd <dir>] [--env KEY=value]... [--timeout <seconds>] -- <command> [args]...
div sandbox exec <sandbox> '<script>'
```

Runs a command in a running sandbox as root and waits for it to finish.

| Flag | Description | Default |
| --- | --- | --- |
| `--cwd <dir>` | Working directory. | `/root` |
| `--env KEY=value` | An environment variable for this command. Repeat for each variable. | none |
| `--timeout <seconds>` | Maximum run time, up to 600. A command that runs longer is killed and exits 124. | `60` |

- One argument runs as a shell script: `div sandbox exec $SB 'cd app && make'`.
- Several arguments run as a command with those exact arguments: `-- echo "a b"` prints `a b`.
- Put `--` before a command that has its own flags. Otherwise `div` reads them.

**Output.** The command's stdout and stderr, unchanged, on stdout and stderr. Each stream is cut at 1 MB. For more output, write it to a file and copy it back with `cp`. Values of the sandbox's secrets are masked.

**Exit code.** The command's exit code.

**Examples**

```bash
div sandbox exec $SB -- npm test
div sandbox exec $SB --cwd /root/app --timeout 600 'make && make check'
div sandbox exec $SB -- cat /root/log.txt | grep loss
```

## cp

```text
div sandbox cp <from> <to>
```

Copies one file between your machine and a sandbox. Write the sandbox side as `<sandbox>:<path>`. Use `-` for stdin or stdout. Files can be up to 64 MB. For larger files, download them from inside the sandbox with `curl`.

**Output.** The size copied, on stderr. Nothing on stdout unless `<to>` is `-`.

**Examples**

```bash
div sandbox cp ./app.py $SB:/root/app.py
div sandbox cp $SB:/root/out.json ./out.json
div sandbox cp $SB:/root/out.json - | jq .metrics
tar cz src | div sandbox cp - $SB:/root/src.tgz
```

## ssh

```text
div sandbox ssh <sandbox> [-- <command>]
```

Opens a root shell on a running sandbox, or runs one command, with your system's `ssh`. Requires `ssh` and `ssh-keygen` on your `PATH`, and an API key with the `sandboxes:write` scope.

- The first run creates a key at `~/.config/divergent/ssh_ed25519`. Each `div sandbox ssh` adds the key to the sandbox it connects to.
- The session is encrypted end to end. Output is not masked.
- The shell has the sandbox's environment, including its secrets.
- An open session counts as use, so the sandbox is not stopped as idle.
- Stopping the sandbox ends the session.

**Exit code.** The remote command's exit code, or 255 if `ssh` fails to connect.

**Examples**

```bash
div sandbox ssh $SB
div sandbox ssh $SB -- tail -f /root/app/server.log
```

To use `scp`, `rsync` or an editor's remote SSH, see [Use a sandbox over SSH](https://docs.divergentlabs.xyz/sandboxes/ssh.md#connect-scp-rsync-or-an-editor).

## set

```text
div sandbox set <sandbox> [--idle <duration>] [--stop-when-agents-finish on|off] [--metadata <key>=<value>]... [--clear-metadata]
```

Changes the idle timeout of a running or stopped sandbox, whether it stops when its agents finish, or its metadata. Give at least one flag.

| Flag | Description | Default |
| --- | --- | --- |
| `--idle <duration>` | Same values as [`create`](#create). `0` means never. | unchanged |
| `--stop-when-agents-finish on\|off` | `on` stops the sandbox once its agents have finished, as in [`create`](#create). `off` keeps it running. | unchanged |
| `--metadata <key>=<value>` | Replace every label with the labels given. Same rules as [`create`](#create). Repeat for each label. | unchanged |
| `--clear-metadata` | Remove every label. Cannot be combined with `--metadata`. | off |

On a running sandbox, the new timeout counts from now.

`--metadata` replaces the labels as a whole. To add one label, give every label the sandbox should keep.

**Output**

```text
sb-4c1e9a running · small, 1 vCPU, 2 GiB · $0.05/h · stops after 2h idle
```

## stop

```text
div sandbox stop <sandbox>
```

Stops a sandbox. Its files and running processes are kept, and it is billed for storage only. Stopping a stopped sandbox succeeds and changes nothing.

**Output.** On stderr: the size of the stored data and the sandbox's total spend.

```text
sb-4c1e9a stopped · 1.2 GB stored · spent $0.14
```

With `--json`, `stopped_reason` is `requested`, `idle`, `agents_finished` or `limit_reached`.

## resume

```text
div sandbox resume <sandbox>
```

Resumes a stopped sandbox with its files and processes as they were. Takes a few seconds.

**Output**

```text
sb-4c1e9a running · small, 1 vCPU, 2 GiB · $0.05/h · runs until stopped
```

## fork

```text
div sandbox fork <sandbox> [--name <name>]
```

Creates a new running sandbox with a copy of another sandbox's files. The source can be running or stopped and is not changed. The new sandbox has the source's size, secrets, secrets environment, idle timeout and metadata. Running processes and the desktop are not copied.

| Flag | Description | Default |
| --- | --- | --- |
| `--name <name>` | Name of the new sandbox. Same rules as [`create`](#create). | the org's slug, `-sb-` and six hex digits |

**Output.** The new name on stdout, alone, and a summary on stderr:

```text
try-b
try-b running · small, 1 vCPU, 2 GiB · $0.05/h · runs until stopped · a copy of sb-4c1e9a
```

## rm

```text
div sandbox rm <sandbox>
```

Deletes a sandbox and its stored data. Billing stops. This cannot be undone.

**Output.** On stderr: the sandbox's total spend.

```text
sb-4c1e9a destroyed with all its files · spent $0.14
```

## desktop

```text
div sandbox desktop <sandbox> [start|stop|status] [--resolution <WxH>]
```

Starts the desktop (the default action), stops it, or reports whether it is running. `start` returns when the browser is ready.

| Flag | Description | Default |
| --- | --- | --- |
| `--resolution <WxH>` | Screen size for `start`. Width 320 to 1920, height 240 to 1080. | `1280x800` |

**Output.** The screen size and the dashboard page where you can watch it:

```text
Desktop running on sb-4c1e9a at 1280x800. Watch it at https://app.divergentlabs.xyz/sandboxes/sb-4c1e9a.
```

With `--json`: `running`, `size`, `display`, `vnc_port`, `devtools` and `browser`.

## open

```text
div sandbox open <sandbox> <url>...
```

Opens each URL as a tab in the desktop's Chromium. The desktop must be running.

## screenshot

```text
div sandbox screenshot <sandbox> [file] [--region <x0>,<y0>,<x1>,<y1>]
```

Captures the screen as a PNG. Writes to `file`, or to stdout when you give no file or `-`. Refuses to write to a terminal.

| Flag | Description | Default |
| --- | --- | --- |
| `--region <x0>,<y0>,<x1>,<y1>` | Capture only this part of the screen: the top-left and bottom-right corners, in screen pixels. The PNG is that part scaled up to fit the screen size, keeping its aspect ratio. | the whole screen |

**Output.** The width, height and size, on stderr:

```text
1280×800 PNG, 214 KB
```

**Examples**

```bash
div sandbox screenshot $SB shot.png
div sandbox screenshot $SB | your-model
div sandbox screenshot $SB zoom.png --region 0,0,640,400
```

## input

```text
div sandbox input <sandbox> click [<x> <y>] [--button left|middle|right] [--count 1|2|3] [--double] [--mods <keys>]
div sandbox input <sandbox> move <x> <y>
div sandbox input <sandbox> down
div sandbox input <sandbox> up
div sandbox input <sandbox> drag <x1> <y1> <x2> <y2> [--mods <keys>]
div sandbox input <sandbox> type <text>
div sandbox input <sandbox> key <combo>... [--repeat <n>]
div sandbox input <sandbox> hold <combo>... --seconds <s>
div sandbox input <sandbox> scroll <up|down|left|right> [notches] [--at <x>,<y>] [--mods <keys>]
div sandbox input <sandbox> cursor
```

Sends one input to the desktop. Positions are screenshot pixels from the top left.

| Action | Description |
| --- | --- |
| `click` | Click at `<x> <y>`, or where the pointer is when you give no position. |
| `move` | Move the pointer. |
| `down`, `up` | Press or release the left button where the pointer is. |
| `drag` | Drag with the left button from `<x1> <y1>` to `<x2> <y2>`. |
| `type` | Type the text where the keyboard focus is. |
| `key` | Press each key or combination in turn. |
| `hold` | Hold the keys down for `--seconds`. |
| `scroll` | Scroll by wheel notches. |
| `cursor` | Print the pointer's position as JSON on stdout: `{"x":640,"y":400}`. |

| Flag | Description | Default |
| --- | --- | --- |
| `--button <button>` | `click` only. `left`, `middle` or `right`. | `left` |
| `--count <n>` | `click` only. `1`, `2` (double-click) or `3` (triple-click). | `1` |
| `--double` | `click` only. The same as `--count 2`. Do not combine with `--count`. | off |
| `--mods <keys>` | `click`, `drag` and `scroll`. Keys held down during the action: `shift`, `ctrl`, `alt` or `super`, joined by `+`, such as `ctrl+shift`. | none |
| `--at <x>,<y>` | `scroll` only. Move the pointer here first. | current position |
| `--repeat <n>` | `key` only. Press the keys `n` times, 1 to 100. | `1` |
| `--seconds <s>` | `hold` only, and required. How long to hold the keys, 0 to 300. Decimals are allowed. | none |

- `type` takes the text as one argument. Quote it. Up to 10,000 bytes.
- `key` and `hold` take key names and combinations: `Return`, `Escape`, `ctrl+l`, `alt+Tab`.
- `scroll` moves 3 notches unless you give a number from 1 to 100.
- A sandbox created before an action existed refuses it with `desktop_outdated`. Create a new sandbox to use it.

**Examples**

```bash
div sandbox input $SB click 640 400
div sandbox input $SB click 640 400 --count 3
div sandbox input $SB click 200 300 --mods ctrl
div sandbox input $SB type 'hello world'
div sandbox input $SB key ctrl+l
div sandbox input $SB key Down --repeat 5
div sandbox input $SB hold shift --seconds 2
div sandbox input $SB scroll down 5 --at 640,400
div sandbox input $SB cursor
```

## a11y

```text
div sandbox a11y <sandbox> [--app <name>] [--depth <n>] [--hidden]
div sandbox a11y <sandbox> do <ref> <action> [text]
```

The first form prints the accessibility tree of what is on screen, as JSON on stdout. The second acts on one node.

| Flag | Description | Default |
| --- | --- | --- |
| `--app <name>` | Only this application, for example `chromium`. | all applications |
| `--depth <n>` | Maximum depth. | `60` |
| `--hidden` | Include nodes that are not on screen. | off |

**Tree output**

```json
{
  "apps": [
    {
      "ref": "n1", "role": "application", "name": "Chromium",
      "children": [
        { "ref": "n7", "role": "push button", "name": "Reload", "states": ["focusable"],
          "bounds": [96, 48, 34, 34], "actions": ["press"] },
        { "ref": "n12", "role": "entry", "name": "Address and search bar",
          "states": ["editable", "focusable", "focused"], "bounds": [140, 48, 880, 34],
          "text": "example.com" }
      ]
    }
  ],
  "nodes": 214,
  "truncated": false
}
```

| Field | Description |
| --- | --- |
| `ref` | The node's id for `do`. Valid until the tree is read again. |
| `role`, `name` | What the node is and its label. |
| `states` | For example `focusable`, `focused`, `editable`. |
| `bounds` | `[x, y, width, height]` in screenshot pixels. |
| `actions` | Actions the node supports. |
| `text` | The text of a field. |
| `nodes` | Number of nodes returned. |
| `truncated` | `true` when the tree passed 4,000 nodes and was cut. Narrow it with `--app` or `--depth`. |

Nodes with no name, text or action are left out, and their children take their place.

**Actions for `do`**

| Action | Description |
| --- | --- |
| `press` | Press a button or follow a link. |
| `focus` | Move keyboard focus to the node. |
| `set-text <text>` | Replace the text in a field. |
| `read` | Print the node's current state. |
| any name in `actions` | Run that action. |

If the node has changed since the tree was read, the action is refused. Read the tree again and retry.

**Examples**

```bash
div sandbox a11y $SB --app chromium > tree.json
div sandbox a11y $SB do n12 set-text 'https://example.com'
div sandbox a11y $SB do n7 press
```

## forward

```text
div sandbox forward <sandbox> <port>[:<local port>]
```

Makes a port on the sandbox's `127.0.0.1` available on `127.0.0.1` on your machine until you press Ctrl-C. A single number uses the same port on both sides. Requires `ssh` on your `PATH`.

| Port | Use |
| --- | --- |
| `9222` | The desktop browser's DevTools protocol, for Playwright or Puppeteer. |
| `5900` | The desktop's screen, for a VNC viewer. |

**Output**

```text
Forwarding localhost:9222 to sb-4c1e9a:9222. Press Ctrl-C to stop.
```

**Examples**

```bash
div sandbox forward $SB 9222
div sandbox forward $SB 3000:13000    # the sandbox's 3000 on your 13000
```

## token

```text
div sandbox token <sandbox> [--ability view|control] [--expires <duration>] [--origin <url>]...
```

Prints a token that opens one sandbox's desktop and screen, and nothing else. Give it to a page or a program that must not hold your API key, such as the [SDK's screen](https://docs.divergentlabs.xyz/sandboxes/sdk.md#screen). The sandbox must have no secrets.

| Flag | Description | Default |
| --- | --- | --- |
| `--ability <ability>` | `view` watches the screen and takes screenshots. `control` also sends input and starts or stops the desktop. | `control` |
| `--expires <duration>` | How long the token works: `90s`, `15m` or `1h`. Between 60 seconds and 1 hour. A number without a unit is rejected. | `15m` |
| `--origin <url>` | A page that may use the token in a browser, as a scheme and host with no path: `https://app.example.com`. Repeat for each origin, up to 10. | none |

- Without `--origin`, a request from a browser is refused. Requests from a server, which send no `Origin` header, work on every plan.
- The token stops working when it expires, when the key that minted it is revoked, or when the sandbox has secrets.

**Output.** The token on stdout, alone, so `TOKEN=$(div sandbox token $SB)` captures it. A summary on stderr:

```text
dvs_SFMyNTY.g2gDdAAAAAZtAAAAAWF...
For sb-4c1e9a · view and control · expires 2026-10-07T12:15:00Z · from https://app.example.com
```

With `--json`: `token`, `sandbox`, `abilities`, `origins` and `expires_at`.

**Examples**

```bash
TOKEN=$(div sandbox token $SB --ability view --expires 1h)
div sandbox token $SB --origin https://app.example.com --origin http://localhost:5173
```

**Errors**

| Code | When |
| --- | --- |
| `sandbox_has_secrets` | The sandbox was created with `--secret`, in any environment. Create a sandbox without secrets. |

## tunnel

```text
div sandbox tunnel <sandbox> [<port>[:<local port>]]... [--exit]
```

Makes ports on your machine available on the sandbox's `127.0.0.1`, sends the sandbox's internet traffic through your machine, or both, until you press Ctrl-C. Give at least one port or `--exit`. Requires `ssh` on your `PATH`.

| Argument or flag | Description | Default |
| --- | --- | --- |
| `<port>` | Your machine's port, available on the same port in the sandbox. | none |
| `<port>:<local port>` | Your machine's `<local port>`, available on the sandbox's `<port>`. The sandbox's port comes first, as in `forward`. | none |
| `--exit` | The sandbox's TCP traffic and DNS lookups go out through your machine, to public addresses only. Uses port 1080 on the sandbox's `127.0.0.1`. One `--exit` tunnel per sandbox at a time. | off |

- A tunnel that drops after it connects reconnects on its own. If the sandbox is stopped, the tunnel waits until it is resumed. If the sandbox is deleted, the tunnel exits 1.
- A tunnel that fails on its first attempt exits without retrying, usually because a port is already in use in the sandbox. A closed tunnel's ports can stay in use for up to a minute.
- When the tunnel ends, the sandbox's traffic goes out directly again.

**Output**

```text
Forwarding sb-4c1e9a:3000 to port 3000 on this machine.
Forwarding sb-4c1e9a:5432 to port 15432 on this machine.
Sending sb-4c1e9a's internet traffic through this machine.
Press Ctrl-C to stop.
```

**Examples**

```bash
div sandbox tunnel $SB 3000
div sandbox tunnel $SB 3000 5432:15432 --exit
```

See [Reach your machine from a sandbox](https://docs.divergentlabs.xyz/sandboxes/tunnels.md).

## Exit codes

| Code | When |
| --- | --- |
| the command's own | `exec`, and `ssh` with a command |
| `0` | The subcommand succeeded. |
| `1` | The API refused the request, the desktop is not running, or the sandbox was deleted during a tunnel. The message says what to do next. |
| `2` | A subcommand, argument or flag was typed wrong. |
| `124` | `exec` reached its `--timeout`. |
| `255` | `ssh`, `forward` or `tunnel` could not connect. |

These match [every `div` command](https://docs.divergentlabs.xyz/compute/cli/exit-codes.md).
