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

# GMI Sandbox SDK Reference

> Python SDK reference for GMI Sandbox control-plane and data-plane APIs.

# GMI Sandbox SDK Reference

Python SDK for the GMI Sandbox control plane and sandbox data plane.

## Installation

```bash theme={null}
python -m pip install gmi-sandbox-sdk
```

The SDK requires Python 3.9 or newer.

## Configuration

The client reads these environment variables when explicit arguments are not provided:

| Variable               | Default                  | Description                                          |
| ---------------------- | ------------------------ | ---------------------------------------------------- |
| `GMI_SANDBOX_API_KEY`  | none                     | Bearer API key                                       |
| `GMI_SANDBOX_IDC_NAME` | organization default IDC | Optional. Set only when targeting a non-default IDC. |

```bash theme={null}
export GMI_SANDBOX_API_KEY="your-api-key"
```

## Client

```python theme={null}
from sandbox_sdk import SandboxClient

client = SandboxClient()
```

Explicit configuration:

```python theme={null}
client = SandboxClient(
    api_key="your-api-key",
    timeout=30.0,
)
```

Constructor arguments:

| Argument    | Type             | Description                                                                                     |
| ----------- | ---------------- | ----------------------------------------------------------------------------------------------- |
| `api_key`   | `str \| None`    | API key. Falls back to `GMI_SANDBOX_API_KEY`.                                                   |
| `base_url`  | `str \| None`    | Optional control-plane URL for non-default API endpoints. Falls back to `GMI_SANDBOX_BASE_URL`. |
| `timeout`   | `float`          | Transport timeout in seconds. Default: `30.0`.                                                  |
| `transport` | callable \| None | Optional transport for tests or custom networking.                                              |

`client.health()` returns local client information:

```python theme={null}
{
    "status": "ok",
    "baseUrl": "https://console.gmicloud.ai/api/v2",
    "authenticated": True,
}
```

## Basic Workflow

```python theme={null}
from sandbox_sdk import SandboxClient

client = SandboxClient()

sandbox = client.sandboxes.create(
    template_id="template-id",
    idempotency_key="create-request-1",
)

sandbox.connect(timeout=300)
execution = sandbox.commands.run("echo hello", wait=True, wait_timeout_seconds=25)
print(execution.stdout)
sandbox.delete()
```

`idc_name` is optional for sandbox and template creation: when omitted, the service falls back to the organization's configured default IDC.

## Sandboxes

### `client.sandboxes.create()`

```python theme={null}
sandbox = client.sandboxes.create(
    idc_name="gmi-sandbox-us",
    template_id="template-id",
    timeout=300,
    env_vars={"APP_ENV": "production"},
    metadata={"owner": "platform"},
    idempotency_key="sandbox-create-1",
)
```

Arguments:

| Argument          | Description                                                                      |
| ----------------- | -------------------------------------------------------------------------------- |
| `idc_name`        | Target IDC. Optional; falls back to the organization's default IDC when omitted. |
| `template_id`     | Template source. Required.                                                       |
| `timeout`         | Sandbox lifetime in seconds.                                                     |
| `env_vars`        | Runtime environment variables.                                                   |
| `metadata`        | String metadata attached to the sandbox.                                         |
| `idempotency_key` | Optional create idempotency key.                                                 |

Returns a `Sandbox`.

### `client.sandboxes.list()`

```python theme={null}
page = client.sandboxes.list(
    page=1,
    page_size=20,
    idc_name="gmi-sandbox-us",
    state=["running"],
    metadata={"owner": "platform"},
)
```

`state` accepts a string or a sequence of strings. Metadata is encoded as `metadata[key]` query parameters.

### `client.sandboxes.get()`

```python theme={null}
sandbox = client.sandboxes.get("sandbox-id")
```

### `client.sandboxes.connect()`

```python theme={null}
sandbox = client.sandboxes.connect("sandbox-id", timeout=300)
```

The returned sandbox contains fresh data-plane connection fields.

## `Sandbox`

Properties:

| Property               | Description                                               |
| ---------------------- | --------------------------------------------------------- |
| `sandbox_id`           | Sandbox identifier (control-plane UUID)                   |
| `id`                   | Alias for `sandbox_id`                                    |
| `sandbox_key`          | Data-plane addressing key, used to build `data_plane_url` |
| `domain`               | Data-plane domain                                         |
| `sandbox_access_token` | Data-plane access token                                   |
| `state`                | Lifecycle state                                           |
| `data_plane_url`       | Computed data-plane URL                                   |
| `files`                | `SandboxFiles` helper                                     |
| `commands`             | `SandboxCommands` helper                                  |
| `executions`           | Alias for `commands`                                      |
| `data`                 | Raw response data dictionary                              |

Lifecycle states include `provisioning`, `running`, `checkpointing`, `updating`, and `failed`.

Methods:

```python theme={null}
sandbox.refresh()
sandbox.update_metadata({"team": "platform"})
sandbox.set_timeout(300)
sandbox.connect(timeout=300)
sandbox.delete()
```

## Files

All file methods use the sandbox data plane and require `connect()` first.

```python theme={null}
sandbox.files.read("/tmp/input.txt")
sandbox.files.write("/tmp/output.txt", "hello")
sandbox.files.write("/tmp/output.bin", b"\x00\x01")
sandbox.files.upload("./local.txt", "/tmp/local.txt")
sandbox.files.download("/tmp/local.txt")
sandbox.files.download(
    "/tmp/local.txt",
    destination="./downloaded.txt",
    byte_range="bytes=10-",
)
```

Methods:

| Method                                                             | Description                                |
| ------------------------------------------------------------------ | ------------------------------------------ |
| `read(path, username=None)`                                        | Read file bytes                            |
| `write(path, content, username=None, filename=None)`               | Write text or bytes                        |
| `upload(source, path, username=None)`                              | Upload a local path or bytes               |
| `download(path, destination=None, username=None, byte_range=None)` | Download bytes, optionally to a local path |

`download()` always returns `bytes`. `destination` is an additional local write.

## Command Execution

```python theme={null}
execution = sandbox.commands.run(
    "python --version",
    envs={"PYTHONUNBUFFERED": "1"},
    cwd="/tmp",
    wait=True,
    wait_timeout_seconds=25,
    request_id="execution-request-1",
)
```

Arguments:

| Argument               | Description                                                |
| ---------------------- | ---------------------------------------------------------- |
| `command`              | Shell command                                              |
| `envs`                 | Environment variables for the process                      |
| `cwd`                  | Working directory                                          |
| `wait`                 | Wait for a result within the wait window                   |
| `wait_timeout_seconds` | Server wait window; the API currently accepts 1-25 seconds |
| `request_id`           | Optional request correlation ID                            |

`Execution` properties:

```python theme={null}
execution.execution_id
execution.status
execution.exit_code
execution.stdout
execution.stderr
execution.data
```

Execution statuses include `pending`, `running`, `canceling`, `succeeded`, `failed`, and `canceled`.

Methods:

```python theme={null}
execution.refresh(request_id="refresh-1")
execution.cancel(request_id="cancel-1")
```

Cancel only non-terminal executions. The service may reject cancellation after an execution has completed.

## Templates

### Create

```python theme={null}
template = client.templates.create(
    name="demo-template",
    idc_name="gmi-sandbox-us",
    resources={"type": "preset", "product": "gmi.sandbox.small"},
    build={
        "source": {"type": "image", "image": "ubuntu:22.04"},
        "commands": ["apt-get update"],
        "envs": {"BUILD_ENV": "production"},
        "start_cmd": "sleep infinity",
    },
    description="Example template",
    labels={"team": "platform"},
    idempotency_key="template-create-1",
)
```

`resources` supports preset or custom values.

Preset:

```python theme={null}
{"type": "preset", "product": "gmi.sandbox.small"}
```

Custom:

```python theme={null}
{
    "type": "custom",
    "cpu_count": 2,
    "memory_mb": 4096,
    "disk_size_mb": 20480,
    "architecture": "x86_64",
}
```

Build sources include image and template sources:

```python theme={null}
{"type": "image", "image": "ubuntu:22.04"}
{"type": "template", "template_id": "parent-template-id"}
```

`idempotency_key` is required for template creation.

Returns a `Template`. The returned object can be used with template instance methods such as `update()`, `delete()`, `builds()`, `build()`, and `build_logs()`.

### List and Get

```python theme={null}
page = client.templates.list(idc_name="gmi-sandbox-us")
template = client.templates.get("template-id", idc_name="gmi-sandbox-us")
```

### Update and Delete

```python theme={null}
template.update(name="renamed-template", description="Updated description")
template.delete()
```

The template's `idc_name` is reused automatically when present in the template response.

### Builds and Logs

```python theme={null}
builds = template.builds(page=1, page_size=20)
build = template.build("build-id")
logs = template.build_logs("build-id", offset=0, limit=100)
```

## Product Specifications

```python theme={null}
specifications = client.product_specifications.list()
specifications = client.product_specifications.list(idc_name="gmi-sandbox-us")
```

## Pagination

List methods return a `Page` object:

```python theme={null}
page = client.sandboxes.list(page=1, page_size=20)

print(page.items)
print(page.total)
print(page.page)
print(page.page_size)
print(page.request_id)
```

`Page` fields:

| Field        | Type          | Description              |
| ------------ | ------------- | ------------------------ |
| `items`      | `list`        | Returned resources       |
| `total`      | `int`         | Total matching resources |
| `page`       | `int`         | Current page             |
| `page_size`  | `int`         | Requested page size      |
| `request_id` | `str \| None` | Server request ID        |

## Errors

All SDK exceptions derive from `SandboxSDKError`.

| Exception               | HTTP status                          |
| ----------------------- | ------------------------------------ |
| `BadRequestError`       | 400                                  |
| `AuthenticationError`   | 401                                  |
| `PermissionDeniedError` | 403                                  |
| `NotFoundError`         | 404                                  |
| `ConflictError`         | 409                                  |
| `RateLimitError`        | 429                                  |
| `ServerError`           | 500+                                 |
| `TransportError`        | Request could not reach the endpoint |

`APIError` fields:

```python theme={null}
try:
    client.sandboxes.get("missing")
except NotFoundError as exc:
    print(exc.status_code)
    print(exc.message)
    print(exc.code)
    print(exc.request_id)
    print(exc.details)
```

Error handling example:

```python theme={null}
from sandbox_sdk import ConflictError, NotFoundError, SandboxSDKError

try:
    sandbox = client.sandboxes.get("sandbox-id")
    sandbox.connect()
except NotFoundError:
    print("sandbox no longer exists")
except ConflictError:
    print("sandbox is in a transitional state; retry later")
except SandboxSDKError as exc:
    print(f"sandbox request failed: {exc}")
```

## OpenAPI Coverage

The SDK maps the Sandbox-related OpenAPI operations as follows:

| OpenAPI operation        | SDK                                    |
| ------------------------ | -------------------------------------- |
| `createSandbox`          | `client.sandboxes.create()`            |
| `listSandboxes`          | `client.sandboxes.list()`              |
| `getSandbox`             | `client.sandboxes.get()`               |
| `updateSandbox`          | `sandbox.update_metadata()`            |
| `deleteSandbox`          | `sandbox.delete()`                     |
| `connectSandbox`         | `sandbox.connect()`                    |
| `setSandboxTimeout`      | `sandbox.set_timeout()`                |
| `createSandboxExecution` | `sandbox.commands.run()`               |
| `getSandboxExecution`    | `execution.refresh()`                  |
| `cancelSandboxExecution` | `execution.cancel()`                   |
| `downloadSandboxFile`    | `sandbox.files.read()` / `download()`  |
| `uploadSandboxFile`      | `sandbox.files.write()` / `upload()`   |
| `listProductCatalog`     | `client.product_specifications.list()` |
| `createTemplate`         | `client.templates.create()`            |
| `listTemplates`          | `client.templates.list()`              |
| `getTemplate`            | `client.templates.get()`               |
| `updateTemplate`         | `template.update()`                    |
| `deleteTemplate`         | `template.delete()`                    |
| `listTemplateBuilds`     | `template.builds()`                    |
| `getTemplateBuild`       | `template.build()`                     |
| `getTemplateBuildLogs`   | `template.build_logs()`                |
