Configure Harbor Taskset Runs
This page configures Harbor taskset runs on Kubernetes (Run a Harbor Task Suite on Kubernetes), all under platformConfig.evals.runs:
- Sandbox profiles (
evals.runs.harbor): named rules for every OpenSandbox sandbox in a run: egress, resource ceilings, lifetime and client settings. - Run limits and controller (
evals.runs): concurrency caps, run time limits and how often the run controller creates and settles task Jobs. See Run limits and controller.
About sandbox profiles:
- Profiles live in two blocks of the chart’s
values.yaml:- Chart defaults:
baseHelixConfig→baseHelixConfig.evals.runs.harbordefinesharbor-standard. Don’t edit it. - Your changes: set them under
platformConfig.evals.runs.harborin your own values file.platformConfigis{}in the chart, and the chart merges it over the defaults.- Override
harbor-standardfields or add new profiles there. A list you set replaces the chart’s list. See How your values combine with the chart’s.
- Override
- Chart defaults:
- Users pick a profile at submit:
nemo evals runs submit --sandbox-profile <name>, or"execution": {"sandbox": {"profile": "<name>"}}in a--spec-filerequest (example). Without one, a run getsdefault_sandbox_profile. - Submit copies the profile into the run’s plan. Editing a profile never changes a run that’s already accepted.
- A resubmit with the same idempotency key is checked against the current profiles before it returns the existing run. Keep a profile while its runs may be resubmitted.
- Users can’t list profile names. An unknown name returns a 422 that lists them, so tell your users which names exist.
Before you begin
-
The platform is installed as in Install NeMo Helix Helm Chart. This page reuses its variables
NHX_NAMESPACE,NHX_HELM_RELEASEandNHX_HELM_CHART_VERSION, and writes the chart reference you installed from as<chart>:nemo-helix/nemo-helix,"$NHX_HELM_CHART_REF"for an RC, or the chart archive. -
OpenSandbox is installed and the platform points at it. See OpenSandbox.
-
sandboxClusterCapable: trueandbuilder.enabled: true. The chart then enables taskset runs with one profile,harbor-standard. -
Set
FULLNAME. The chart names its resources<FULLNAME>-<part>: ConfigMap<FULLNAME>-config, and API Service and Deployment${FULLNAME:0:59}-api(it cutsFULLNAMEto 59 characters there). This page uses it to find them, and writes the API Service as<api-service>.- Usually
FULLNAMEis the Helm release name, or<release>-nemo-helixwhen the release name doesn’t containnemo-helix. nameOverrideandfullnameOverridechange it, so read it from the cluster instead of guessing:
- Usually
-
Read the current config:
How your values combine with the chart’s
The chart merges platformConfig over its own defaults:
- Maps merge key by key. Adding
sandbox_profiles.harbor-webkeepsharbor-standard. - Lists are replaced. To add one host to
harbor-standard.agent_setup_egress, set the whole list. - Scalars: your value wins.
- You can’t delete the chart’s
harbor-standard. You can override every key in it. platformConfig.evals.runs.harbor: nullturns taskset runs off.
evals.runs.harbor keys
Profile properties
A new profile starts empty: it inherits nothing from harbor-standard. Every list below defaults to [].
Network
Host format: hostname, *. wildcard hostname, IP or CIDR. No port.
How the profile combines with the network mode in the task’s task.toml:
public(Harbor’s default) → the sandbox reachesegress_allowonly.allowlist→ the sandbox reaches the task’sallowed_hostsplusagent_channel.- Every
allowed_hostsentry must be covered by anegress_allowentry, otherwise the trial fails withTasks may narrow the trusted allowlist but not extend it. A profile entry covers:- the same host, after lowercasing and IP normalization;
- for
*.wikipedia.org: its subdomains at any depth, such asen.wikipedia.org, but notwikipedia.orgitself; - for a CIDR such as
10.0.0.0/8: the addresses and ranges inside it, in the same IP family, such as10.1.2.3or10.1.0.0/16.
- A task host covered only by a
*.wildcard is allowed by name. If it resolves to a private or link-local address, the sandbox still can’t reach that address. To allow one, list the address itself, inegress_allow(or a CIDR around it) and in the task’sallowed_hosts.
- Every
no-network→ the sandbox reachesagent_channelonly.- With a model-calling agent, the task Job fails with
gateway_unreachablebefore any sandbox starts when:no-network: the profile’sagent_channeldoesn’t include the API host.allowlist: neitheragent_channelnor the task’sallowed_hostsincludes it.
- Any mode →
agent_setup_egressis added while the agent installs itself.
Resources
- Without a ceiling, users can request any number of CPUs and any memory. Storage stays capped by
max_disk_mbwhileenforce_disk_limitis on. - Ceilings are per profile. Set them on every profile users may select.
Lifetime
Client
- The server address and API key aren’t profile keys. They come from the
opensandboxHelm values.
Run limits and controller
These keys sit beside harbor under platformConfig.evals.runs and apply to every taskset run, whatever its profile.
Concurrency
A task Job starts only when all three caps have room:
- When several users wait, a free slot goes to the user running the fewest task Jobs.
- Example with the defaults:
- One user submits 3 runs of 100 tasks.
- At most 50 task Jobs run at once: 20 + 20 + 10, oldest run first.
Controller timing
- Cycles start every
interval_seconds. One that runs longer is followed by the next at once, so under load the interval adds no wait. - Raise
interval_secondsfirst when cycles run long: a cycle over 3 intervals (60 s by default) marks the core-controller pod not ready. When cycles are short, a longer interval delays new task Jobs by up to one interval. - Raise
max_creates_per_cycleorsettle_concurrencywhen many runs are open, andcreate_grace_secondswhen the Jobs API is slow to save.
Run time limits
- The budget starts when the run’s first task gets a slot, before its task Job is created, so scheduling and Job startup count against it.
Which key to change
- The cluster is busy with task Jobs → lower
controller.max_cluster_concurrent_jobs. - One user’s runs starve everyone else’s → set
controller.max_concurrent_task_jobs_per_creator(auth on only). - Suites need more than 24 h → raise
default_timeout_seconds, andmax_timeout_secondsif users ask for more. - Runs expire in the queue → raise
queue_timeout_seconds, or raise the concurrency caps.
When a change applies
A config change restarts the API and core-controller pods. Then:
- Concurrency caps → open runs use them from the next cycle. Lowering a cap cancels nothing; new task Jobs wait until the count is below it.
default_timeout_seconds,queue_timeout_seconds,finalization_grace_seconds→ new runs only. A run keeps the values it was accepted with, even while it’s still queued.max_timeout_seconds→ checked at submit only.
Recipes
A new profile must copy the network baseline it needs from harbor-standard: the API host in agent_channel and the full agent_setup_egress list. Without them, model-calling agents can’t install themselves or reach their model.
Add a host an agent needs at install time
-
Copy
harbor-standard.agent_setup_egressfrom the current config. -
Append the host, then set the full list:
Add a profile for tasks that call public hosts
- The API host in
egress_allowandagent_channelkeeps model-calling agents reaching the gateway. *.wikipedia.orgopens Wikipedia’s subdomains, such asen.wikipedia.org, topublictasks. Addwikipedia.orgtoo if tasks need the bare domain. A Harbor task inallowlistmode lists the Wikipedia hosts it needs in its ownallowed_hosts, such asen.wikipedia.org.
Set ceilings on a profile
- Maps merge, so
harbor-standardkeeps its network lists.
Change the default profile
- The new default must carry the network baseline above.
Raise the run limits
default_timeout_secondsmust stay ≤max_timeout_seconds(72 h by default).- Maps merge, so the chart’s
harborblock stays.
Apply and verify
An invalid evals config doesn’t stop the rollout, but what breaks depends on platform auth:
- Auth off: the API starts without the evals service and the run controller. Every
nemo evalscommand returns 404, and the API log has onlyFailed to load 'evals' from 'nemo.services' … skipping. - Auth on: the auth service can’t load the evals plugin either. With the default
authz.on_invalid_plugin: hard_fail, it doesn’t build its authorization bundle, so requests to every service fail, not onlynemo evals. Withquarantineordeny_route,nemo evalscommands return 403.
Validate before you apply.
-
Validate the rendered
evalsconfig. Pass the chart version and values files you installed with, thenharbor-profiles.yaml. This needs the evals plugin of the chart’s release in your Python environment, since another version may accept different keys:- Stable chart
0.10.0→pip install 'nemo-helix[nemo-evals-plugin]==0.10.0'
valid→ apply.- A
ValidationErrornames the bad key, such asruns.harbor.sandbox_profiles.harbor-web.egress_alow Extra inputs are not permitted. Fix the file and validate again.
- Stable chart
-
Upgrade the release with the same chart version and values files and wait for it:
-
The chart truncates
FULLNAMEin these deployment names, as the commands do. -
A config change restarts the API and core-controller pods. New runs get the new profile; accepted runs keep theirs.
-
Don’t use
--reuse-valuesfor profiles: a key you set by mistake stays in the release after you delete it from the file, and setting it tonulldoesn’t remove it.
-
-
Run the hello-world suite with
oracleon the profile, as in the Quickstart (step 1 copies the suite to$SUITE_DIR). The run endscompletedwith resultready. This checks that sandboxes start:Save the taskset ref from the
Rerun these tasks:line. The checks below reuse it, so they upload and build nothing: -
Check the profile is offered. The 422 lists every profile name:
-
Run one task with a model-calling agent on the profile, as in Run with a model-calling agent.
--spec-filerejects--sandbox-profile, so set"execution": {"sandbox": {"profile": "harbor-web"}}inopenhands-run.json. The trial has no install error and non-zero tokens. This checksagent_setup_egressandagent_channel;oracleinstalls nothing and calls no model. -
For ceilings, request one more than the ceiling. The 422 names it: