> ## Documentation Index
> Fetch the complete documentation index at: https://docs.declaw.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Sandbox

> Synchronous Sandbox class: create, connect, kill, inspect, extend timeout, pause, snapshot, and retrieve metrics.

```python theme={null}
from declaw import Sandbox
```

`Sandbox` is the synchronous entry point for all sandbox operations. Every instance exposes a `.commands` sub-module for running commands and a `.files` sub-module for filesystem operations.

## Class methods

### `Sandbox.create()`

Create a new sandbox and return a connected `Sandbox` instance.

```python theme={null}
sbx = Sandbox.create(
    template="base",
    timeout=300,
    envs={"MY_VAR": "hello"},
    api_key="your-api-key",
    domain="104.198.24.180:8080",
)
```

<ParamField body="template" type="str | None" default="'base'">
  Template ID or alias to boot. Defaults to `'base'` (Ubuntu 22.04).
</ParamField>

<ParamField body="timeout" type="int | None" default="300">
  Sandbox lifetime in seconds. The sandbox is killed automatically when the
  timeout expires unless `lifecycle.on_timeout` is set to `'pause'`.
</ParamField>

<ParamField body="metadata" type="dict[str, str] | None" default="None">
  Arbitrary key-value pairs attached to the sandbox. Searchable via
  `Sandbox.list()`.
</ParamField>

<ParamField body="envs" type="dict[str, str] | None" default="None">
  Environment variables injected into the sandbox at boot time.
</ParamField>

<ParamField body="secure" type="bool" default="True">
  Whether to enable the edge proxy security proxy. Set to `False` only for trusted
  workloads where TLS interception overhead is unacceptable.
</ParamField>

<ParamField body="allow_internet_access" type="bool" default="True">
  When `False`, all outbound traffic is blocked by adding `deny_out:   ["0.0.0.0/0"]` to the network config. Use `network` for fine-grained
  control.
</ParamField>

<ParamField body="network" type="dict | SandboxNetworkOpts | None" default="None">
  Fine-grained network configuration. Overrides `allow_internet_access` when
  provided. See [SandboxNetworkOpts](/sdks/python/security-policy#sandboxnetworkopts).
</ParamField>

<ParamField body="security" type="SecurityPolicy | None" default="None">
  Full security policy including PII detection, injection defense,
  transformations, audit, and env masking. See
  [SecurityPolicy](/sdks/python/security-policy).
</ParamField>

<ParamField body="lifecycle" type="SandboxLifecycle | None" default="None">
  Controls sandbox behaviour on timeout. See
  [SandboxLifecycle](#sandboxlifecycle).
</ParamField>

<ParamField body="api_key" type="str | None" default="$DECLAW_API_KEY">
  API key override for this call.
</ParamField>

<ParamField body="domain" type="str | None" default="$DECLAW_DOMAIN">
  Domain override for this call. Supports `host:port` format.
</ParamField>

<ParamField body="request_timeout" type="float | None" default="None">
  Per-request HTTP timeout in seconds.
</ParamField>

**Returns** `Sandbox`

***

### `Sandbox.connect()`

Connect to an existing sandbox by ID without creating a new one.

```python theme={null}
sbx = Sandbox.connect(
    sandbox_id="abc123",
    api_key="your-api-key",
    domain="104.198.24.180:8080",
)
```

<ParamField body="sandbox_id" type="str" required>
  The ID of the sandbox to connect to.
</ParamField>

<ParamField body="timeout" type="int | None" default="None">
  Optionally update the sandbox timeout on connection.
</ParamField>

<ParamField body="api_key" type="str | None" default="$DECLAW_API_KEY">
  API key override.
</ParamField>

<ParamField body="domain" type="str | None" default="$DECLAW_DOMAIN">
  Domain override.
</ParamField>

<ParamField body="request_timeout" type="float | None" default="None">
  Per-request HTTP timeout in seconds.
</ParamField>

**Returns** `Sandbox`

***

### `Sandbox.list()`

List sandboxes with optional filtering and pagination.

```python theme={null}
result = Sandbox.list(
    query=SandboxQuery(state=[SandboxState.RUNNING]),
    limit=20,
    api_key="your-api-key",
    domain="104.198.24.180:8080",
)
sandboxes = result.get("sandboxes", [])
```

<ParamField body="query" type="SandboxQuery | None" default="None">
  Filter by metadata or state. See [SandboxQuery](#sandboxquery).
</ParamField>

<ParamField body="limit" type="int | None" default="None">
  Maximum number of results to return.
</ParamField>

<ParamField body="next_token" type="str | None" default="None">
  Pagination cursor from a previous `list()` call.
</ParamField>

<ParamField body="api_key" type="str | None" default="$DECLAW_API_KEY">
  API key override.
</ParamField>

<ParamField body="domain" type="str | None" default="$DECLAW_DOMAIN">
  Domain override.
</ParamField>

<ParamField body="request_timeout" type="float | None" default="None">
  Per-request HTTP timeout in seconds.
</ParamField>

**Returns** `dict` — raw JSON containing `sandboxes` list and optional `next_token`.

***

## Instance methods

### `sbx.kill()`

Kill and destroy the sandbox. After this call the sandbox ID becomes invalid.

```python theme={null}
killed = sbx.kill()
```

<ParamField body="request_timeout" type="float | None" default="None">
  Per-request HTTP timeout in seconds.
</ParamField>

**Returns** `bool` — `True` if the sandbox was killed, `False` if it was already dead.

***

### `sbx.is_running()`

Check whether the sandbox is currently in the `running` state.

```python theme={null}
if sbx.is_running():
    print("sandbox is alive")
```

<ParamField body="request_timeout" type="float | None" default="None">
  Per-request HTTP timeout in seconds.
</ParamField>

**Returns** `bool`

***

### `sbx.set_timeout()`

Update the sandbox timeout. The new timeout is relative to the current time.

```python theme={null}
sbx.set_timeout(600)  # extend to 10 minutes from now
```

<ParamField body="timeout" type="int" required>
  New timeout in seconds.
</ParamField>

<ParamField body="request_timeout" type="float | None" default="None">
  Per-request HTTP timeout in seconds.
</ParamField>

**Returns** `None`

***

### `sbx.get_info()`

Fetch the current metadata and state of the sandbox.

```python theme={null}
info = sbx.get_info()
print(info.state)       # SandboxState.RUNNING
print(info.started_at)  # datetime.datetime
```

<ParamField body="request_timeout" type="float | None" default="None">
  Per-request HTTP timeout in seconds.
</ParamField>

**Returns** `SandboxInfo`

***

### `sbx.get_metrics()`

Retrieve CPU, memory, and disk usage metrics for a time range.

```python theme={null}
import datetime

metrics = sbx.get_metrics(
    start=datetime.datetime.utcnow() - datetime.timedelta(minutes=5),
    end=datetime.datetime.utcnow(),
)
for m in metrics:
    print(m.cpu_usage_percent, m.memory_usage_mb)
```

<ParamField body="start" type="datetime.datetime | None" default="None">
  Start of the time range. Defaults to beginning of sandbox lifetime.
</ParamField>

<ParamField body="end" type="datetime.datetime | None" default="None">
  End of the time range. Defaults to now.
</ParamField>

<ParamField body="request_timeout" type="float | None" default="None">
  Per-request HTTP timeout in seconds.
</ParamField>

**Returns** `list[SandboxMetrics]`

***

### `sbx.pause()`

Pause a running sandbox, preserving its in-memory state for later resumption.

```python theme={null}
sbx.pause()
```

<ParamField body="request_timeout" type="float | None" default="None">
  Per-request HTTP timeout in seconds.
</ParamField>

**Returns** `None`

***

### `sbx.resume()`

Resume a previously paused sandbox.

```python theme={null}
sbx.resume()
```

<ParamField body="request_timeout" type="float | None" default="None">
  Per-request HTTP timeout in seconds.
</ParamField>

**Returns** `None`

***

### `sbx.create_snapshot()`

Create a snapshot of the sandbox. The snapshot can be used as a template ID
to boot new sandboxes from a known state.

```python theme={null}
snap = sbx.create_snapshot()
print(snap.snapshot_id)
```

<ParamField body="request_timeout" type="float | None" default="None">
  Per-request HTTP timeout in seconds.
</ParamField>

**Returns** `SnapshotInfo`

***

### `sbx.snapshot()`

Create a manual snapshot of this sandbox. Manual snapshots accumulate — every
call creates a new persistent checkpoint that survives `sbx.kill()`. Use
[`Sandbox.restore()`](#sandbox-restore) or [`sbx.list_snapshots()`](#sbx-list_snapshots)
to retrieve and fork from them.

```python theme={null}
snap = sbx.snapshot()
print(snap.snapshot_id)
```

<ParamField body="request_timeout" type="float | None" default="None">
  Per-request HTTP timeout in seconds.
</ParamField>

**Returns** `Snapshot`

***

### `sbx.list_snapshots()`

List all snapshots (periodic, pause, and manual) for this sandbox, newest first.

```python theme={null}
for snap in sbx.list_snapshots():
    print(snap.snapshot_id, snap.created_at)
```

<ParamField body="request_timeout" type="float | None" default="None">
  Per-request HTTP timeout in seconds.
</ParamField>

**Returns** `list[Snapshot]`

***

### `Sandbox.restore()`

Restore a sandbox from a snapshot. The restored sandbox may run on a different
worker than the original. Returns a usable `Sandbox` instance already connected
to the restored sandbox.

```python theme={null}
sbx = Sandbox.restore("sbx-a1b2c3d4", snapshot_id="snap-xyz")
sbx.commands.run("echo restored")
```

<ParamField body="sandbox_id" type="str" required>
  The sandbox to restore.
</ParamField>

<ParamField body="snapshot_id" type="str | None" default="None">
  Specific snapshot to restore from. If omitted, the most recent snapshot is
  used (preference order: pause > periodic > manual).
</ParamField>

<ParamField body="api_key" type="str | None" default="$DECLAW_API_KEY">
  API key override.
</ParamField>

<ParamField body="domain" type="str | None" default="$DECLAW_DOMAIN">
  Domain override.
</ParamField>

<ParamField body="request_timeout" type="float | None" default="None">
  Per-request HTTP timeout in seconds.
</ParamField>

**Returns** `Sandbox`

***

### `sbx.get_host()`

Return the URL that reverse-proxies HTTP traffic to the given port inside the sandbox. Requires `allow_public_traffic` to be enabled in the sandbox's network config (the default).

```python theme={null}
url = sbx.get_host(8080)
# https://api.declaw.ai/sandboxes/sbx-.../ports/8080
```

<ParamField body="port" type="int" required>
  The port number to proxy to inside the sandbox.
</ParamField>

**Returns:** `str` — fully qualified HTTPS URL for the port proxy endpoint.

***

### `sbx.get_mcp_url()`

Return the URL for an MCP server listening on port 50005 inside the sandbox. Equivalent to `sbx.get_host(50005) + "/mcp"`.

```python theme={null}
url = sbx.get_mcp_url()
# https://api.declaw.ai/sandboxes/sbx-.../ports/50005/mcp
```

**Returns:** `str`

***

### `sbx.close()`

Close the underlying HTTP client and release connection pool resources. Does
not kill the sandbox. Call this when you are done with the object but want the
sandbox to keep running.

```python theme={null}
sbx.close()
```

***

## Context manager

`Sandbox` supports the context manager protocol. `__exit__` closes the HTTP client but does **not** kill the sandbox. Call `sbx.kill()` explicitly inside the block if you want the sandbox destroyed.

```python theme={null}
with Sandbox.create(api_key="key", domain="host:8080") as sbx:
    result = sbx.commands.run("python3 --version")
    print(result.stdout)
    sbx.kill()
```

***

## Properties

| Property         | Type         | Description                |
| ---------------- | ------------ | -------------------------- |
| `sbx.sandbox_id` | `str`        | Unique sandbox identifier. |
| `sbx.commands`   | `Commands`   | Commands sub-module.       |
| `sbx.files`      | `Filesystem` | Filesystem sub-module.     |
| `sbx.pty`        | `Pty`        | PTY sub-module.            |

***

## Data models

### `SandboxInfo`

```python theme={null}
@dataclass
class SandboxInfo:
    sandbox_id: str
    template_id: str
    name: str
    metadata: dict[str, str]
    started_at: datetime.datetime | None
    end_at: datetime.datetime | None
    state: SandboxState
```

### `SandboxState`

```python theme={null}
class SandboxState(str, Enum):
    LIVE     = "live"
    RUNNING  = "running"
    PAUSED   = "paused"
    CREATING = "creating"
    KILLED   = "killed"
```

### `SandboxMetrics`

```python theme={null}
@dataclass
class SandboxMetrics:
    timestamp: datetime.datetime
    cpu_usage_percent: float
    memory_usage_mb: float
    disk_usage_mb: float
```

### `SandboxQuery`

```python theme={null}
@dataclass
class SandboxQuery:
    metadata: dict[str, str] | None = None
    state: list[SandboxState] | None = None
```

### `SandboxLifecycle`

```python theme={null}
@dataclass
class SandboxLifecycle:
    on_timeout: str = "kill"   # "kill" or "pause"
    auto_resume: bool = False
```

### `SnapshotInfo`

```python theme={null}
@dataclass
class SnapshotInfo:
    snapshot_id: str
    sandbox_id: str
    created_at: datetime.datetime | None
```
