> This page is for version 0.4.0.
> 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.agent_utils.process_supervisor

Standalone Linux process supervisor to upload beside a sandboxed harness.

Uses only the standard library; Gym need not be installed in the task sandbox.
The receipt confirms termination independently of the harness result. On forced
stop, newly adopted children are also drained, including tools in other sessions.
Detached services adopted before stopping remain for verification. Natural exit
only drains the harness group: orphaned services and unfinished detached tools
cannot be distinguished without cooperation from the harness.

## Module Contents

### Classes

| Name                                                                        | Description                                |
| --------------------------------------------------------------------------- | ------------------------------------------ |
| [`CleanupReceipt`](#nemo_gym-agent_utils-process_supervisor-CleanupReceipt) | Outcome after bounded harness termination. |

### Functions

| Name                                                                                              | Description                                                                    |
| ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| [`_child_pids`](#nemo_gym-agent_utils-process_supervisor-_child_pids)                             | Read this single-threaded subreaper's current children.                        |
| [`_group_has_live_processes`](#nemo_gym-agent_utils-process_supervisor-_group_has_live_processes) | -                                                                              |
| [`_positive_seconds`](#nemo_gym-agent_utils-process_supervisor-_positive_seconds)                 | -                                                                              |
| [`_reap_process_group`](#nemo_gym-agent_utils-process_supervisor-_reap_process_group)             | Drain the group and, on forced stop, newly adopted tools within one budget.    |
| [`_supervise`](#nemo_gym-agent_utils-process_supervisor-_supervise)                               | Stop the harness and forced-stop tools; preserve earlier detached services.    |
| [`exec_timeout`](#nemo_gym-agent_utils-process_supervisor-exec_timeout)                           | Reserve TERM grace, direct-process reaping, and process-group reaping.         |
| [`main`](#nemo_gym-agent_utils-process_supervisor-main)                                           | Run COMMAND and atomically write its cleanup receipt outside the task workdir. |

### Data

[`CLEANUP_PHASE_COUNT`](#nemo_gym-agent_utils-process_supervisor-CLEANUP_PHASE_COUNT)

[`DEFAULT_CLEANUP_TIMEOUT`](#nemo_gym-agent_utils-process_supervisor-DEFAULT_CLEANUP_TIMEOUT)

### API

```python
class nemo_gym.agent_utils.process_supervisor.CleanupReceipt
```

**Bases:** `typing.TypedDict`

Outcome after bounded harness termination.

`cleanup_confirmed` means no live harness-group members remain. Forced
stops also drain newly adopted children. Previously adopted detached services
remain until the owner closes the sandbox; this is not a sandbox-empty check.

**`cleanup_confirmed`** `bool`

---

**`error`** `str | None`

---

**`return_code`** `int | None`

---

**`timed_out`** `bool`

---

```python
nemo_gym.agent_utils.process_supervisor._child_pids() -> set[int]
```

Read this single-threaded subreaper's current children.

```python
nemo_gym.agent_utils.process_supervisor._group_has_live_processes(
    pgid: int
) -> bool
```

```python
nemo_gym.agent_utils.process_supervisor._positive_seconds(
    value: str
) -> float
```

```python
nemo_gym.agent_utils.process_supervisor._reap_process_group(
    pgid: int,
    timeout: float,
    preserved_children: set[int] | None = None
) -> None
```

Drain the group and, on forced stop, newly adopted tools within one budget.

```python
nemo_gym.agent_utils.process_supervisor._supervise(
    command: list[str],
    timeout: float,
    cleanup_timeout: float = DEFAULT_CLEANUP_TIMEOUT,
    stop_path: pathlib.Path | None = None
) -> nemo_gym.agent_utils.process_supervisor.CleanupReceipt
```

Stop the harness and forced-stop tools; preserve earlier detached services.

```python
nemo_gym.agent_utils.process_supervisor.exec_timeout(
    timeout: float,
    cleanup_timeout: float = DEFAULT_CLEANUP_TIMEOUT
) -> float
```

Reserve TERM grace, direct-process reaping, and process-group reaping.

The extra 30 seconds cover startup, polling, and receipt I/O beyond those
bounded cleanup phases. Keep their count shared with the controller budget.

```python
nemo_gym.agent_utils.process_supervisor.main() -> int
```

Run COMMAND and atomically write its cleanup receipt outside the task workdir.

```python
nemo_gym.agent_utils.process_supervisor.CLEANUP_PHASE_COUNT = 3
```

```python
nemo_gym.agent_utils.process_supervisor.DEFAULT_CLEANUP_TIMEOUT = 10.0
```