> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/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 Public sandbox API for NeMo Gym. ## Subpackages * **[`nemo_gym.sandbox.adapters`](/nemo/gym/nemo-gym/nemo_gym/sandbox/adapters)** * **[`nemo_gym.sandbox.providers`](/nemo/gym/nemo-gym/nemo_gym/sandbox/providers)** ## Submodules * **[`nemo_gym.sandbox.access`](/nemo/gym/nemo-gym/nemo_gym/sandbox/access)** * **[`nemo_gym.sandbox.agent_tools`](/nemo/gym/nemo-gym/nemo_gym/sandbox/agent_tools)** * **[`nemo_gym.sandbox.api`](/nemo/gym/nemo-gym/nemo_gym/sandbox/api)** * **[`nemo_gym.sandbox.attribution`](/nemo/gym/nemo-gym/nemo_gym/sandbox/attribution)** * **[`nemo_gym.sandbox.config`](/nemo/gym/nemo-gym/nemo_gym/sandbox/config)** * **[`nemo_gym.sandbox.shell`](/nemo/gym/nemo-gym/nemo_gym/sandbox/shell)** * **[`nemo_gym.sandbox.utils`](/nemo/gym/nemo-gym/nemo_gym/sandbox/utils)** ## Package Contents ### Classes | Name | Description | | ----------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | | [`AsyncSandbox`](#nemo_gym-sandbox-api-AsyncSandbox) | Async sandbox object backed by a runtime provider. | | [`AsyncSandboxCompose`](#nemo_gym-sandbox-adapters-docker_compose-AsyncSandboxCompose) | Start services from a Compose YAML file and own their sandbox lifecycle. | | [`ConnectableProvider`](#nemo_gym-sandbox-providers-base-ConnectableProvider) | Optional capability: rebuild a handle in another process from a descriptor. | | [`Sandbox`](#nemo_gym-sandbox-api-Sandbox) | Synchronous wrapper around `AsyncSandbox`. | | [`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. | | [`SandboxPty`](#nemo_gym-sandbox-api-SandboxPty) | PTY namespace of a sandbox: `await sandbox.pty.create(...)` for a live | | [`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. | | [`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. | ### Functions | Name | Description | | --------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | | [`create_provider`](#nemo_gym-sandbox-providers-registry-create_provider) | Instantiate a provider from a single-key provider config. | | [`get_provider_class`](#nemo_gym-sandbox-providers-registry-get_provider_class) | Return a provider class by name (explicit > built-in > entry point). | | [`list_providers`](#nemo_gym-sandbox-providers-registry-list_providers) | List available provider names from all sources. | | [`register_provider`](#nemo_gym-sandbox-providers-registry-register_provider) | Register a sandbox provider class. | | [`resolve_provider_config`](#nemo_gym-sandbox-config-resolve_provider_config) | Resolve a `sandbox_provider` field into a single-key provider config dict. | | [`resolve_provider_metadata`](#nemo_gym-sandbox-config-resolve_provider_metadata) | Return a sandbox block's `default_metadata`. | | [`rewrite_image`](#nemo_gym-sandbox-utils-rewrite_image) | Apply ordered image-prefix rewrites used by sandbox configs. | ### Data [`ExecResult`](#nemo_gym-sandbox-providers-base-ExecResult) ### API ```python class nemo_gym.sandbox.AsyncSandbox( provider: collections.abc.Mapping[str, typing.Any] | nemo_gym.sandbox.providers.SandboxProvider, spec: nemo_gym.sandbox.providers.SandboxSpec | None = None, owns_provider: bool = True ) ``` Async sandbox object backed by a runtime provider. With `owns_provider=False`, the caller closes the shared provider after all of its sandboxes have stopped. **`_handle`** `SandboxHandle | None = None` --- **`_provider`** --- **`pty`** `= SandboxPty(self)` --- ```python nemo_gym.sandbox.AsyncSandbox.__aenter__() -> nemo_gym.sandbox.api.AsyncSandbox ``` async ```python nemo_gym.sandbox.AsyncSandbox.__aexit__( exc_type: typing.Any, exc_val: typing.Any, exc_tb: typing.Any ) -> None ``` async ```python nemo_gym.sandbox.AsyncSandbox._exec_uninstrumented( command: str, cwd: str | None = None, env: dict[str, str] | None = None, timeout_s: int | float | None = 180, user: str | int | None = None, preserve_background_services: bool = False ) -> nemo_gym.sandbox.providers.SandboxExecResult ``` async ```python nemo_gym.sandbox.AsyncSandbox._require_handle() -> nemo_gym.sandbox.providers.SandboxHandle ``` ```python nemo_gym.sandbox.AsyncSandbox._telemetry_provider_name() -> str ``` Provider name for span attributes (`docker`, `daytona`, `opensandbox`, ...). ```python nemo_gym.sandbox.AsyncSandbox.connect( descriptor: collections.abc.Mapping[str, typing.Any] | typing.Any, provider: nemo_gym.sandbox.providers.SandboxProvider, owns_provider: bool = True ) -> nemo_gym.sandbox.api.AsyncSandbox ``` async classmethod Rebuild a sandbox in this process from a descriptor produced by `serialize`, using `provider` (which must support connect). ```python nemo_gym.sandbox.AsyncSandbox.disconnect() -> None ``` async Release this client without stopping a borrowed sandbox. Use this only for a sandbox rebuilt with `connect`. The component that created the sandbox remains responsible for stopping it. ```python nemo_gym.sandbox.AsyncSandbox.download( remote_path: str, local_path: pathlib.Path | str ) -> None ``` async ```python nemo_gym.sandbox.AsyncSandbox.endpoint( port: int ) -> nemo_gym.sandbox.providers.SandboxEndpoint ``` async Resolve a declared sandbox service port without exposing provider state. ```python nemo_gym.sandbox.AsyncSandbox.exec( command: str, cwd: str | None = None, env: dict[str, str] | None = None, timeout_s: int | float | None = 180, user: str | int | None = None, preserve_background_services: bool = False ) -> nemo_gym.sandbox.providers.SandboxExecResult ``` async Run a command, optionally preserving services needed by later commands. `preserve_background_services` selects a provider's service-preserving execution when available; other providers use ordinary exec. Services must redirect stdout and stderr. This mode does not accept per-command `env` or `user` overrides on providers with a service-preserving path. ```python nemo_gym.sandbox.AsyncSandbox.pause() -> None ``` async Pause this sandbox while preserving its state. Open PTY sessions are detached; whether processes survive and sessions can be re-attached after `resume()` depends on the provider backend. ```python nemo_gym.sandbox.AsyncSandbox.resume() -> None ``` async Resume this sandbox and wait until it is ready. On timeout the server-side state is unknown: reconnect and check `status()` before retrying. ```python nemo_gym.sandbox.AsyncSandbox.serialize( scope: str | None = None ) -> dict[str, typing.Any] ``` async Return a JSON descriptor another process can rebuild this box from. Requires a provider that supports the connect capability (the remote provider, or an external-control-plane provider such as OpenSandbox). For the remote provider, `scope` mints a co-lease (`scope="operate"`). ```python nemo_gym.sandbox.AsyncSandbox.start( spec: nemo_gym.sandbox.providers.SandboxSpec | None = None ) -> nemo_gym.sandbox.api.AsyncSandbox ``` async ```python nemo_gym.sandbox.AsyncSandbox.start_with_setup( spec: nemo_gym.sandbox.providers.SandboxSpec | None, setup: collections.abc.Callable[[AsyncSandbox], collections.abc.Awaitable[None]] ) -> nemo_gym.sandbox.api.AsyncSandbox ``` async Start the sandbox, then run `setup` against it. If `setup` raises, the sandbox is stopped before the exception propagates. ```python nemo_gym.sandbox.AsyncSandbox.status() -> nemo_gym.sandbox.providers.SandboxStatus ``` async ```python nemo_gym.sandbox.AsyncSandbox.stop() -> None ``` async ```python nemo_gym.sandbox.AsyncSandbox.upload( local_path: pathlib.Path | str, remote_path: str ) -> None ``` async ```python class nemo_gym.sandbox.AsyncSandboxCompose( provider, compose_file: str | pathlib.Path | None, service_specs: collections.abc.Mapping[str, nemo_gym.sandbox.providers.SandboxSpec] | None = None, timeout_s: float = 1200, poll_interval_s: float = 0.5, volume_init_image: str = 'alpine:3.22', volume_sources: collections.abc.Mapping[str, str] | None = None ) ``` Start services from a Compose YAML file and own their sandbox lifecycle. Deployment settings stay in the provider and optional `service_specs`. Compose fields override the corresponding spec fields. **`_plans`** `dict[str, dict[str, Any]] = {}` --- **`_processes`** `dict[str, Task] = {}` --- **`_runtime_metadata`** `dict[str, dict[str, str]] = {}` --- **`_seeds`** `list[AsyncSandbox] = []` --- **`_stop_task`** `Task | None = None` --- **`_volume_helper`** `AsyncSandbox | None = None` --- **`compose_file`** --- **`document`** `dict[str, Any] = {}` --- **`project`** `= 'compose-' + uuid.uuid4().hex` --- **`provider`** --- **`service_specs`** `= dict(service_specs or {})` --- **`services`** `dict[str, AsyncSandbox] = {}` --- **`volume_sources`** `= dict(volume_sources or {})` --- ```python nemo_gym.sandbox.AsyncSandboxCompose.__aenter__() ``` async ```python nemo_gym.sandbox.AsyncSandboxCompose.__aexit__( exc = () ) ``` async ```python nemo_gym.sandbox.AsyncSandboxCompose._load() ``` ```python nemo_gym.sandbox.AsyncSandboxCompose._prepare() ``` async ```python nemo_gym.sandbox.AsyncSandboxCompose._prepare_volumes() ``` async ```python nemo_gym.sandbox.AsyncSandboxCompose._stop() ``` async ```python nemo_gym.sandbox.AsyncSandboxCompose._validate() -> list[str] ``` ```python nemo_gym.sandbox.AsyncSandboxCompose._wait( name, condition ) ``` async ```python nemo_gym.sandbox.AsyncSandboxCompose.connect( descriptor: collections.abc.Mapping[str, typing.Any], provider ) -> nemo_gym.sandbox.adapters.docker_compose.AsyncSandboxCompose ``` async classmethod Connect to all members without provisioning or restarting services. Like AsyncSandbox.connect, stop() closes the connected sandboxes using provider semantics. The creator retains ownership of managed-volume cleanup and running service/forwarding tasks and must also call stop(). ```python nemo_gym.sandbox.AsyncSandboxCompose.serialize( scope: str | None = None ) -> dict[str, typing.Any] ``` async Describe a running collection using provider connection descriptors. The creating process must keep the collection alive: it owns service and forwarding tasks and managed-volume cleanup. Provider configuration and YAML are not included. ```python nemo_gym.sandbox.AsyncSandboxCompose.start() ``` async ```python nemo_gym.sandbox.AsyncSandboxCompose.stop() ``` async ```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.Sandbox( provider: collections.abc.Mapping[str, typing.Any] | nemo_gym.sandbox.providers.SandboxProvider, spec: nemo_gym.sandbox.providers.SandboxSpec | None = None ) ``` Synchronous wrapper around `AsyncSandbox`. `pty`, `serialize` and `connect` are async-only; use `AsyncSandbox` for those. **`_async_sandbox`** --- **`_runner`** `= _AsyncLoopRunner()` --- ```python nemo_gym.sandbox.Sandbox.__del__() -> None ``` ```python nemo_gym.sandbox.Sandbox.__enter__() -> nemo_gym.sandbox.api.Sandbox ``` ```python nemo_gym.sandbox.Sandbox.__exit__( exc_type: typing.Any, exc_val: typing.Any, exc_tb: typing.Any ) -> None ``` ```python nemo_gym.sandbox.Sandbox.download( remote_path: str, local_path: pathlib.Path | str ) -> None ``` ```python nemo_gym.sandbox.Sandbox.endpoint( port: int ) -> nemo_gym.sandbox.providers.SandboxEndpoint ``` ```python nemo_gym.sandbox.Sandbox.exec( command: str, cwd: str | None = None, env: dict[str, str] | None = None, timeout_s: int | float | None = 180, user: str | int | None = None, preserve_background_services: bool = False ) -> nemo_gym.sandbox.providers.SandboxExecResult ``` ```python nemo_gym.sandbox.Sandbox.pause() -> None ``` ```python nemo_gym.sandbox.Sandbox.resume() -> None ``` ```python nemo_gym.sandbox.Sandbox.start( spec: nemo_gym.sandbox.providers.SandboxSpec | None = None ) -> nemo_gym.sandbox.api.Sandbox ``` ```python nemo_gym.sandbox.Sandbox.status() -> nemo_gym.sandbox.providers.SandboxStatus ``` ```python nemo_gym.sandbox.Sandbox.stop() -> None ``` ```python nemo_gym.sandbox.Sandbox.upload( local_path: pathlib.Path | str, remote_path: str ) -> None ``` ```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.SandboxPty( sandbox: nemo_gym.sandbox.api.AsyncSandbox ) ``` PTY namespace of a sandbox: `await sandbox.pty.create(...)` for a live session, `await sandbox.pty.exec(...)` for one-shot run-and-collect. **`_default_session`** `SandboxPtySession | None = None` --- **`_session_exec_lock`** `= asyncio.Lock()` --- ```python nemo_gym.sandbox.SandboxPty._exec_detached( command: str, session: nemo_gym.sandbox.providers.SandboxPtySession | None, cwd: str | None, env: dict[str, str] | None, user: str | int | None, rows: int, cols: int, pty: bool, timeout_s: int | float | None, poll_interval_s: float ) -> nemo_gym.sandbox.providers.SandboxExecResult ``` async `exec(detach=True)`: hand the command to the session's detached runner, which holds the socket only for brief completion polls. ```python nemo_gym.sandbox.SandboxPty.attach( session_id: str, takeover: bool = True, since: int | None = None ) -> nemo_gym.sandbox.providers.SandboxPtySession ``` async Re-attach to a session opened earlier, here or in another process. Sessions outlive the client that opened them, so `session.session_id` is all another process needs. `takeover` evicts the current holder, whose session then fails with `SandboxPtyError`; without it, attaching to a held session fails. `since` replays retained output from that byte offset first (`0` replays all of it). ```python nemo_gym.sandbox.SandboxPty.create( 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 ) -> nemo_gym.sandbox.providers.SandboxPtySession ``` async Open an interactive terminal; the returned session carries `read`/`read_stderr`/`write`/`resize`/`send_signal`/ `wait_exit`/`close` and is an async context manager. `pty=False` selects pipe mode: no TTY, stdout/stderr split across `read()`/`read_stderr()`. `rows`/`cols` are applied right after the terminal connects, because the backend has no spawn-time size, so a `command` that reads the size in its first moments can still see the 80x24 default; programs that honor SIGWINCH pick up the real size. Close the session before the sandbox stops: a session that outlives its sandbox fails subsequent reads with `SandboxPtyError`. Async-only; the sync `Sandbox` facade does not mirror it. ```python nemo_gym.sandbox.SandboxPty.exec( command: str, session: nemo_gym.sandbox.providers.SandboxPtySession | None = None, cwd: str | None = None, env: dict[str, str] | None = None, timeout_s: int | float | None = 180, user: str | int | None = None, rows: int = 24, cols: int = 80, pty: bool = True, detach: bool = False, poll_interval_s: float = 15.0 ) -> nemo_gym.sandbox.providers.SandboxExecResult ``` async Run one command in a terminal session and collect its output. Without `session`, the sandbox's default-shell session — the oldest live one opened by `create()` with no `command` — is reused, provided the call sets none of the session-shaping arguments (`cwd`/`env`/`user`, non-default `rows`/`cols`, or `pty=False`), since those are fixed at `create()`. Custom-command and attached sessions run arbitrary programs, so they are only used when passed explicitly. When no default-shell session exists (or shaping arguments are given) a private session is opened for the command, drained and closed. Session-mode execs are serialized per sandbox: concurrent calls into one shared stream would corrupt it. With `session` the command runs in that live session, which stays open and keeps its shell state. In a live session the output also contains the shell's echo of the command, `stderr` is best-effort (pipe mode only), and a command that ends the shell (`exit`) raises `SandboxPtyError`. With `detach=True` the command runs without holding a connection while it works: it starts in a session, the socket is dropped, and the session is briefly re-attached every `poll_interval_s` to drain output and check for completion, so a long command occupies a connection for milliseconds per poll instead of its whole runtime (completion latency is bounded by `poll_interval_s`). Nothing is written to the sandbox filesystem; output rides the server's retained window (\~1 MiB) between polls, comes back as one merged stream (`stderr` is `None`), and exceeding the window raises rather than returning truncated output — run bulk-output commands attached or via the exec API instead. A detached exec never reuses the default-shell session implicitly: without `session` it opens a private one. With `session`, the session is detached while the command works, must not be used concurrently, and is attached and reusable again when this returns. PTY mode returns all output on `stdout` and `None` stderr; pipe mode splits the two. A command that outlives `timeout_s` returns `error_type="timeout"` like `sandbox.exec()` rather than raising; in an explicitly passed session that command keeps running and leaves unread output behind, so discard the session rather than reusing it (an implicitly reused session is retired automatically). ```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.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.create_provider( config: collections.abc.Mapping[str, typing.Any] ) -> nemo_gym.sandbox.providers.base.SandboxProvider ``` Instantiate a provider from a single-key provider config. ```python nemo_gym.sandbox.get_provider_class( name: str ) -> nemo_gym.sandbox.providers.registry.ProviderClass ``` Return a provider class by name (explicit > built-in > entry point). ```python nemo_gym.sandbox.list_providers() -> list[str] ``` List available provider names from all sources. ```python nemo_gym.sandbox.register_provider( name: str, provider_class: nemo_gym.sandbox.providers.registry.ProviderClass, override: bool = False ) -> None ``` Register a sandbox provider class. ```python nemo_gym.sandbox.resolve_provider_config( sandbox_provider: str | collections.abc.Mapping[str, typing.Any], named_configs: collections.abc.Mapping[str, typing.Any] | None = None ) -> dict[str, typing.Any] ``` Resolve a `sandbox_provider` field into a single-key provider config dict. **Parameters:** **`sandbox_provider`** `str | Mapping[str, Any]` Either the name of a top-level sandbox config block (resolved from `named_configs`) or an inline single-key provider mapping of the form `{provider_name: {...}}`. --- **`named_configs`** `Mapping[str, Any] | None` — default: None Mapping of top-level config name to config block, typically the merged global config dict. Required when `sandbox_provider` is a name reference. --- **Returns:** `dict[str, Any]` A plain `{provider_name: provider_kwargs}` dict suitable for **Raises:** * `TypeError`: If `sandbox_provider` is neither a string nor a mapping. * `ValueError`: If a named reference cannot be found, or if the block does not hold exactly one provider key. ```python nemo_gym.sandbox.resolve_provider_metadata( sandbox_provider: str | collections.abc.Mapping[str, typing.Any], named_configs: collections.abc.Mapping[str, typing.Any] | None = None ) -> dict[str, typing.Any] ``` Return a sandbox block's `default_metadata`. These are provider-contributed defaults to merge into `SandboxSpec.metadata`. Returns an empty dict when the block has no `default_metadata` key. See `resolve_provider_config` for argument semantics. ```python nemo_gym.sandbox.rewrite_image( image: str | None, rewrites: list[dict[str, str]] ) -> str | None ``` Apply ordered image-prefix rewrites used by sandbox configs. ```python nemo_gym.sandbox.providers.base.ExecResult = SandboxExecResult ``` ## Docs - [nemo_gym.sandbox.access](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/access.md) - [nemo_gym.sandbox.adapters](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/adapters.md) - [nemo_gym.sandbox.adapters.docker_compose](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/adapters/docker_compose.md) - [nemo_gym.sandbox.agent_tools](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/agent_tools.md) - [nemo_gym.sandbox.api](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/api.md) - [nemo_gym.sandbox.attribution](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/attribution.md) - [nemo_gym.sandbox.config](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/config.md) - [nemo_gym.sandbox.providers](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/providers.md) - [nemo_gym.sandbox.providers.apptainer](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/providers/apptainer.md) - [nemo_gym.sandbox.providers.apptainer.provider](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/providers/apptainer/provider.md) - [nemo_gym.sandbox.providers.base](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/providers/base.md) - [nemo_gym.sandbox.providers.daytona](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/providers/daytona.md) - [nemo_gym.sandbox.providers.daytona.provider](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/providers/daytona/provider.md) - [nemo_gym.sandbox.providers.docker](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/providers/docker.md) - [nemo_gym.sandbox.providers.docker.provider](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/providers/docker/provider.md) - [nemo_gym.sandbox.providers.e2b](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/providers/e2b.md) - [nemo_gym.sandbox.providers.e2b.build](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/providers/e2b/build.md) - [nemo_gym.sandbox.providers.e2b.provider](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/providers/e2b/provider.md) - [nemo_gym.sandbox.providers.ecs_fargate](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/providers/ecs_fargate.md) - [nemo_gym.sandbox.providers.ecs_fargate.engine](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/providers/ecs_fargate/engine.md) - [nemo_gym.sandbox.providers.ecs_fargate.provider](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/providers/ecs_fargate/provider.md) - [nemo_gym.sandbox.providers.enroot](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/providers/enroot.md) - [nemo_gym.sandbox.providers.enroot.provider](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/providers/enroot/provider.md) - [nemo_gym.sandbox.providers.local](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/providers/local.md) - [nemo_gym.sandbox.providers.local.provider](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/providers/local/provider.md) - [nemo_gym.sandbox.providers.opensandbox](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/providers/opensandbox.md) - [nemo_gym.sandbox.providers.opensandbox.cleanup_sandboxes](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/providers/opensandbox/cleanup_sandboxes.md) - [nemo_gym.sandbox.providers.opensandbox.provider](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/providers/opensandbox/provider.md) - [nemo_gym.sandbox.providers.opensandbox.pty](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/providers/opensandbox/pty.md) - [nemo_gym.sandbox.providers.opensandbox.snapshots](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/providers/opensandbox/snapshots.md) - [nemo_gym.sandbox.providers.openshell](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/providers/openshell.md) - [nemo_gym.sandbox.providers.openshell.provider](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/providers/openshell/provider.md) - [nemo_gym.sandbox.providers.registry](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/providers/registry.md) - [nemo_gym.sandbox.providers.utils](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/providers/utils.md) - [nemo_gym.sandbox.shell](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/shell.md) - [nemo_gym.sandbox.utils](https://docs.nvidia.com/nemo/gym/v0.6.0/nemo-gym/nemo_gym/sandbox/utils.md)