> 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.data.tasks.harbor.models

Pydantic mirror of Harbor's `task.toml` (schema 1.4).

Field names are Harbor's. Deprecated spellings (`version`, `memory`, `storage`,
`allow_internet`) are read and normalized but never written back; the pre-1.3 `multi_step_reward_mode`
is accepted and dropped, as Harbor drops it. Keys this mirror does not know are ignored, as Harbor ignores
them; `HarborSettings.unknown_keys` lists them so the loader can say so.

## Module Contents

### Classes

| Name                                                                                  | Description                                                                                              |
| ------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| [`HarborAgent`](#nemo_gym-data-tasks-harbor-models-HarborAgent)                       | -                                                                                                        |
| [`HarborArtifact`](#nemo_gym-data-tasks-harbor-models-HarborArtifact)                 | One `artifacts` entry: a path copied out of the agent's sandbox after it finishes.                       |
| [`HarborCollectHook`](#nemo_gym-data-tasks-harbor-models-HarborCollectHook)           | `[[verifier.collect]]`: a command run in a service before its artifacts are collected.                   |
| [`HarborEnvironment`](#nemo_gym-data-tasks-harbor-models-HarborEnvironment)           | `[environment]`: the sandbox the agent works in.                                                         |
| [`HarborHealthcheck`](#nemo_gym-data-tasks-harbor-models-HarborHealthcheck)           | Mirrors Harbor's `HealthcheckConfig`: plain numbers with Harbor's defaults and no bounds.                |
| [`HarborMCPServer`](#nemo_gym-data-tasks-harbor-models-HarborMCPServer)               | -                                                                                                        |
| [`HarborPhaseSettings`](#nemo_gym-data-tasks-harbor-models-HarborPhaseSettings)       | -                                                                                                        |
| [`HarborSettings`](#nemo_gym-data-tasks-harbor-models-HarborSettings)                 | -                                                                                                        |
| [`HarborSolution`](#nemo_gym-data-tasks-harbor-models-HarborSolution)                 | -                                                                                                        |
| [`HarborTaskConfig`](#nemo_gym-data-tasks-harbor-models-HarborTaskConfig)             | One `task.toml`.                                                                                         |
| [`HarborTaskStep`](#nemo_gym-data-tasks-harbor-models-HarborTaskStep)                 | One `[[steps]]` entry of `task.toml` (Harbor's `StepConfig`): a step of the task, which the task         |
| [`HarborTaskStepAgent`](#nemo_gym-data-tasks-harbor-models-HarborTaskStepAgent)       | `[steps.agent]`: unset values fall back to the task's `[agent]`, as in Harbor.                           |
| [`HarborTaskStepVerifier`](#nemo_gym-data-tasks-harbor-models-HarborTaskStepVerifier) | `[steps.verifier]`: `user`, `env`, `environment_mode` and `environment` fall back to the task's          |
| [`HarborVerifier`](#nemo_gym-data-tasks-harbor-models-HarborVerifier)                 | `[verifier]`. `inputs` is a Gym extension Harbor has no field for, set from the dataset's `dataset.toml` |

### Functions

| Name                                                                      | Description |
| ------------------------------------------------------------------------- | ----------- |
| [`_nested_settings`](#nemo_gym-data-tasks-harbor-models-_nested_settings) | -           |
| [`_size_to_mb`](#nemo_gym-data-tasks-harbor-models-_size_to_mb)           | -           |

### Data

[`HARBOR_STEP_VERIFIER_TIMEOUT_SEC`](#nemo_gym-data-tasks-harbor-models-HARBOR_STEP_VERIFIER_TIMEOUT_SEC)

[`PROTECTED_ARTIFACT_SOURCES`](#nemo_gym-data-tasks-harbor-models-PROTECTED_ARTIFACT_SOURCES)

[`VERIFIER_OUTPUT_NAMES`](#nemo_gym-data-tasks-harbor-models-VERIFIER_OUTPUT_NAMES)

[`_STEP_NAME`](#nemo_gym-data-tasks-harbor-models-_STEP_NAME)

### API

```python
class nemo_gym.data.tasks.harbor.models.HarborAgent()
```

**Bases:** [HarborPhaseSettings](#nemo_gym-data-tasks-harbor-models-HarborPhaseSettings)

**`timeout_sec`** `float = Field(default=28800, gt=0)`

---

**`user`** `str | int | None = None`

---

```python
class nemo_gym.data.tasks.harbor.models.HarborArtifact()
```

**Bases:** [HarborSettings](#nemo_gym-data-tasks-harbor-models-HarborSettings)

One `artifacts` entry: a path copied out of the agent's sandbox after it finishes.

A bare string is the `source`. `destination` is where it lands relative to the run's
artifacts folder (default: the source path without its leading slash). `service` names a
Compose sidecar; `None` or `"main"` is the agent's own container.

**`destination`** `str | None = None`

---

**`exclude`** `list[str] = Field(default_factory=list)`

---

**`host_path`** `PurePosixPath`

---

**`service`** `str | None = None`

---

**`source`** `str`

---

```python
nemo_gym.data.tasks.harbor.models.HarborArtifact.contained_paths() -> nemo_gym.data.tasks.harbor.models.HarborArtifact
```

```python
nemo_gym.data.tasks.harbor.models.HarborArtifact.from_string(
    data: typing.Any
) -> typing.Any
```

classmethod

```python
class nemo_gym.data.tasks.harbor.models.HarborCollectHook()
```

**Bases:** [HarborSettings](#nemo_gym-data-tasks-harbor-models-HarborSettings)

`[[verifier.collect]]`: a command run in a service before its artifacts are collected.

**`command`** `str`

---

**`service`** `str = 'main'`

---

**`timeout_sec`** `float = Field(default=60, gt=0)`

---

**`user`** `str | int | None = None`

---

```python
class nemo_gym.data.tasks.harbor.models.HarborEnvironment()
```

**Bases:** [HarborPhaseSettings](#nemo_gym-data-tasks-harbor-models-HarborPhaseSettings)

`[environment]`: the sandbox the agent works in.

`docker_image` is optional. A task without one builds from
`environment/Dockerfile` or, when that file only names a base image, runs the
base image directly.

**`build_timeout_sec`** `float = Field(default=600, gt=0)`

---

**`cpus`** `int | None = None`

---

**`deprecated_keys`** `frozenset[str] = frozenset({'allow_internet', 'memory', 'storage'})`

---

**`docker_image`** `str | None = None`

---

**`env`** `dict[str, str] = Field(default_factory=dict)`

---

**`gpu_types`** `list[str] | None = None`

---

**`gpus`** `int | None = None`

---

**`healthcheck`** `HarborHealthcheck | None = None`

---

**`mcp_servers`** `list[HarborMCPServer] = Field(default_factory=list)`

---

**`memory_mb`** `int | None = None`

---

**`network_mode`** `Literal['public', 'no-network', 'allowlist'] = 'public'`

---

**`os`** `Literal['linux', 'windows'] = 'linux'`

---

**`skills_dir`** `str | None = None`

---

**`storage_mb`** `int | None = None`

---

**`workdir`** `str | None = None`

---

```python
nemo_gym.data.tasks.harbor.models.HarborEnvironment.read_deprecated_fields(
    data: typing.Any
) -> typing.Any
```

classmethod

```python
class nemo_gym.data.tasks.harbor.models.HarborHealthcheck()
```

**Bases:** [HarborSettings](#nemo_gym-data-tasks-harbor-models-HarborSettings)

Mirrors Harbor's `HealthcheckConfig`: plain numbers with Harbor's defaults and no bounds.

Published tasks pin values at the lower bound (`retries = 0`: one attempt once the start
period ends), and Harbor loads them; bounding the fields here rejected those tasks.

**`command`** `str`

---

**`interval_sec`** `float = 5.0`

---

**`retries`** `int = 3`

---

**`start_interval_sec`** `float = 5.0`

---

**`start_period_sec`** `float = 0.0`

---

**`timeout_sec`** `float = 30.0`

---

```python
class nemo_gym.data.tasks.harbor.models.HarborMCPServer()
```

**Bases:** [HarborSettings](#nemo_gym-data-tasks-harbor-models-HarborSettings)

**`args`** `list[str] = Field(default_factory=list)`

---

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

---

**`name`** `str`

---

**`transport`** `Literal['stdio', 'sse', 'streamable-http'] = 'sse'`

---

**`url`** `str | None = None`

---

```python
nemo_gym.data.tasks.harbor.models.HarborMCPServer.normalize_transport(
    data: typing.Any
) -> typing.Any
```

classmethod

```python
nemo_gym.data.tasks.harbor.models.HarborMCPServer.require_endpoint() -> nemo_gym.data.tasks.harbor.models.HarborMCPServer
```

```python
class nemo_gym.data.tasks.harbor.models.HarborPhaseSettings()
```

**Bases:** [HarborSettings](#nemo_gym-data-tasks-harbor-models-HarborSettings)

**`allowed_hosts`** `list[str] | None = None`

---

**`network_mode`** `Literal['public', 'no-network', 'allowlist'] | None = None`

---

```python
class nemo_gym.data.tasks.harbor.models.HarborSettings()
```

**Bases:** `BaseModel`

**`deprecated_keys`** `frozenset[str] = frozenset()`

---

**`model_config`** `= ConfigDict(extra='ignore', allow_inf_nan=False)`

---

```python
nemo_gym.data.tasks.harbor.models.HarborSettings.unknown_keys(
    data: typing.Any,
    prefix: str = ''
) -> list[str]
```

classmethod

Dotted paths of the keys in `data` that no field of this model tree declares.

```python
class nemo_gym.data.tasks.harbor.models.HarborSolution()
```

**Bases:** [HarborSettings](#nemo_gym-data-tasks-harbor-models-HarborSettings)

**`env`** `dict[str, str] = Field(default_factory=dict)`

---

```python
class nemo_gym.data.tasks.harbor.models.HarborTaskConfig()
```

**Bases:** [HarborSettings](#nemo_gym-data-tasks-harbor-models-HarborSettings)

One `task.toml`.

**`_timeout_multiplier`** `float = PrivateAttr(default=1.0)`

---

**`agent`** `HarborAgent = Field(default_factory=HarborAgent)`

---

**`artifacts`** `list[HarborArtifact] = Field(default_factory=list)`

---

**`deprecated_keys`** `frozenset[str] = frozenset({'version', 'multi_step_reward_mode'})`

---

**`environment`** `HarborEnvironment = Field(default_factory=HarborEnvironment)`

---

**`is_multi_turn`** `bool`

---

**`is_shared_verifier`** `bool`

Harbor runs the verifier in the agent's container unless the task says otherwise.

As in Harbor, `[verifier].environment_mode = "separate"` or a `[verifier.environment]`
block selects the separate mode, where a fresh container receives `/logs/artifacts` and
the declared `artifacts`. A verifier is shared unless the mode is `"separate"` or a
`[verifier.environment]` block is declared.

---

**`metadata`** `dict[str, Any] = Field(default_factory=dict)`

---

**`multi_step_reward_strategy`** `Literal['mean', 'final'] = 'mean'`

---

**`schema_version`** `str = '1.4'`

---

**`solution`** `HarborSolution = Field(default_factory=HarborSolution)`

---

**`source`** `str | None = None`

---

**`steps`** `list[HarborTaskStep] = Field(default_factory=list)`

---

**`task`** `dict[str, Any] = Field(default_factory=dict)`

---

**`verifier`** `HarborVerifier = Field(default_factory=HarborVerifier)`

---

```python
nemo_gym.data.tasks.harbor.models.HarborTaskConfig.read_deprecated_fields(
    data: typing.Any
) -> typing.Any
```

classmethod

```python
nemo_gym.data.tasks.harbor.models.HarborTaskConfig.step_agent_timeout_sec(
    step: nemo_gym.data.tasks.harbor.models.HarborTaskStep
) -> float
```

```python
nemo_gym.data.tasks.harbor.models.HarborTaskConfig.step_verifier_timeout_sec(
    step: nemo_gym.data.tasks.harbor.models.HarborTaskStep
) -> float
```

The step's own `[steps.verifier].timeout_sec`, else Harbor's step default of 600 s, never the task's
`[verifier].timeout_sec` (`HARBOR_STEP_VERIFIER_TIMEOUT_SEC`).

```python
nemo_gym.data.tasks.harbor.models.HarborTaskConfig.unique_step_names() -> nemo_gym.data.tasks.harbor.models.HarborTaskConfig
```

```python
class nemo_gym.data.tasks.harbor.models.HarborTaskStep()
```

**Bases:** [HarborSettings](#nemo_gym-data-tasks-harbor-models-HarborSettings)

One `[[steps]]` entry of `task.toml` (Harbor's `StepConfig`): a step of the task, which the task
author defines and grades, not a step of a trajectory (`nemo_gym.trajectory.atif_v1_7.AtifStep`).

The loader pairs it with its `steps/<name>/` folder into a `HarborTurn`, as `HarborTaskConfig` pairs
with its folder into a `HarborTask`. The step has its own instruction (`steps/<name>/instruction.md`)
and verifier (the task's `tests/` with `steps/<name>/tests/` on top). `min_reward` stops the episode
after this step when its rewards fall short: a number gates the `reward` key, a mapping gates each named
key, and a step without a verifier result fails every gate.

**`agent`** `HarborTaskStepAgent = Field(default_factory=HarborTaskStepAgent)`

---

**`artifacts`** `list[HarborArtifact] = Field(default_factory=list)`

---

**`healthcheck`** `HarborHealthcheck | None = None`

---

**`min_reward`** `float | dict[str, float] | None = None`

---

**`name`** `str`

---

**`verifier`** `HarborTaskStepVerifier = Field(default_factory=HarborTaskStepVerifier)`

---

```python
nemo_gym.data.tasks.harbor.models.HarborTaskStep.portable_name() -> nemo_gym.data.tasks.harbor.models.HarborTaskStep
```

```python
class nemo_gym.data.tasks.harbor.models.HarborTaskStepAgent()
```

**Bases:** [HarborPhaseSettings](#nemo_gym-data-tasks-harbor-models-HarborPhaseSettings)

`[steps.agent]`: unset values fall back to the task's `[agent]`, as in Harbor.

**`timeout_sec`** `float | None = Field(default=None, gt=0)`

---

**`user`** `str | int | None = None`

---

```python
class nemo_gym.data.tasks.harbor.models.HarborTaskStepVerifier()
```

**Bases:** [HarborPhaseSettings](#nemo_gym-data-tasks-harbor-models-HarborPhaseSettings)

`[steps.verifier]`: `user`, `env`, `environment_mode` and `environment` fall back to the task's
`[verifier]` as Harbor resolves them (`_step_verifier_user`, `resolve_step_verifier_mode`,
`resolve_effective_verifier_env_config`). `timeout_sec` does not: Harbor's step verifier is a
`VerifierConfig` of its own with the 600 s default, so a step that names none is graded within
`HARBOR_STEP_VERIFIER_TIMEOUT_SEC`, whatever the task's `[verifier].timeout_sec` says
(`HarborTaskConfig.step_verifier_timeout_sec`; the loader warns when the two differ). `collect` is the
step's own `[[steps.verifier.collect]]` hooks, run after the task's in the step's collection pass (Harbor's
`_collect_hooks_for`: the task's hooks, then the step's). A shared step cannot declare its own environment, as
the task's verifier cannot (Harbor's `_validate_mode_env_consistency` is on the class both share).

**`collect`** `list[HarborCollectHook] = Field(default_factory=list)`

---

**`env`** `dict[str, str] = Field(default_factory=dict)`

---

**`environment`** `HarborEnvironment | None = None`

---

**`environment_mode`** `Literal['separate', 'shared'] | None = None`

---

**`timeout_sec`** `float | None = Field(default=None, gt=0)`

---

**`user`** `str | int | None = None`

---

```python
nemo_gym.data.tasks.harbor.models.HarborTaskStepVerifier.shared_has_no_environment() -> nemo_gym.data.tasks.harbor.models.HarborTaskStepVerifier
```

```python
class nemo_gym.data.tasks.harbor.models.HarborVerifier()
```

**Bases:** [HarborPhaseSettings](#nemo_gym-data-tasks-harbor-models-HarborPhaseSettings)

`[verifier]`. `inputs` is a Gym extension Harbor has no field for, set from the dataset's `dataset.toml`
(`[gym.tasks."<task_id>".verifier] inputs = [...]`): the names of files under `/logs/verifier` a Compose
sidecar writes during the rollout for `test.sh` to read (kumo's `verifier` service appends `actions.jsonl`
for `main`'s `tests/score.py`). The server empties `/logs/verifier` before a shared verification and
before the next turn of a multi-step task; these names alone survive, as regular files, so an agent-planted
report or reward is never left for the grader. Plain file names: no path separators, never the grader's own
outputs (`VERIFIER_OUTPUT_NAMES`).

**`collect`** `list[HarborCollectHook] = Field(default_factory=list)`

---

**`env`** `dict[str, str] = Field(default_factory=dict)`

---

**`environment`** `HarborEnvironment | None = None`

---

**`environment_mode`** `Literal['separate', 'shared'] | None = None`

---

**`inputs`** `list[str] = Field(default_factory=list)`

---

**`timeout_sec`** `float = Field(default=600, gt=0)`

---

**`user`** `str | int | None = None`

---

```python
nemo_gym.data.tasks.harbor.models.HarborVerifier.inputs_are_file_names() -> nemo_gym.data.tasks.harbor.models.HarborVerifier
```

```python
nemo_gym.data.tasks.harbor.models.HarborVerifier.shared_has_no_environment() -> nemo_gym.data.tasks.harbor.models.HarborVerifier
```

```python
nemo_gym.data.tasks.harbor.models._nested_settings(
    annotation: typing.Any
) -> type[nemo_gym.data.tasks.harbor.models.HarborSettings] | None
```

```python
nemo_gym.data.tasks.harbor.models._size_to_mb(
    raw: str
) -> int
```

```python
nemo_gym.data.tasks.harbor.models.HARBOR_STEP_VERIFIER_TIMEOUT_SEC = 600.0
```

```python
nemo_gym.data.tasks.harbor.models.PROTECTED_ARTIFACT_SOURCES = ('/tests', '/logs/verifier')
```

```python
nemo_gym.data.tasks.harbor.models.VERIFIER_OUTPUT_NAMES = ('reward.json', 'reward.txt', 'test-stdout.txt', '.ng-exit')
```

```python
nemo_gym.data.tasks.harbor.models._STEP_NAME = re.compile('^[A-Za-z0-9][A-Za-z0-9._-]*$')
```