> 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.openshell

OpenShell sandbox provider package.

## Submodules

* **[`nemo_gym.sandbox.providers.openshell.provider`](/nemo/gym/nemo-gym/nemo_gym/sandbox/providers/openshell/provider)**

## Package Contents

### Classes

| Name                                                                                                                  | Description                                                                                     |
| --------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
| [`OpenShellConnectionConfig`](#nemo_gym-sandbox-providers-openshell-provider-OpenShellConnectionConfig)               | Gateway connection settings. Defaults target a local plaintext gateway (deploy/docker compose). |
| [`OpenShellCreateConfig`](#nemo_gym-sandbox-providers-openshell-provider-OpenShellCreateConfig)                       | -                                                                                               |
| [`OpenShellCreateError`](#nemo_gym-sandbox-providers-openshell-provider-OpenShellCreateError)                         | Raised when the OpenShell gateway cannot create a sandbox.                                      |
| [`OpenShellCreateVerificationError`](#nemo_gym-sandbox-providers-openshell-provider-OpenShellCreateVerificationError) | Raised when a new sandbox fails its readiness probe.                                            |
| [`OpenShellExecConfig`](#nemo_gym-sandbox-providers-openshell-provider-OpenShellExecConfig)                           | -                                                                                               |
| [`OpenShellOperationsConfig`](#nemo_gym-sandbox-providers-openshell-provider-OpenShellOperationsConfig)               | -                                                                                               |
| [`OpenShellProbeConfig`](#nemo_gym-sandbox-providers-openshell-provider-OpenShellProbeConfig)                         | -                                                                                               |
| [`OpenShellProvider`](#nemo_gym-sandbox-providers-openshell-provider-OpenShellProvider)                               | Sandbox provider backed by an OpenShell gateway's gRPC control plane.                           |
| [`OpenShellProviderOptions`](#nemo_gym-sandbox-providers-openshell-provider-OpenShellProviderOptions)                 | Validated per-sandbox options carried in `SandboxSpec.provider_options`.                        |

### API

```python
class nemo_gym.sandbox.providers.openshell.OpenShellConnectionConfig(
    endpoint: str = 'localhost:8080',
    workspace: str = 'default',
    bearer_token: str | None = None,
    tls_ca_path: str | None = None,
    tls_cert_path: str | None = None,
    tls_key_path: str | None = None,
    request_timeout_s: float = 30.0
)
```

Dataclass

Gateway connection settings. Defaults target a local plaintext gateway (deploy/docker compose).

**`bearer_token`** `str | None = None`

---

**`endpoint`** `str = 'localhost:8080'`

---

**`request_timeout_s`** `float = 30.0`

---

**`tls_ca_path`** `str | None = None`

---

**`tls_cert_path`** `str | None = None`

---

**`tls_key_path`** `str | None = None`

---

**`workspace`** `str = 'default'`

---

```python
nemo_gym.sandbox.providers.openshell.OpenShellConnectionConfig.__post_init__() -> None
```

```python
class nemo_gym.sandbox.providers.openshell.OpenShellCreateConfig(
    ready_timeout_s: float = 300,
    poll_interval_s: float = 1.0,
    retries: int = 2,
    retry_delay_s: float = 1.0,
    retry_max_delay_s: float = 30.0
)
```

Dataclass

**`poll_interval_s`** `float = 1.0`

---

**`ready_timeout_s`** `float = 300`

---

**`retries`** `int = 2`

---

**`retry_delay_s`** `float = 1.0`

---

**`retry_max_delay_s`** `float = 30.0`

---

```python
nemo_gym.sandbox.providers.openshell.OpenShellCreateConfig.__post_init__() -> None
```

```python
class nemo_gym.sandbox.providers.openshell.OpenShellCreateError()
```

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

Raised when the OpenShell gateway cannot create a sandbox.

```python
class nemo_gym.sandbox.providers.openshell.OpenShellCreateVerificationError()
```

**Bases:** [SandboxCreateVerificationError](/nemo/gym/nemo-gym/nemo_gym/sandbox/providers/base#nemo_gym-sandbox-providers-base-SandboxCreateVerificationError)

Raised when a new sandbox fails its readiness probe.

```python
class nemo_gym.sandbox.providers.openshell.OpenShellExecConfig(
    default_timeout_s: float | None = 180,
    concurrency: int = 32,
    exec_shell: str = '/bin/sh',
    upload_chunk_bytes: int = DEFAULT_UPLOAD_CHUNK_BYTES
)
```

Dataclass

**`concurrency`** `int = 32`

---

**`default_timeout_s`** `float | None = 180`

---

**`exec_shell`** `str = '/bin/sh'`

---

**`upload_chunk_bytes`** `int = DEFAULT_UPLOAD_CHUNK_BYTES`

---

```python
nemo_gym.sandbox.providers.openshell.OpenShellExecConfig.__post_init__() -> None
```

```python
class nemo_gym.sandbox.providers.openshell.OpenShellOperationsConfig(
    close_wait_deleted: bool = True,
    close_timeout_s: float = 60,
    poll_interval_s: float = 1.0
)
```

Dataclass

**`close_timeout_s`** `float = 60`

---

**`close_wait_deleted`** `bool = True`

---

**`poll_interval_s`** `float = 1.0`

---

```python
nemo_gym.sandbox.providers.openshell.OpenShellOperationsConfig.__post_init__() -> None
```

```python
class nemo_gym.sandbox.providers.openshell.OpenShellProbeConfig(
    command: str | None = READY_PROBE_COMMAND,
    expected_stdout: str | None = READY_PROBE_EXPECTED,
    timeout_s: int = 30,
    deadline_s: float | None = 60,
    stable_count: int = 1,
    stable_delay_s: float = 1.0
)
```

Dataclass

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

---

**`deadline_s`** `float | None = 60`

---

**`expected_stdout`** `str | None = READY_PROBE_EXPECTED`

---

**`stable_count`** `int = 1`

---

**`stable_delay_s`** `float = 1.0`

---

**`timeout_s`** `int = 30`

---

```python
nemo_gym.sandbox.providers.openshell.OpenShellProbeConfig.__post_init__() -> None
```

```python
class nemo_gym.sandbox.providers.openshell.OpenShellProvider(
    connection: nemo_gym.sandbox.providers.openshell.provider.OpenShellConnectionConfig | collections.abc.Mapping[str, typing.Any] | None = None,
    create: nemo_gym.sandbox.providers.openshell.provider.OpenShellCreateConfig | collections.abc.Mapping[str, typing.Any] | None = None,
    exec: nemo_gym.sandbox.providers.openshell.provider.OpenShellExecConfig | collections.abc.Mapping[str, typing.Any] | None = None,
    probe: nemo_gym.sandbox.providers.openshell.provider.OpenShellProbeConfig | collections.abc.Mapping[str, typing.Any] | None = None,
    operations: nemo_gym.sandbox.providers.openshell.provider.OpenShellOperationsConfig | collections.abc.Mapping[str, typing.Any] | None = None
)
```

Sandbox provider backed by an OpenShell gateway's gRPC control plane.

**`_connection`**

---

**`_create_config`** `= _coerce_config(create, OpenShellCreateConfig)`

---

**`_exec_config`** `= _coerce_config(exec, OpenShellExecConfig)`

---

**`_operations`**

---

**`_probe`** `= _coerce_config(probe, OpenShellProbeConfig)`

---

**`_shared`**

---

**`name`** `= 'openshell'`

---

```python
nemo_gym.sandbox.providers.openshell.OpenShellProvider._build_policy(
    policy: str | collections.abc.Mapping[str, typing.Any]
) -> typing.Any
```

```python
nemo_gym.sandbox.providers.openshell.OpenShellProvider._build_sandbox_spec(
    spec: nemo_gym.sandbox.providers.base.SandboxSpec,
    image: str | None,
    options: nemo_gym.sandbox.providers.openshell.provider.OpenShellProviderOptions
) -> typing.Any
```

```python
nemo_gym.sandbox.providers.openshell.OpenShellProvider._call(
    func: typing.Any,
    args: typing.Any = (),
    kwargs: typing.Any = {}
) -> typing.Any
```

async

```python
nemo_gym.sandbox.providers.openshell.OpenShellProvider._cleanup_failed_create_handle(
    handle: nemo_gym.sandbox.providers.base.SandboxHandle
) -> None
```

async

```python
nemo_gym.sandbox.providers.openshell.OpenShellProvider._create_sandbox_with_retries(
    pb_spec: typing.Any,
    name: str,
    labels: dict[str, str]
) -> typing.Any
```

async

Issue CreateSandbox, retrying transient gRPC failures with the same name.

Retrying with the same name is safe: if an earlier attempt actually committed, the
retry fails ALREADY\_EXISTS and the sandbox is recovered via GetSandbox.

```python
nemo_gym.sandbox.providers.openshell.OpenShellProvider._verify_created_handle(
    handle: nemo_gym.sandbox.providers.base.SandboxHandle
) -> None
```

async

Poll the readiness probe until it passes `stable_count` times or the deadline elapses.

```python
nemo_gym.sandbox.providers.openshell.OpenShellProvider._wait_deleted(
    inst: nemo_gym.sandbox.providers.openshell.provider._OpenShellSandbox
) -> None
```

async

Poll GetSandbox until NOT\_FOUND (transient RPC failures keep polling until the deadline).

```python
nemo_gym.sandbox.providers.openshell.OpenShellProvider._wait_ready(
    handle: nemo_gym.sandbox.providers.base.SandboxHandle,
    timeout_s: int | float
) -> None
```

async

Poll GetSandbox until READY, raising on the ERROR/DELETING phases or the deadline.

```python
nemo_gym.sandbox.providers.openshell.OpenShellProvider.aclose() -> None
```

async

Release the shared client/pool (closed for real when the last provider releases it).

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

async

Delete the sandbox (already-gone counts as success), then wait until it is fully gone.

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

async

Create a sandbox through the gateway, wait for the READY phase, then probe exec readiness.

`spec.image` is optional (the gateway's configured default image is used when unset).
`spec.ttl_s` is not enforced (OpenShell sandboxes live until deleted) and only logs a
warning. `spec.entrypoint` is unsupported: the OpenShell supervisor owns the sandbox
entrypoint. `spec.provider_options` accepts `providers` (OpenShell credential-provider
names), `policy` (a SandboxPolicy mapping or YAML path), and `template_resources` /
`driver_config` (free-form driver passthrough Structs). A half-created sandbox is
deleted on any failure.

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

async

Download one sandbox file via a base64 round-trip (binary-safe over the text exec stream).

The whole file is buffered in memory (inflated 4/3 by base64), so this is intended for
small-to-medium artifacts rather than large archives.

```python
nemo_gym.sandbox.providers.openshell.OpenShellProvider.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,
    stdin: bytes | None = None
) -> nemo_gym.sandbox.providers.base.SandboxExecResult
```

async

Run `&lt;shell&gt; -c &lt;command&gt;` through the gateway's streaming exec; never raises for command failure.

The timeout is enforced by the gateway (`timeout_seconds`); the SDK extends its gRPC
deadline past it. `user` is ignored with a warning: the OpenShell exec API has no user
field, so commands run as the sandbox's default user.

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

async

Sandbox phase via GetSandbox (missing -> STOPPED; RPC failure -> UNKNOWN).

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

async

Upload one local file by streaming its bytes through exec stdin (creates the parent dir).

Bytes are sent in `exec.upload_chunk_bytes` chunks because each chunk travels as a
single gRPC message that must stay under the gateway's max decode size.

```python
class nemo_gym.sandbox.providers.openshell.OpenShellProviderOptions(
    providers: list[str] = list(),
    policy: typing.Any | None = None,
    template_resources: dict[str, typing.Any] = dict(),
    driver_config: dict[str, typing.Any] = dict()
)
```

Dataclass

Validated per-sandbox options carried in `SandboxSpec.provider_options`.

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

---

**`policy`** `Any | None = None`

---

**`providers`** `list[str] = field(default_factory=list)`

---

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

---

```python
nemo_gym.sandbox.providers.openshell.OpenShellProviderOptions.from_mapping(
    options: collections.abc.Mapping[str, typing.Any]
) -> nemo_gym.sandbox.providers.openshell.provider.OpenShellProviderOptions
```

classmethod