> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.nvidia.com/nemo/gym/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.nvidia.com/nemo/gym/_mcp/server.

# nemo_gym.sandbox.providers.base

Provider-facing sandbox protocol.

## Module Contents

### Classes

| Name                                                                                                        | Description                                                                 |
| ----------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| [`ConnectableProvider`](#nemo_gym-sandbox-providers-base-ConnectableProvider)                               | Optional capability: rebuild a handle in another process from a descriptor. |
| [`SandboxCreateError`](#nemo_gym-sandbox-providers-base-SandboxCreateError)                                 | Raised when a provider cannot create a sandbox.                             |
| [`SandboxCreateVerificationError`](#nemo_gym-sandbox-providers-base-SandboxCreateVerificationError)         | Raised when a newly-created sandbox fails provider readiness checks.        |
| [`SandboxEndpoint`](#nemo_gym-sandbox-providers-base-SandboxEndpoint)                                       | Provider-neutral route to a long-lived service inside a sandbox.            |
| [`SandboxExecResult`](#nemo_gym-sandbox-providers-base-SandboxExecResult)                                   | Provider-neutral process execution result.                                  |
| [`SandboxHandle`](#nemo_gym-sandbox-providers-base-SandboxHandle)                                           | Provider-neutral handle to a created sandbox.                               |
| [`SandboxProvider`](#nemo_gym-sandbox-providers-base-SandboxProvider)                                       | Runtime/infra provider contract used by the public sandbox API.             |
| [`SandboxPtyError`](#nemo_gym-sandbox-providers-base-SandboxPtyError)                                       | Raised when a PTY session fails outside normal process exit.                |
| [`SandboxPtySession`](#nemo_gym-sandbox-providers-base-SandboxPtySession)                                   | One live interactive terminal. Async context manager; exit closes it.       |
| [`SandboxPtySpec`](#nemo_gym-sandbox-providers-base-SandboxPtySpec)                                         | Interactive PTY session request.                                            |
| [`SandboxResources`](#nemo_gym-sandbox-providers-base-SandboxResources)                                     | Provider-neutral resource request.                                          |
| [`SandboxSpec`](#nemo_gym-sandbox-providers-base-SandboxSpec)                                               | Sandbox creation request.                                                   |
| [`SandboxStatus`](#nemo_gym-sandbox-providers-base-SandboxStatus)                                           | Provider-neutral sandbox lifecycle status.                                  |
| [`SupportsSandboxBackgroundServices`](#nemo_gym-sandbox-providers-base-SupportsSandboxBackgroundServices)   | Optional execution override for services needed by a later command.         |
| [`SupportsSandboxEndpoint`](#nemo_gym-sandbox-providers-base-SupportsSandboxEndpoint)                       | Optional provider capability for resolving declared service ports.          |
| [`SupportsSandboxNetwork`](#nemo_gym-sandbox-providers-base-SupportsSandboxNetwork)                         | Optional direct networking between sandboxes, preserving service ports.     |
| [`SupportsSandboxPauseResume`](#nemo_gym-sandbox-providers-base-SupportsSandboxPauseResume)                 | Optional provider capability to pause and resume a sandbox.                 |
| [`SupportsSandboxPortForwarding`](#nemo_gym-sandbox-providers-base-SupportsSandboxPortForwarding)           | Optional loopback TCP forwarding, running until cancellation.               |
| [`SupportsSandboxPty`](#nemo_gym-sandbox-providers-base-SupportsSandboxPty)                                 | Optional provider capability: interactive PTY sessions.                     |
| [`SupportsSandboxPtyAttach`](#nemo_gym-sandbox-providers-base-SupportsSandboxPtyAttach)                     | Optional provider capability: re-attach to a PTY session by id.             |
| [`SupportsSandboxRuntimeRequirements`](#nemo_gym-sandbox-providers-base-SupportsSandboxRuntimeRequirements) | Optional validation and setup of task-declared runtime requirements.        |
| [`SupportsSandboxSharedStorage`](#nemo_gym-sandbox-providers-base-SupportsSandboxSharedStorage)             | Optional shared filesystem provisioned by the operator's provider config.   |

### Data

[`ExecResult`](#nemo_gym-sandbox-providers-base-ExecResult)

### API

```python
class nemo_gym.sandbox.ConnectableProvider()
```

Protocol

Optional capability: rebuild a handle in another process from a descriptor.

Providers whose sandboxes are reachable by id (external control plane, e.g.
OpenSandbox and Fargate, and the sandbox server's remote provider) implement
this. A provider that does not implement it can only be shared by fronting it
with a sandbox server. Membership is checked with `isinstance` because the
protocol is `runtime_checkable`.

```python
nemo_gym.sandbox.ConnectableProvider.connect(
    descriptor: collections.abc.Mapping[str, typing.Any]
) -> nemo_gym.sandbox.providers.base.SandboxHandle
```

async

Rebuild a live handle in this process from a descriptor.

```python
nemo_gym.sandbox.ConnectableProvider.serialize_handle(
    handle: nemo_gym.sandbox.providers.base.SandboxHandle,
    scope: str | None = None
) -> dict[str, typing.Any]
```

async

Return a JSON-serializable descriptor that `connect` can rebuild a
handle from. `scope` is honored by providers that mint leases (the
remote provider) and ignored by the rest.

```python
class nemo_gym.sandbox.SandboxCreateError()
```

**Bases:** `RuntimeError`

Raised when a provider cannot create a sandbox.

```python
class nemo_gym.sandbox.SandboxCreateVerificationError()
```

**Bases:** [SandboxCreateError](#nemo_gym-sandbox-providers-base-SandboxCreateError)

Raised when a newly-created sandbox fails provider readiness checks.

```python
class nemo_gym.sandbox.SandboxEndpoint(
    endpoint: str,
    headers: dict[str, str] = dict()
)
```

Dataclass

Provider-neutral route to a long-lived service inside a sandbox.

`endpoint` is an absolute URL. `headers` carries provider-required
authentication or routing headers without exposing the provider's opaque
handle to callers.

**`endpoint`** `str`

---

**`headers`** `dict[str, str] = field(default_factory=dict)`

---

```python
nemo_gym.sandbox.SandboxEndpoint.__post_init__() -> None
```

```python
class nemo_gym.sandbox.SandboxExecResult(
    stdout: str | None,
    stderr: str | None,
    return_code: int,
    error_type: str | None = None
)
```

Dataclass

Provider-neutral process execution result.

`return_code` is the process exit code when the sandbox actually ran the
command. Providers may use a non-process sentinel with `error_type` set
when the sandbox runtime reports an execution failure without a process
exit code.

**`error_type`** `str | None = None`

---

**`return_code`** `int`

---

**`stderr`** `str | None`

---

**`stdout`** `str | None`

---

```python
class nemo_gym.sandbox.SandboxHandle(
    sandbox_id: str,
    provider_name: str,
    raw: typing.Any
)
```

Dataclass

Provider-neutral handle to a created sandbox.

`raw` is provider-owned opaque state. Public code should pass it back to
the provider through this handle rather than inspecting or mutating it
directly.

**`provider_name`** `str`

---

**`sandbox_id`** `str`

---

```python
class nemo_gym.sandbox.SandboxProvider()
```

Protocol

Runtime/infra provider contract used by the public sandbox API.

**`name`** `str`

---

```python
nemo_gym.sandbox.SandboxProvider.aclose() -> None
```

async

Close provider-scoped resources such as SDK clients.

```python
nemo_gym.sandbox.SandboxProvider.close(
    handle: nemo_gym.sandbox.providers.base.SandboxHandle
) -> None
```

async

End the sandbox lifecycle and close provider resources for it.

```python
nemo_gym.sandbox.SandboxProvider.create(
    spec: nemo_gym.sandbox.providers.base.SandboxSpec
) -> nemo_gym.sandbox.providers.base.SandboxHandle
```

async

Create a ready sandbox and return a provider-neutral handle.

Providers must return only after the sandbox is healthy enough to run
commands and transfer files. If the sandbox cannot become ready before
the configured timeout, providers should raise `SandboxCreateError`
or a provider-specific subclass.

```python
nemo_gym.sandbox.SandboxProvider.download_file(
    handle: nemo_gym.sandbox.providers.base.SandboxHandle,
    source_path: str,
    target_path: pathlib.Path
) -> None
```

async

Download one sandbox file to the local filesystem.

```python
nemo_gym.sandbox.SandboxProvider.exec(
    handle: nemo_gym.sandbox.providers.base.SandboxHandle,
    command: str,
    cwd: str | None = None,
    env: dict[str, str] | None = None,
    timeout_s: int | float | None = None,
    user: str | int | None = None
) -> nemo_gym.sandbox.providers.base.SandboxExecResult
```

async

Run a command inside a sandbox.

```python
nemo_gym.sandbox.SandboxProvider.status(
    handle: nemo_gym.sandbox.providers.base.SandboxHandle
) -> nemo_gym.sandbox.providers.base.SandboxStatus
```

async

Return the current sandbox lifecycle status.

```python
nemo_gym.sandbox.SandboxProvider.upload_file(
    handle: nemo_gym.sandbox.providers.base.SandboxHandle,
    source_path: pathlib.Path,
    target_path: str
) -> None
```

async

Upload one local file into a sandbox.

```python
class nemo_gym.sandbox.SandboxPtyError()
```

**Bases:** `RuntimeError`

Raised when a PTY session fails outside normal process exit.

```python
class nemo_gym.sandbox.SandboxPtySession()
```

Protocol

One live interactive terminal. Async context manager; exit closes it.

**`closed`** `bool`

Whether `close()` has run; a closed session cannot run commands.

---

**`mode`** `str | None`

`"pty"` or `"pipe"` once connected, `None` before that. Only pipe
mode splits stderr; in PTY mode all output arrives through `read()`.

---

**`session_id`** `str`

---

```python
nemo_gym.sandbox.SandboxPtySession.__aenter__() -> nemo_gym.sandbox.providers.base.SandboxPtySession
```

async

```python
nemo_gym.sandbox.SandboxPtySession.__aexit__(
    exc_type: typing.Any,
    exc_val: typing.Any,
    exc_tb: typing.Any
) -> None
```

async

```python
nemo_gym.sandbox.SandboxPtySession.__aiter__() -> collections.abc.AsyncIterator[bytes]
```

Yield output chunks until EOF.

```python
nemo_gym.sandbox.SandboxPtySession.close() -> None
```

async

Idempotent: release local resources; a session this client created
is also ended, while an attached one is merely detached and lives on
for its owner.

```python
nemo_gym.sandbox.SandboxPtySession.read(
    timeout_s: float | None = None
) -> bytes
```

async

Return the next output chunk (all terminal output in PTY mode;
stdout only in pipe mode). `b""` means the process exited and the
stream is drained. Raises `TimeoutError` on timeout and
`SandboxPtyError` if the session died without exiting.

```python
nemo_gym.sandbox.SandboxPtySession.read_stderr(
    timeout_s: float | None = None
) -> bytes
```

async

Return the next stderr chunk. Only pipe mode (`pty=False`)
carries stderr separately; in PTY mode this stream is empty and
returns `b""` once the process exits. Same timeout/error semantics
as `read()`.

```python
nemo_gym.sandbox.SandboxPtySession.resize(
    rows: int,
    cols: int
) -> None
```

async

Resize the terminal.

```python
nemo_gym.sandbox.SandboxPtySession.run_detached(
    command: str,
    poll_interval_s: float = 15.0
) -> tuple[bytes, int | None]
```

async

Run one command holding the transport only for brief completion
polls; returns `(merged output, exit code or None)`. The server
retains a bounded window of output between polls, and exceeding it
raises rather than returning truncated output.

```python
nemo_gym.sandbox.SandboxPtySession.send_signal(
    signal: str
) -> None
```

async

Deliver a named signal, e.g. `"SIGTERM"`, to the session's process
group. Interactive shells run foreground jobs in their own group, so
signals reliably reach the process only for command sessions; whether
`SIGINT` interrupts at all also depends on the sandbox runtime's
inherited signal dispositions.

```python
nemo_gym.sandbox.SandboxPtySession.wait_exit(
    timeout_s: float | None = None
) -> int
```

async

Block until the process exits and return its exit code.

```python
nemo_gym.sandbox.SandboxPtySession.write(
    data: bytes
) -> None
```

async

Send raw bytes to the terminal's stdin.

```python
class nemo_gym.sandbox.SandboxPtySpec(
    command: str | None = None,
    cwd: str | None = None,
    env: dict[str, str] | None = None,
    rows: int = 24,
    cols: int = 80,
    user: str | int | None = None,
    pty: bool = True
)
```

Dataclass

Interactive PTY session request.

`command` runs under the backend's interactive shell; `None` spawns the
shell itself. Backends without native env/user support may rewrite the
command (mirroring `exec()`'s user rewrite) and must raise `ValueError`
for values they cannot honor. `pty=False` selects pipe mode: no TTY,
stdout and stderr delivered as separate streams, `rows`/`cols` ignored.
Backends that cannot size a terminal at spawn apply `rows`/`cols` as
soon as it connects, so a `command` reading the size immediately may
observe the backend default.

**`cols`** `int = 80`

---

**`command`** `str | None = None`

---

**`cwd`** `str | None = None`

---

**`env`** `dict[str, str] | None = None`

---

**`pty`** `bool = True`

---

**`rows`** `int = 24`

---

**`user`** `str | int | None = None`

---

```python
class nemo_gym.sandbox.SandboxResources(
    cpu: float | None = None,
    memory_mib: int | None = None,
    disk_gib: int | None = None,
    gpu: int | None = None,
    gpu_type: str | None = None
)
```

Dataclass

Provider-neutral resource request.

**`cpu`** `float | None = None`

---

**`disk_gib`** `int | None = None`

---

**`gpu`** `int | None = None`

---

**`gpu_type`** `str | None = None`

---

**`memory_mib`** `int | None = None`

---

```python
nemo_gym.sandbox.SandboxResources.from_mapping(
    resources: collections.abc.Mapping[str, typing.Any] | None
) -> nemo_gym.sandbox.providers.base.SandboxResources
```

classmethod

```python
class nemo_gym.sandbox.SandboxSpec(
    image: str | None = None,
    ttl_s: int | float | None = None,
    ready_timeout_s: int | float | None = None,
    workdir: str | None = None,
    env: dict[str, str] = dict(),
    files: dict[str, str] = dict(),
    metadata: dict[str, str] = dict(),
    resources: nemo_gym.sandbox.providers.base.SandboxResources | collections.abc.Mapping[str, typing.Any] = SandboxResources(),
    entrypoint: list[str] | None = None,
    provider_options: dict[str, typing.Any] = dict(),
    ports: tuple[int, ...] | list[int] = tuple()
)
```

Dataclass

Sandbox creation request.

**`entrypoint`** `list[str] | None = None`

---

**`env`** `dict[str, str] = field(default_factory=dict)`

---

**`files`** `dict[str, str] = field(default_factory=dict)`

---

**`image`** `str | None = None`

---

**`metadata`** `dict[str, str] = field(default_factory=dict)`

---

**`ports`** `tuple[int, ...] | list[int] = field(default_factory=tuple)`

---

**`provider_options`** `dict[str, Any] = field(default_factory=dict)`

---

**`ready_timeout_s`** `int | float | None = None`

---

**`resources`** `SandboxResources | Mapping[str, Any] = field(default_factory=SandboxResources)`

---

**`ttl_s`** `int | float | None = None`

---

**`workdir`** `str | None = None`

---

```python
nemo_gym.sandbox.SandboxSpec.__post_init__() -> None
```

```python
class nemo_gym.sandbox.SandboxStatus
```

**Bases:** `enum.Enum`

Provider-neutral sandbox lifecycle status.

**`ERROR`** `= 'error'`

---

**`PAUSED`** `= 'paused'`

---

**`RUNNING`** `= 'running'`

---

**`STARTING`** `= 'starting'`

---

**`STOPPED`** `= 'stopped'`

---

**`UNKNOWN`** `= 'unknown'`

---

```python
class nemo_gym.sandbox.providers.SupportsSandboxBackgroundServices()
```

Protocol

Optional execution override for services needed by a later command.

```python
nemo_gym.sandbox.providers.SupportsSandboxBackgroundServices.exec_with_background_services(
    handle: nemo_gym.sandbox.providers.base.SandboxHandle,
    command: str,
    cwd: str | None = None,
    timeout_s: int | float | None = None
) -> nemo_gym.sandbox.providers.base.SandboxExecResult
```

async

```python
class nemo_gym.sandbox.SupportsSandboxEndpoint()
```

Protocol

Optional provider capability for resolving declared service ports.

```python
nemo_gym.sandbox.SupportsSandboxEndpoint.endpoint(
    handle: nemo_gym.sandbox.providers.base.SandboxHandle,
    port: int
) -> nemo_gym.sandbox.providers.base.SandboxEndpoint
```

async

Resolve a declared service port to a caller-reachable endpoint.

```python
class nemo_gym.sandbox.SupportsSandboxNetwork()
```

Protocol

Optional direct networking between sandboxes, preserving service ports.

```python
nemo_gym.sandbox.SupportsSandboxNetwork.network_address(
    handle: nemo_gym.sandbox.providers.base.SandboxHandle
) -> str
```

async

```python
nemo_gym.sandbox.SupportsSandboxNetwork.set_hosts(
    handle: nemo_gym.sandbox.providers.base.SandboxHandle,
    hosts: collections.abc.Mapping[str, str]
) -> None
```

async

```python
nemo_gym.sandbox.SupportsSandboxNetwork.validate_networking() -> None
```

```python
class nemo_gym.sandbox.SupportsSandboxPauseResume()
```

Protocol

Optional provider capability to pause and resume a sandbox.

What survives a pause beyond the filesystem is backend-specific.

```python
nemo_gym.sandbox.SupportsSandboxPauseResume.pause(
    handle: nemo_gym.sandbox.providers.base.SandboxHandle
) -> None
```

async

Pause a sandbox while preserving its state.

```python
nemo_gym.sandbox.SupportsSandboxPauseResume.resume(
    handle: nemo_gym.sandbox.providers.base.SandboxHandle
) -> None
```

async

Resume a paused sandbox and refresh its handle.

```python
class nemo_gym.sandbox.SupportsSandboxPortForwarding()
```

Protocol

Optional loopback TCP forwarding, running until cancellation.

```python
nemo_gym.sandbox.SupportsSandboxPortForwarding.forward_ports(
    handle: nemo_gym.sandbox.providers.base.SandboxHandle,
    target_address: str,
    ports: tuple[int, ...],
    ready_file: str
) -> None
```

async

```python
nemo_gym.sandbox.SupportsSandboxPortForwarding.validate_port_forwarding() -> None
```

```python
class nemo_gym.sandbox.SupportsSandboxPty()
```

Protocol

Optional provider capability: interactive PTY sessions.

```python
nemo_gym.sandbox.SupportsSandboxPty.create_pty(
    handle: nemo_gym.sandbox.providers.base.SandboxHandle,
    spec: nemo_gym.sandbox.providers.base.SandboxPtySpec
) -> nemo_gym.sandbox.providers.base.SandboxPtySession
```

async

Open an interactive terminal inside a sandbox.

```python
class nemo_gym.sandbox.SupportsSandboxPtyAttach()
```

Protocol

Optional provider capability: re-attach to a PTY session by id.

Separate from `SupportsSandboxPty` because it requires sessions that live
in the sandbox rather than in the client, so a provider may offer terminals
without offering re-attach.

```python
nemo_gym.sandbox.SupportsSandboxPtyAttach.attach_pty(
    handle: nemo_gym.sandbox.providers.base.SandboxHandle,
    session_id: str,
    takeover: bool = True,
    since: int | None = None
) -> nemo_gym.sandbox.providers.base.SandboxPtySession
```

async

Re-attach to an existing session by id.

`takeover` evicts the current holder, whose session then fails with
`SandboxPtyError`; without it, attaching to a held session fails.
`since` is a byte offset into the session's retained output to replay
before live output (`0` replays everything still retained).

```python
class nemo_gym.sandbox.SupportsSandboxRuntimeRequirements()
```

Protocol

Optional validation and setup of task-declared runtime requirements.

```python
nemo_gym.sandbox.SupportsSandboxRuntimeRequirements.configure_runtime(
    handle: nemo_gym.sandbox.providers.base.SandboxHandle,
    cap_add: tuple[str, ...],
    shm_size: int | None
) -> None
```

async

```python
nemo_gym.sandbox.SupportsSandboxRuntimeRequirements.validate_runtime_requirements(
    cap_add: tuple[str, ...],
    shm_size: int | None
) -> dict[str, str] | None
```

Validate support and return any required create-time metadata.

```python
class nemo_gym.sandbox.SupportsSandboxSharedStorage()
```

Protocol

Optional shared filesystem provisioned by the operator's provider config.

`shared_volume_options` returns provider options containing a `volumes`
list of opaque mount descriptors. Collections concatenate these lists.
`source` is relative to the configured shared root; `None` mounts that
root for initialization and cleanup. Metadata supplies placement settings.

```python
nemo_gym.sandbox.SupportsSandboxSharedStorage.shared_volume_metadata() -> dict[str, str]
```

```python
nemo_gym.sandbox.SupportsSandboxSharedStorage.shared_volume_options(
    source: str | None,
    target: str,
    read_only: bool = False
) -> dict[str, typing.Any]
```

```python
nemo_gym.sandbox.providers.base.ExecResult = SandboxExecResult
```