> This page is for version 0.5.1.
> For other versions, use one of these documentation indexes:
> - Main (default): https://docs.nvidia.com/nemo/gym/main/llms.txt
> - 0.7.0: https://docs.nvidia.com/nemo/gym/v0.7.0/llms.txt
> - 0.6.0: https://docs.nvidia.com/nemo/gym/v0.6.0/llms.txt
> - 0.5.1: https://docs.nvidia.com/nemo/gym/v0.5.1/llms.txt
> - 0.5.0: https://docs.nvidia.com/nemo/gym/v0.5.0/llms.txt
> - 0.4.0: https://docs.nvidia.com/nemo/gym/v0.4.0/llms.txt
> - 0.3.0: https://docs.nvidia.com/nemo/gym/v0.3.0/llms.txt
> - 0.2.1: https://docs.nvidia.com/nemo/gym/v0.2.1/llms.txt

> 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.agents.utils.sandbox_python

A Python harness's private runtime, built on the Agent Server host and uploaded into the task sandbox.

The sandbox needs no network, no `uv` and no Python of its own. For each sandbox platform, the host downloads a
pinned python-build-standalone CPython and checks its SHA-256, then installs the harness's requirements for that
platform with `uv` into a separate site-packages archive. Packages are pinned to the versions installed in this
Agent Server's environment, so the sandbox runs the versions the adapter is tested with. Requirements given as
direct URLs, such as a harness pinned to a commit, are built from source on the host; every other package must
publish a wheel for the sandbox's platform. Both archives are cached on the host under `sandbox_python` in Gym's
`cache_dir`.

In the sandbox, `install_python_runtime.sh` unpacks the archives in a private directory, checks that the runtime
imports the harness, and renames it into place, so a concurrent seed never sees a partial runtime. The runtime
lives under `/tmp`, outside the task's working directory and `HOME`, and every command runs from `/`.

## Module Contents

### Classes

| Name                                                                                 | Description                                                                                  |
| ------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------- |
| [`SandboxPlatform`](#nemo_gym-agents-utils-sandbox_python-SandboxPlatform)           | The sandbox's CPU architecture and C library, which select the Python build and the wheels.  |
| [`SandboxPythonRuntime`](#nemo_gym-agents-utils-sandbox_python-SandboxPythonRuntime) | A harness's private Python in the sandbox: the pinned CPython with `requirements` installed. |

### Functions

| Name                                                                                       | Description                                                                                            |
| ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------ |
| [`_agent_environment_pins`](#nemo_gym-agents-utils-sandbox_python-_agent_environment_pins) | `name==version` for each package this server's environment installed from an index.                    |
| [`_cache_dir`](#nemo_gym-agents-utils-sandbox_python-_cache_dir)                           | Where the host keeps the archives: `sandbox_python` under Gym's `cache_dir`.                           |
| [`_cached`](#nemo_gym-agents-utils-sandbox_python-_cached)                                 | `path`, built once per host. Builders write atomically, so other processes see it whole or not at all. |
| [`_discard`](#nemo_gym-agents-utils-sandbox_python-_discard)                               | Remove `path` from the sandbox, best effort. Cancelling the caller does not stop the removal.          |
| [`_environment_proxy`](#nemo_gym-agents-utils-sandbox_python-_environment_proxy)           | The proxy the host's environment names for `url`. Gym's shared HTTP client does not read it itself.    |
| [`_forget_build`](#nemo_gym-agents-utils-sandbox_python-_forget_build)                     | -                                                                                                      |
| [`_python_archive`](#nemo_gym-agents-utils-sandbox_python-_python_archive)                 | The pinned python-build-standalone archive for `platform`, checked against its published SHA-256.      |
| [`_run`](#nemo_gym-agents-utils-sandbox_python-_run)                                       | -                                                                                                      |
| [`_sha256`](#nemo_gym-agents-utils-sandbox_python-_sha256)                                 | -                                                                                                      |
| [`_source_built`](#nemo_gym-agents-utils-sandbox_python-_source_built)                     | Names of the requirements given as direct URLs; uv builds these from source on the host.               |
| [`_write_archive`](#nemo_gym-agents-utils-sandbox_python-_write_archive)                   | -                                                                                                      |
| [`probe_sandbox_platform`](#nemo_gym-agents-utils-sandbox_python-probe_sandbox_platform)   | Ask the sandbox for its kernel, machine and C library.                                                 |

### Data

[`LOG`](#nemo_gym-agents-utils-sandbox_python-LOG)

[`PYTHON_VERSION`](#nemo_gym-agents-utils-sandbox_python-PYTHON_VERSION)

[`_BUILDS`](#nemo_gym-agents-utils-sandbox_python-_BUILDS)

[`_INSTALLER`](#nemo_gym-agents-utils-sandbox_python-_INSTALLER)

[`_MACHINES`](#nemo_gym-agents-utils-sandbox_python-_MACHINES)

[`_MANYLINUX_LEVELS`](#nemo_gym-agents-utils-sandbox_python-_MANYLINUX_LEVELS)

[`_PLATFORM_PROBE`](#nemo_gym-agents-utils-sandbox_python-_PLATFORM_PROBE)

[`_PYTHON_DOWNLOADS`](#nemo_gym-agents-utils-sandbox_python-_PYTHON_DOWNLOADS)

[`_PYTHON_FILE`](#nemo_gym-agents-utils-sandbox_python-_PYTHON_FILE)

[`_PYTHON_RELEASE`](#nemo_gym-agents-utils-sandbox_python-_PYTHON_RELEASE)

[`_PYTHON_SHA256`](#nemo_gym-agents-utils-sandbox_python-_PYTHON_SHA256)

[`_SITE_PACKAGES`](#nemo_gym-agents-utils-sandbox_python-_SITE_PACKAGES)

### API

```python
class nemo_gym.agents.utils.sandbox_python.SandboxPlatform(
    arch: str,
    libc: str,
    glibc_minor: int | None = None
)
```

Dataclass

The sandbox's CPU architecture and C library, which select the Python build and the wheels.

**`arch`** `str`

---

**`glibc_minor`** `int | None = None`

---

**`libc`** `str`

---

**`wheel_platform`** `str`

The `uv pip --python-platform` value whose wheels run in the sandbox.

---

```python
class nemo_gym.agents.utils.sandbox_python.SandboxPythonRuntime(
    harness: str,
    requirements: tuple[str, ...],
    import_check: str,
    overrides: tuple[str, ...] = ()
)
```

Dataclass

A harness's private Python in the sandbox: the pinned CPython with `requirements` installed.

`import_check` is Python source that runs without error only in a usable runtime, for example
`"import run_agent, mcp"`. `overrides` are the uv overrides the adapter's own environment is installed with,
such as the lines of its `overrides.txt`.

**`directory`** `str`

Sandbox directory keyed by everything that goes into the runtime.

A runtime found there, such as one an earlier session left in this sandbox, was built from the same inputs and
is reused. The key covers every index-installed version in this Agent Server's environment, so a runtime
baked into an image is reused only by an Agent Server environment with exactly those versions. The adapter
may keep its own harness files here, beside `python/`.

---

**`harness`** `str`

---

**`import_check`** `str`

---

**`overrides`** `tuple[str, ...] = ()`

---

**`python`** `str`

The runtime's interpreter in the sandbox, once `is_installed()` passes or `install()` returns.

Run an absolute harness script with `-E -s`: ignore the task's Python environment settings and user
site-packages without changing the environment inherited by tool subprocesses. The script directory
must belong to the harness, so task files cannot shadow its imports.

---

**`requirements`** `tuple[str, ...]`

---

```python
nemo_gym.agents.utils.sandbox_python.SandboxPythonRuntime._build_site_packages(
    platform: nemo_gym.agents.utils.sandbox_python.SandboxPlatform,
    destination: pathlib.Path
) -> None
```

async

```python
nemo_gym.agents.utils.sandbox_python.SandboxPythonRuntime._site_packages_archive(
    platform: nemo_gym.agents.utils.sandbox_python.SandboxPlatform
) -> pathlib.Path
```

async

```python
nemo_gym.agents.utils.sandbox_python.SandboxPythonRuntime.install(
    sandbox: nemo_gym.sandbox.api.AsyncSandbox,
    timeout_s: float
) -> None
```

async

Build the runtime for the sandbox's platform on this host if needed, then upload and publish it.

`timeout_s` bounds the whole installation, including a build that another seed started. Raises
`RuntimeError` when the platform is unsupported, the host build or download fails, or the runtime fails
its import check in the sandbox, and `TimeoutError` when `timeout_s` runs out.

```python
nemo_gym.agents.utils.sandbox_python.SandboxPythonRuntime.is_installed(
    sandbox: nemo_gym.sandbox.api.AsyncSandbox
) -> bool
```

async

Whether the runtime in the sandbox passes `import_check`. The existence of the directory proves nothing.

Like the installer's checks, it runs with `HOME` in the runtime directory, because some harnesses write
their state under `HOME` when imported.

```python
nemo_gym.agents.utils.sandbox_python._agent_environment_pins() -> tuple[str, ...]
```

`name==version` for each package this server's environment installed from an index.

Passed to uv as constraints, which keep the extras that dependencies request (an override would replace
`lxml[html_clean]` with plain `lxml`). Packages installed from a URL or a path, including editable ones,
are left free.

```python
nemo_gym.agents.utils.sandbox_python._cache_dir() -> pathlib.Path
```

Where the host keeps the archives: `sandbox_python` under Gym's `cache_dir`.

```python
nemo_gym.agents.utils.sandbox_python._cached(
    path: pathlib.Path,
    build: collections.abc.Callable[[], collections.abc.Awaitable[None]]
) -> pathlib.Path
```

async

`path`, built once per host. Builders write atomically, so other processes see it whole or not at all.

Concurrent callers share one build and its outcome, and a caller that is cancelled leaves it running for the
others. A failed build is retried by the next call.

```python
nemo_gym.agents.utils.sandbox_python._discard(
    sandbox: nemo_gym.sandbox.api.AsyncSandbox,
    path: str
) -> None
```

async

Remove `path` from the sandbox, best effort. Cancelling the caller does not stop the removal.

```python
nemo_gym.agents.utils.sandbox_python._environment_proxy(
    url: str
) -> str | None
```

The proxy the host's environment names for `url`. Gym's shared HTTP client does not read it itself.

```python
nemo_gym.agents.utils.sandbox_python._forget_build(
    path: pathlib.Path,
    build: asyncio.Task[None]
) -> None
```

```python
nemo_gym.agents.utils.sandbox_python._python_archive(
    platform: nemo_gym.agents.utils.sandbox_python.SandboxPlatform
) -> pathlib.Path
```

async

The pinned python-build-standalone archive for `platform`, checked against its published SHA-256.

```python
nemo_gym.agents.utils.sandbox_python._run(
    argv: list[str],
    cwd: pathlib.Path
) -> None
```

async

```python
nemo_gym.agents.utils.sandbox_python._sha256(
    path: pathlib.Path
) -> str
```

```python
nemo_gym.agents.utils.sandbox_python._source_built(
    requirements: collections.abc.Iterable[str]
) -> list[str]
```

Names of the requirements given as direct URLs; uv builds these from source on the host.

```python
nemo_gym.agents.utils.sandbox_python._write_archive(
    source: pathlib.Path,
    archive: pathlib.Path
) -> None
```

```python
nemo_gym.agents.utils.sandbox_python.probe_sandbox_platform(
    sandbox: nemo_gym.sandbox.api.AsyncSandbox
) -> nemo_gym.agents.utils.sandbox_python.SandboxPlatform
```

async

Ask the sandbox for its kernel, machine and C library.

```python
nemo_gym.agents.utils.sandbox_python.LOG = logging.getLogger(__name__)
```

```python
nemo_gym.agents.utils.sandbox_python.PYTHON_VERSION = '3.13.14'
```

```python
nemo_gym.agents.utils.sandbox_python._BUILDS: dict[Path, Task[None]] = {}
```

```python
nemo_gym.agents.utils.sandbox_python._INSTALLER = Path(__file__).with_name('install_python_runtime.sh')
```

```python
nemo_gym.agents.utils.sandbox_python._MACHINES = {'x86_64': 'x86_64', 'amd64': 'x86_64', 'aarch64': 'aarch64', 'arm64': 'aarch64'...
```

```python
nemo_gym.agents.utils.sandbox_python._MANYLINUX_LEVELS = (40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 28, 17)
```

```python
nemo_gym.agents.utils.sandbox_python._PLATFORM_PROBE = 'uname -s; uname -m; libc=$(getconf GNU_LIBC_VERSION 2>/dev/null || ldd --versio...
```

```python
nemo_gym.agents.utils.sandbox_python._PYTHON_DOWNLOADS = 'https://github.com/astral-sh/python-build-standalone/releases/download'
```

```python
nemo_gym.agents.utils.sandbox_python._PYTHON_FILE = 'cpython-{version}%2B{release}-{arch}-unknown-linux-{libc}-install_only_stripped...
```

```python
nemo_gym.agents.utils.sandbox_python._PYTHON_RELEASE = '20260805'
```

```python
nemo_gym.agents.utils.sandbox_python._PYTHON_SHA256 = {'x86_64/gnu': '39e82d05926bdcd206732026bcd878d9f00e288cd227d91c1fabf379b6ea4fa5...
```

```python
nemo_gym.agents.utils.sandbox_python._SITE_PACKAGES = f'python/lib/python{PYTHON_VERSION.rsplit('.', 1)[0]}/site-packages'
```