Marin runs Harbor benchmarks through the shared evaluation launcher. The launcher starts one model
server, gives Harbor its Iris capability URL, normalizes completed trials into v2
EvalRunRecord/EvalSample artifacts, and tears inference down after the selected evaluations
finish.
Harbor provides containerized agent benchmarks such as Terminal-Bench, SWE-bench Verified, AIME, GAIA, BFCL, and Aider. Trials can run in Daytona or another Harbor-supported sandbox environment. See Running Evaluations with Marin for the model and suite command matrix. This page documents Harbor-specific configuration and output behavior.
Use a model and evaluation name from experiments/evaluation/models.py and
experiments/evaluation/evals.py:
# Inspect placement, task limit, and record destination.
uv run python -m experiments.evaluation.cli launch \
--model qwen3-8b \
--evals tb2-lite \
--dry-run
# Serve once and run two Terminal-Bench tasks in Daytona.
uv run python -m experiments.evaluation.cli launch \
--model qwen3-8b \
--evals tb2-liteThe agentic suite expands to the standard Harbor presets:
uv run python -m experiments.evaluation.cli launch \
--model qwen3-8b \
--evals agenticUse --limit N to cap the number of trials and --no-wait to return after submission.
Launch a Harbor JobConfig without adding it to the catalog:
# Validate policy, model overlay, and placement without opening Iris.
uv run python -m experiments.evaluation.cli launch \
--model qwen3-8b \
--harbor-config experiments/evaluation/configs/harbor/aime-smoke.yaml \
--limit 2 \
--dry-run
# Serve the model and run the checked-in policy with a two-task cap.
uv run python -m experiments.evaluation.cli launch \
--model qwen3-8b \
--harbor-config experiments/evaluation/configs/harbor/aime-smoke.yaml \
--limit 2--harbor-config is repeatable and additive with --evals. All selected built-in and supplied
Harbor policies pass pinned-schema and placeholder effective-job validation before the launcher
opens an Iris client.
Daytona-backed definitions in experiments/evaluation/evals.py own their credential references.
They use DAYTONA_API_KEY from the launch environment when present, then fall back to the approved
Google Secret Manager version. DAYTONA_API_KEY is the only supported environment override.
The generic launcher resolves declared references immediately before Iris submission. The isolated Harbor subprocess receives the Daytona key without inheriting the orchestrator's other credentials. Do not put resolved credentials in model YAMLs, runner configs, or evaluation artifacts.
Harbor receives a RunningModel whose base URL is an Iris link endpoint. The inference runner
chooses the opaque endpoint name, registers either the direct server or broker proxy with Iris, and
mints the capability URL. Daytona never receives a worker address.
Each inference session chooses an opaque endpoint name. Iris endpoint leases remove abandoned registrations, and a retried task attempt atomically replaces its own same-name registration.
Harbor policy belongs in YAML. This example uses a Hugging Face repository whose root contains Harbor task directories:
n_concurrent_trials: 4
environment:
type: daytona
agents:
- name: terminus-2
datasets:
- name: hf://DCAgent2/terminal_bench_2
ref: mainUse datasets[].name, not datasets[].path, for hf://org/repository. The evaluator downloads the
snapshot on the submitted worker and gives Harbor a local path. A Harbor registry source uses its
native selector, such as name: aime plus version: "1.0". A local source uses a relative path:
environment:
type: daytona
agents:
- name: terminus-2
datasets:
- path: tasksLocal paths resolve against the directory containing the policy. The resulting directory must remain inside the Marin workspace and must be included in the Iris workspace bundle. The launcher stores its workspace-relative path so the submitted worker resolves it under the unpacked workspace. Absolute, outside-workspace, and missing local directories fail before Iris submission. Hugging Face selector syntax is checked before submission; repository availability is checked when the worker downloads the snapshot.
Every catalog policy lives under experiments/evaluation/configs/harbor/ and shares its filename
with its EVALS key. Keep suite membership, runtime task caps, model and hardware selection, and
secret source declarations in experiments/evaluation/evals.py.
Marin does not install or import Harbor, harbor_config, Daytona, or Harbor's path runtime. The
root workspace lock contains none of those packages. marin.external_dependencies.HARBOR identifies
the exact Git revision used by two isolated calls:
- Preflight parses YAML or JSON with Harbor's Pydantic models, rejects unsupported launch shapes, validates a placeholder model/endpoint overlay, and emits opaque deterministic policy JSON plus Marin-owned metadata.
- Execution reparses the opaque policy, applies the real endpoint, served model, output directory, materialized dataset path, model kwargs, and task limit, then validates the complete typed job before calling Harbor.
Runtime values do not change the source-policy digest. Policy kwargs override model-catalog kwargs;
the served endpoint/model, output paths, materialized source, and explicit --limit override both.
Temporary policy and overlay files are owner-readable and removed after each isolated call.
Preflight snapshots Harbor's infrastructure, agent, passthrough, and undecided error categories from
the pinned harbor-config environment. Marin uses that snapshot to classify trial results and records
the Harbor commit SHA in record.json. Undecided errors are known to Harbor but have no default scoring
policy; Marin leaves them ungraded and counts them against the completion gate. Names absent from all
four categories fail the run as an infrastructure failure, so taxonomy changes cannot silently alter
scoring or completion coverage.
The agent's model_info.max_input_tokens comes from the model's resolved serve.max_model_len and its
model_info.max_output_tokens from generation.max_gen_toks, so the agent compacts against the
window the server actually offers. With auto_overrides, explicit context limits are clamped to the
checkpoint's native window before Harbor preflight; the batch retains that resolved serving configuration.
A policy may state a lower limit to keep headroom under that window, and the lower limit wins:
grug-opencode-id.yaml asks for 64512 input tokens against a
model serving 65536. A policy limit above the served one fails preflight, before Iris opens, with
both values named. A limit neither the model nor the policy states falls back to Harbor's own
default, 32768 input and 8192 output tokens. --dry-run prints the resolved pair per Harbor eval
and record.json keeps it under eval.harbor.
Each Harbor evaluation writes:
{records_prefix}/{run_id}/record.json{records_prefix}/{run_id}/results/samples_harbor.parquet- durable Harbor trial directories and trajectory references
Every completed trial becomes an agentic EvalSample. The verifier reward is stored as
Grading(method="harbor:verifier"), and the trajectory is referenced by trajectory_uri. Evaldash
ingests the record and sample parquet in the same way as Evalchemy runs. record.json stores the
deterministic source-policy digest and any Marin runtime task cap. A source policy's own n_tasks
remains part of the policy digest.