> ## Documentation Index
> Fetch the complete documentation index at: https://porter-adi-agent-app-creation-eval.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Sandboxes CLI

> Create, list, exec into, monitor CPU and memory usage, and terminate Porter Sandboxes from the Porter CLI

`porter sandbox` contains commands for listing, inspecting, executing commands in, monitoring CPU and memory usage of, and terminating sandboxes in the currently selected Porter project and cluster.

<Warning>
  Sandboxes are in a private beta. Please reach out to us at [support@porter.run](mailto:support@porter.run) or over Slack if you are interested in joining.
</Warning>

## Prerequisites

* You've logged in to the Porter CLI after running [porter auth login](/standard/cli/command-reference/porter-auth)
* You're connected to the correct project by running [porter config set-project](/standard/cli/command-reference/porter-config)
* You're connected to the correct cluster by running [porter config set-cluster](/standard/cli/command-reference/porter-config)
* Sandboxes are enabled on the selected AWS cluster

If the CLI cannot find a selected project or cluster, it asks you to run `porter config` or pass `--project` and `--cluster`.

***

## `porter sandbox create`

Creates a sandbox from a container image in the current project and cluster. The image accepts a tag (`alpine:3.20`) or a digest (`repo@sha256:<digest>`).

**Usage:**

```bash theme={null}
porter sandbox create <image> [-- <command> [args...]] [flags]
```

**Options:**

| Flag           | Description                                                                                                                                                         |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--name`       | Cluster-unique sandbox name. Use lowercase letters, numbers, and hyphens; start and end with a letter or number. Use this name with `exec`, `logs`, and `terminate` |
| `--command`    | Override the image entrypoint. Repeat for each argv element                                                                                                         |
| `--arg`        | Argument passed to the command. Repeatable                                                                                                                          |
| `-e, --env`    | Environment variable in `KEY=VALUE` form. Repeatable                                                                                                                |
| `--env-group`  | Environment group on the cluster whose variables are injected into the sandbox. Repeatable                                                                          |
| `--tag`        | Tag in `key=value` form. Repeatable                                                                                                                                 |
| `--volume`     | Volume mount in `mount_path=volume-ref` form, where `volume-ref` is a volume name or ID. Repeatable. The mount path must be absolute                                |
| `--ttl`        | Maximum sandbox lifetime as a Go duration, such as `30m` or `2h`. Defaults to no limit                                                                              |
| `-o, --output` | Output format: `text` or `json`                                                                                                                                     |

Use the positional form after `--` for common one-shot commands. Use `--command` and `--arg` when scripting individual argv elements.

Volume values can be volume names or volume IDs. The CLI resolves names first, then falls back to treating the value as an ID.

`--env-group` injects the variables of a named [environment group](/applications/configure/environment-groups) on the cluster. Values are resolved to the group's latest version at create time and do not update afterwards. On a key conflict, a later `--env-group` wins over an earlier one, and an explicit `--env` wins over any group value. Creation fails if a named group does not exist on the cluster or has not synced yet.

`--ttl` bounds the sandbox's lifetime regardless of its main process: once the duration elapses, counted from creation, Porter terminates the sandbox the same way an explicit `terminate` does. See [sandbox lifetime](/sandboxes/overview#sandbox-lifetime).

Sandbox names currently cannot be reused, even after the sandbox is terminated. Omit `--name` only for one-off sandboxes where you do not need stable lookup later.

The sandbox runs as long as its main process. When the process exits, the sandbox moves to `succeeded` or `failed` and stops accepting exec calls, so pass a long-running command if you plan to exec into the sandbox. See [sandbox lifetime](/sandboxes/overview#sandbox-lifetime).

<CodeGroup>
  ```bash Create Sandbox theme={null}
  porter sandbox create alpine:3.20
  ```

  ```bash Named Sandbox theme={null}
  porter sandbox create alpine:3.20 --name web -- sleep 3600
  ```

  ```bash With Env and Tags theme={null}
  porter sandbox create ghcr.io/example/tool:latest --env PORT=8080 --tag env=dev --tag owner=me
  ```

  ```bash With Volume theme={null}
  porter sandbox create ubuntu:24.04 --volume /workspace=my-data -- bash -lc 'ls -la /workspace'
  ```

  ```bash With Env Group theme={null}
  porter sandbox create alpine:3.20 --env-group my-env-group -- sleep 3600
  ```

  ```bash With TTL theme={null}
  porter sandbox create alpine:3.20 --ttl 2h -- sleep 7200
  ```

  ```bash JSON Output theme={null}
  porter sandbox create ubuntu:24.04 --volume /workspace=my-data --command bash --arg -lc --arg 'ls -la' -o json
  ```
</CodeGroup>

***

## `porter sandbox list`

Lists sandboxes in the current project and cluster. The command auto-paginates through the API and sorts results most-recent-first.

**Usage:**

```bash theme={null}
porter sandbox list [flags]
```

**Options:**

| Flag           | Description                                                                                  |
| -------------- | -------------------------------------------------------------------------------------------- |
| `--phase`      | Filter by phase. Defaults to hiding `terminated` sandboxes. Use `all` to include every phase |
| `--tag`        | Filter by tag in `key=value` format. Repeat the flag to require multiple tags                |
| `-o, --output` | Output format: `table`, `plain`, or `json`                                                   |

**Phases:**

| Phase        | Description                                             |
| ------------ | ------------------------------------------------------- |
| `queued`     | Accepted by the API and waiting for capacity            |
| `creating`   | Runtime is being prepared and the container is starting |
| `running`    | Sandbox is ready and can accept exec calls              |
| `succeeded`  | Sandbox command completed successfully                  |
| `failed`     | Sandbox command or runtime failed                       |
| `terminated` | Sandbox was explicitly terminated                       |
| `all`        | Includes every phase when used with `--phase`           |

**Output formats:**

| Format  | Description                                                                          |
| ------- | ------------------------------------------------------------------------------------ |
| `table` | Colorized table for terminal output                                                  |
| `plain` | Tab-separated rows with a header. Used by default when output is piped or redirected |
| `json`  | JSON array, recommended for scripts                                                  |

Plain output includes these columns:

| Column    | Description                     |
| --------- | ------------------------------- |
| `NAME`    | Sandbox name                    |
| `IMAGE`   | Container image                 |
| `PHASE`   | Current sandbox phase           |
| `CREATED` | Creation timestamp              |
| `STARTED` | Start timestamp, when available |
| `EXIT`    | Exit code, when available       |
| `TAGS`    | Sandbox tags                    |

<CodeGroup>
  ```bash List Sandboxes theme={null}
  porter sandbox list
  ```

  ```bash Include Terminated theme={null}
  porter sandbox list --phase all
  ```

  ```bash Filter by Phase theme={null}
  porter sandbox list --phase running
  ```

  ```bash Filter by Tags theme={null}
  porter sandbox list --tag workflow=agent-run --tag run=2026-06-17
  ```

  ```bash JSON Output theme={null}
  porter sandbox list -o json
  ```

  ```bash Script Running Names theme={null}
  porter sandbox list -o json | jq -r '.[] | select(.phase == "running") | .name'
  ```
</CodeGroup>

***

## `porter sandbox exec`

Runs a command in a running sandbox, identified by name. Non-interactive exec prints stdout and stderr; interactive exec opens a shell session.

**Usage:**

```bash theme={null}
porter sandbox exec <sandbox> [-it] -- <command> [args...] [flags]
```

**Options:**

| Flag                | Description                                                          |
| ------------------- | -------------------------------------------------------------------- |
| `-c, --command`     | Shell-style command string to run through `sh -c` inside the sandbox |
| `-i, --interactive` | Keep stdin open and stream it to the sandbox                         |
| `-t, --tty`         | Allocate a TTY for an interactive shell                              |

Do not combine `--command` with positional command arguments.

**Exit codes:**

| Exit code | Meaning                                                 |
| --------- | ------------------------------------------------------- |
| `0`       | Command succeeded                                       |
| `1`       | Operational error or propagated sandbox command failure |
| `2`       | CLI usage error                                         |
| `3`       | Sandbox is not in the `running` phase                   |

Only `running` sandboxes accept exec calls.

<CodeGroup>
  ```bash List Files theme={null}
  porter sandbox exec abc123 -- ls -la /workspace
  ```

  ```bash Check Python theme={null}
  porter sandbox exec abc123 -- python --version
  ```

  ```bash Shell Command theme={null}
  porter sandbox exec abc123 --command "echo hi && ls /workspace"
  ```

  ```bash Inline Script theme={null}
  porter sandbox exec abc123 -- python -c 'print("ok")'
  ```

  ```bash Interactive Shell theme={null}
  porter sandbox exec web -it -- sh
  ```
</CodeGroup>

***

## `porter sandbox logs`

Fetches and prints a batch of log lines for a sandbox. By default, the CLI requests logs from the last hour with a limit of 500 lines.

**Usage:**

```bash theme={null}
porter sandbox logs <sandbox> [flags]
```

**Options:**

| Flag              | Description                                                                                       |
| ----------------- | ------------------------------------------------------------------------------------------------- |
| `--since`         | Lookback window as a Go duration, such as `30m` or `1h30m`. Defaults to `1h`                      |
| `--limit`         | Maximum number of log lines. Defaults to `500`; server cap is `5000`; `0` uses the server default |
| `--tail`          | Alias for `--limit`. When greater than `0`, it overrides `--limit`                                |
| `--level`         | Client-side filter: `info`, `warning`, or `error`                                                 |
| `--no-timestamps` | Suppress the leading RFC3339 timestamp on each line                                               |

Each rendered log line uses this format:

```text theme={null}
<timestamp> [<level>] <text>
```

<CodeGroup>
  ```bash Recent Logs theme={null}
  porter sandbox logs abc123
  ```

  ```bash Last 15 Minutes theme={null}
  porter sandbox logs abc123 --since 15m --tail 100
  ```

  ```bash Errors Only theme={null}
  porter sandbox logs abc123 --level error --no-timestamps
  ```

  ```bash Search Logs theme={null}
  porter sandbox logs abc123 --tail 200 | grep -i 'panic\|fatal'
  ```
</CodeGroup>

***

## `porter sandbox metrics`

Use this command to monitor a sandbox's resource usage: how much CPU and memory it is consuming and how close it is to its limits.

It prints p50 and p90 CPU and memory usage over a lookback window for a running sandbox, alongside the sandbox's CPU and memory limits and each percentile's utilization as a percentage of that limit. Only `running` sandboxes report metrics.

**Usage:**

```bash theme={null}
porter sandbox metrics <sandbox> [flags]
```

**Options:**

| Flag           | Description                                                                                       |
| -------------- | ------------------------------------------------------------------------------------------------- |
| `--since`      | Lookback window as a Go duration, such as `30m` or `2h`. Bounded to `[3m, 24h]`. Defaults to `1h` |
| `-o, --output` | Output format: `table`, `plain`, or `json`. Defaults to `table` on a TTY and `plain` when piped   |

CPU is reported in cores and memory in bytes. Utilization is each percentile divided by the sandbox's limit, as a percentage; it can exceed 100% because the limit is a throttling and OOM threshold, not a hard cap on the reported sample. Memory values include page cache and slightly overestimate resident memory.

**Output formats:**

| Format  | Description                                                                                  |
| ------- | -------------------------------------------------------------------------------------------- |
| `table` | Human-friendly box table with a `window:` footer. Used by default on a terminal              |
| `plain` | Tab-separated numeric rows with a header. Used by default when output is piped or redirected |
| `json`  | Single-line JSON record, recommended for scripts and agents                                  |

Plain output has one row per metric (`cpu_cores`, `mem_bytes`) with these columns:

| Column           | Description                              |
| ---------------- | ---------------------------------------- |
| `metric`         | Metric name                              |
| `p50`            | Median value over the window             |
| `p90`            | 90th-percentile value over the window    |
| `limit`          | The sandbox's limit for this metric      |
| `p50_util_pct`   | `p50` as a percentage of `limit`         |
| `p90_util_pct`   | `p90` as a percentage of `limit`         |
| `window_seconds` | Length of the lookback window in seconds |

The JSON record carries the same values at full precision, plus a `has_data` boolean that is `false` when no samples were collected in the window.

<CodeGroup>
  ```bash Recent Metrics theme={null}
  porter sandbox metrics web
  ```

  ```bash Last 30 Minutes theme={null}
  porter sandbox metrics web --since 30m
  ```

  ```bash JSON Output theme={null}
  porter sandbox metrics web -o json
  ```

  ```bash Script p90 CPU Utilization theme={null}
  porter sandbox metrics web -o json | jq '.cpu_util_p90_pct'
  ```
</CodeGroup>

The table output looks like this:

```text theme={null}
┌──────────────┬────────────────────┬────────────────────┐
│    METRIC    │        P50         │        P90         │
├──────────────┼────────────────────┼────────────────────┤
│ cpu cores    │ 0.001 cores (0.1%) │ 0.003 cores (0.3%) │
│ cpu limit    │ 1.000 cores        │                    │
│ memory       │ 1.27 GiB (63.6%)   │ 2.54 GiB (126.9%)  │
│ memory limit │ 2.00 GiB           │                    │
└──────────────┴────────────────────┴────────────────────┘

window: 1h0m0s
```

***

## `porter sandbox terminate`

Terminates one sandbox by name, or terminates many sandboxes with `--all`.

**Usage:**

```bash theme={null}
porter sandbox terminate <sandbox> [flags]
porter sandbox terminate --all [flags]
```

**Options:**

| Flag        | Description                                                           |
| ----------- | --------------------------------------------------------------------- |
| `--all`     | Terminate every actionable sandbox in the current project and cluster |
| `--dry-run` | Print the sandboxes that would be terminated without terminating them |
| `--tag`     | Scope bulk termination by tag in `key=value` format. Requires `--all` |

**Behavior:**

| Case                         | Behavior                                                                       |
| ---------------------------- | ------------------------------------------------------------------------------ |
| `--all`                      | No interactive confirmation is shown                                           |
| Already terminated sandboxes | Skipped                                                                        |
| `404` during `--all`         | Treated as success because another caller may have already deleted the sandbox |

<CodeGroup>
  ```bash Terminate One theme={null}
  porter sandbox terminate abc123
  ```

  ```bash Dry Run Bulk Terminate theme={null}
  porter sandbox terminate --all --dry-run
  ```

  ```bash Terminate by Tag Dry Run theme={null}
  porter sandbox terminate --all --tag workflow=agent-run --dry-run
  ```

  ```bash Terminate by Tag theme={null}
  porter sandbox terminate --all --tag workflow=agent-run
  ```
</CodeGroup>

***

## `porter sandbox volume`

Manages persistent volumes that sandboxes can mount at launch. Create a volume first, then reference it from `porter sandbox create` with `--volume <mount_path>=<volume-ref>`, where `volume-ref` is a volume name or ID.

### `porter sandbox volume list`

Lists sandbox volumes in the current project and cluster, sorted most-recent-first.

**Usage:**

```bash theme={null}
porter sandbox volume list [flags]
```

**Options:**

| Flag           | Description                                |
| -------------- | ------------------------------------------ |
| `-o, --output` | Output format: `table`, `plain`, or `json` |

**Volume phases:**

| Phase     | Description                                                            |
| --------- | ---------------------------------------------------------------------- |
| `pending` | The volume was created and is waiting for the underlying claim to bind |
| `ready`   | The volume is ready to mount into sandboxes                            |
| `failed`  | The volume failed to provision                                         |

**Output formats:**

| Format  | Description                                                                          |
| ------- | ------------------------------------------------------------------------------------ |
| `table` | Colorized table for terminal output                                                  |
| `plain` | Tab-separated rows with a header. Used by default when output is piped or redirected |
| `json`  | JSON array, recommended for scripts                                                  |

Plain output includes these columns:

| Column     | Description                                |
| ---------- | ------------------------------------------ |
| `NAME`     | Volume name                                |
| `PHASE`    | Current volume phase                       |
| `ATTACHED` | Attached sandboxes, or `-` when unattached |
| `CREATED`  | Creation timestamp                         |

<CodeGroup>
  ```bash List Volumes theme={null}
  porter sandbox volume list
  ```

  ```bash JSON Output theme={null}
  porter sandbox volume list -o json
  ```

  ```bash Script Volume Names theme={null}
  porter sandbox volume list -o json | jq -r '.[].name'
  ```

  ```bash Ready Volume Names theme={null}
  porter sandbox volume list | awk -F'\t' '$2=="ready" {print $1}'
  ```
</CodeGroup>

### `porter sandbox volume create`

Creates a persistent volume on the current cluster. The volume name may contain lowercase letters, numbers, and hyphens, and must start and end with a letter or number. Omit the name only for one-off volumes where you do not need stable lookup later.

Volumes start in the `pending` phase. Sandboxes that mount them wait for the underlying claim to bind, so `porter sandbox create` does not need a separate wait step.

Volume names must be unique within a cluster for the lifetime of the volume. After a volume is deleted, its name can be used again.

**Usage:**

```bash theme={null}
porter sandbox volume create [name] [flags]
```

**Options:**

| Flag           | Description                     |
| -------------- | ------------------------------- |
| `-o, --output` | Output format: `text` or `json` |

<CodeGroup>
  ```bash Create Named Volume theme={null}
  porter sandbox volume create my-data
  ```

  ```bash Create Generated Name theme={null}
  porter sandbox volume create
  ```

  ```bash JSON Output theme={null}
  porter sandbox volume create my-data -o json
  ```
</CodeGroup>

### `porter sandbox volume get`

Shows a single sandbox volume by name, including phase, creation time, and currently attached sandboxes.

**Usage:**

```bash theme={null}
porter sandbox volume get <name> [flags]
```

**Options:**

| Flag           | Description                     |
| -------------- | ------------------------------- |
| `-o, --output` | Output format: `text` or `json` |

<CodeGroup>
  ```bash Get by Name theme={null}
  porter sandbox volume get my-data
  ```

  ```bash JSON Output theme={null}
  porter sandbox volume get my-data -o json
  ```
</CodeGroup>

### `porter sandbox volume files`

Lists the files and directories under a path inside a volume. Omit the path to list from the volume root. The server walks the tree up to an entry budget; directories it could not fully read are marked truncated. List them directly to see more.

**Usage:**

```bash theme={null}
porter sandbox volume files <name|id> [path] [flags]
```

**Options:**

| Flag       | Description                                                             |
| ---------- | ----------------------------------------------------------------------- |
| `--search` | Only show entries whose name contains this substring (case-insensitive) |
| `--json`   | Print the full nested listing as JSON instead of a table of paths       |

<CodeGroup>
  ```bash List From Root theme={null}
  porter sandbox volume files my-data
  ```

  ```bash List a Subdirectory theme={null}
  porter sandbox volume files my-data models/checkpoints
  ```

  ```bash Filter by Name theme={null}
  porter sandbox volume files my-data --search .bin
  ```

  ```bash JSON Output theme={null}
  porter sandbox volume files my-data --json | jq '.entries[].name'
  ```
</CodeGroup>

### `porter sandbox volume read`

Streams a file's raw bytes from a volume to stdout. Redirect stdout to save the file locally, or use `--range` to read part of a large file.

**Usage:**

```bash theme={null}
porter sandbox volume read <name|id> <path> [flags]
```

**Options:**

| Flag      | Description                                                                                 |
| --------- | ------------------------------------------------------------------------------------------- |
| `--range` | Single byte range to read (`start-end`, `start-`, or `-length`). Defaults to the whole file |

Reading a path that does not exist fails with a not-found error.

<CodeGroup>
  ```bash Print a File theme={null}
  porter sandbox volume read my-data config/app.yaml
  ```

  ```bash Save Locally theme={null}
  porter sandbox volume read my-data models/model.bin > model.bin
  ```

  ```bash Read a Byte Range theme={null}
  porter sandbox volume read my-data logs/app.log --range 0-4095
  ```
</CodeGroup>

### `porter sandbox volume write`

Uploads a file into a volume at a path relative to the volume root. Parent directories are created as needed, and an existing file at the path is replaced. Content comes from stdin unless `--file` names a local file.

The write is staged to a temporary file and renamed into place, so a failed or interrupted upload leaves the previous contents alone rather than a truncated file. You can write to a volume whether or not a sandbox has it mounted.

**Usage:**

```bash theme={null}
porter sandbox volume write <name|id> <path> [flags]
```

**Options:**

| Flag     | Description                                     |
| -------- | ----------------------------------------------- |
| `--file` | Local file to upload. Defaults to reading stdin |

A single write is capped at 1 GiB, and a request from outside the cluster must finish within 30 seconds; write very large files from inside a sandbox that mounts the volume.

<CodeGroup>
  ```bash Upload a Local File theme={null}
  porter sandbox volume write my-data config/app.yaml --file ./app.yaml
  ```

  ```bash Redirect a File to stdin theme={null}
  porter sandbox volume write my-data config/app.yaml < app.yaml
  ```

  ```bash Pipe Content theme={null}
  echo hello | porter sandbox volume write my-data notes.txt
  ```
</CodeGroup>

### `porter sandbox volume move`

Moves a file or directory to a new path inside one volume. The destination is the entry's full new path, not a directory to drop it into, so a move renames and relocates in one call. A directory moves with everything under it.

**Usage:**

```bash theme={null}
porter sandbox volume move <name|id> <from> <to>
```

The destination's parent directory must already exist, and nothing is replaced. The server refuses a move onto an occupied path, and the volume root cannot be moved or overwritten.

<CodeGroup>
  ```bash Rename a File theme={null}
  porter sandbox volume move my-data notes.txt archive/notes.txt
  ```

  ```bash Move a Directory theme={null}
  porter sandbox volume move my-data models/v1 models/v2
  ```
</CodeGroup>

### `porter sandbox volume delete`

Deletes a sandbox volume by name.

**Usage:**

```bash theme={null}
porter sandbox volume delete <name>
```

The server rejects deletion while the volume is attached to any sandbox. Terminate or recreate the attached sandboxes first.

<CodeGroup>
  ```bash Delete by Name theme={null}
  porter sandbox volume delete my-data
  ```
</CodeGroup>

## Common Workflows

| Workflow                               | Command                                                                                                          |
| -------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| Create a named sandbox                 | `porter sandbox create alpine:3.20 --name web -- sleep 3600`                                                     |
| Create a sandbox that cleans itself up | `porter sandbox create alpine:3.20 --ttl 2h -- sleep 7200`                                                       |
| Create a sandbox with an env group     | `porter sandbox create alpine:3.20 --env-group my-env-group -- sleep 3600`                                       |
| Create and mount a volume              | `porter sandbox volume create my-data && porter sandbox create ubuntu:24.04 --volume /workspace=my-data -- bash` |
| Upload a local file to a volume        | `porter sandbox volume write my-data config/app.yaml --file ./app.yaml`                                          |
| Read a file back from a volume         | `porter sandbox volume read my-data config/app.yaml`                                                             |
| List running sandboxes                 | `porter sandbox list --phase running`                                                                            |
| Get running sandbox names for a script | `porter sandbox list -o json \| jq -r '.[] \| select(.phase == "running") \| .name'`                             |
| Run a smoke command                    | `porter sandbox exec <sandbox-name> -- python -c 'print("ok")'`                                                  |
| Fetch recent errors                    | `porter sandbox logs <sandbox-name> --since 30m --level error`                                                   |
| Check CPU and memory usage             | `porter sandbox metrics <sandbox-name> --since 30m`                                                              |
| Preview tagged cleanup                 | `porter sandbox terminate --all --tag run=<run-id> --dry-run`                                                    |
| Clean up tagged sandboxes              | `porter sandbox terminate --all --tag run=<run-id>`                                                              |

## Related Docs

* [Sandboxes Overview](/sandboxes/overview)
* [Sandboxes Getting Started](/sandboxes/getting-started)
* [Python Sandbox SDK quickstart](/sandboxes/sdk/python/quickstart)
* [TypeScript Sandbox SDK quickstart](/sandboxes/sdk/typescript/quickstart)
