> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.nvidia.com/nemo/gym/main/nemo-gym/nemo_gym/sandbox/providers/openshell/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( delete_rpc_timeout_s: float = 120, delete_concurrency: int = 32, 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` --- **`delete_concurrency`** `int = 32` --- **`delete_rpc_timeout_s`** `float = 120` --- **`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, attribution: nemo_gym.sandbox.attribution.AttributionConfig | collections.abc.Mapping[str, typing.Any] | None = None ) ``` Sandbox provider backed by an OpenShell gateway's gRPC control plane. **`_attribution`** `= _coerce_config(attribution, AttributionConfig)` --- **`_connection`** --- **`_create_config`** `= _coerce_config(create, OpenShellCreateConfig)` --- **`_delete_shared`** --- **`_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._call_create( name: str, workspace: str, kwargs: typing.Any = {} ) -> typing.Any ``` async Run CreateSandbox on a worker. Cancelling the await does not stop a call already running, so a create that commits after the cancel is deleted when it returns. ```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._reap_orphans() -> None ``` async Delete this process's orphaned sandboxes: ones it no longer tracks, for example a create cancelled after the gateway committed it. Selected by the process label, which needs attribution to be enabled. ```python nemo_gym.sandbox.providers.openshell.OpenShellProvider._submit_delete( inst: nemo_gym.sandbox.providers.openshell.provider._OpenShellSandbox ) -> None ``` ```python nemo_gym.sandbox.providers.openshell.OpenShellProvider._timed_exec( args: typing.Any = (), kwargs: typing.Any = {} ) -> tuple[typing.Any, float] ``` Run the SDK exec and time it inside the worker thread, so executor queueing is not counted. ```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_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). Does not wait for deletes: they run on their own workers. When no sandbox of this process is still live or being created, it first deletes this process's orphaned sandboxes (see `_reap_orphans`). ```python nemo_gym.sandbox.providers.openshell.OpenShellProvider.close( handle: nemo_gym.sandbox.providers.base.SandboxHandle ) -> None ``` async Hand the sandbox's delete to a worker thread and return without waiting for the gateway. The worker deletes, waits until the sandbox is gone when `operations.close_wait_deleted` is set, and retries transient failures. It is already queued when this returns and runs to completion at interpreter exit even if the event loop is gone. Every outcome is logged with the sandbox name; a delete that fails for good is logged as possibly leaked and then forgotten. ```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 ` -c ` 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 ## Docs - [nemo_gym.sandbox.providers.openshell.provider](https://docs.nvidia.com/nemo/gym/main/nemo-gym/nemo_gym/sandbox/providers/openshell/provider.md)