Skip to content

feat: first-class v1 harnesses/tasksets packages (+ README, serve/CLI fixes) - #1600

Merged
mikasenghaas merged 18 commits into
feat/nano-as-v1from
docs/v1-readme
Jun 10, 2026
Merged

feat: first-class v1 harnesses/tasksets packages (+ README, serve/CLI fixes)#1600
mikasenghaas merged 18 commits into
feat/nano-as-v1from
docs/v1-readme

Conversation

@mikasenghaas

@mikasenghaas mikasenghaas commented Jun 10, 2026

Copy link
Copy Markdown
Member

Summary

  • First-class built-in packagespackages/harnesses and packages/tasksets are now real namespaced packages (harnesses/{default,rlm}, tasksets/{harbor_v1,textarena_v1}). Each package's __init__ re-exports its plugins' classes (from harnesses import RLMHarness, from tasksets import HarborTaskset); the loader resolves a built-in id to its namespaced module directly (find_spec), falling back to a flat import for local examples and hub ids. textarena_v1 stays lazily imported (it pulls the optional textarena dep), so import tasksets doesn't require it. Package descriptions are just "Built-in harnesses" / "Built-in tasksets".
  • Renamed the built-in harbor taskset → harbor-v1 (module tasksets.harbor_v1), consistent with textarena-v1 and the -v1 examples.
  • verifiers/v1/README.md — the README for the v1 framework (originally vf-nano), framed as the next version of verifiers. Mirrors the vf-nano README's command-driven structure (Highlights / Install / Quickstart + alias table / Patterns) and folds in the features that landed since on feat/nano-as-v1 (modal runtime + managed runtime lifecycle; per-rollout limits + native retries + wall-clock timeouts; hub ids; v0 --id bridge; vf.User; token-id/logprob traces).
  • serve accepts @ file.toml — serve rejected config-only argv with USAGE before parsing even though @ file.toml supplies the ids; now mirrors eval's references_config_file. (Also: the legacy --id <env-id> path for serving v0 envs through LegacyEnvServer.)
  • prime-pydantic-config bump (dev83 → dev86) — the README uses single-dash short flags (-n / -r / …); on dev83 those parsed as values. Bumped (lock + a >=0.3.0.dev86 floor) so they work.
  • README API/section fixestool_servers → the tools() method; removed the User-simulation section; split the examples enumeration into tasksets/harnesses (matching examples/{tasksets,harnesses}).
  • Removed the hello-rlm-v1 example — dropped the example package + its pyproject source/group + lock entries.

Breaking

  • Built-in plugins are namespaced. The built-in harnesses/tasksets are no longer importable as top-level modules (import rlm / default / harbor / textarena_v1); they're now harnesses.rlm, harnesses.default, tasksets.harbor_v1, tasksets.textarena_v1 (or re-exported: from harnesses import RLMHarness, from tasksets import HarborTaskset). Selection by id (the public surface: --harness.id rlm, eval harbor-v1, …) is unchanged.
  • harbor taskset id → harbor-v1 (e.g. eval harboreval harbor-v1).
  • hello-rlm-v1 example removed.

Verification

  • Every uv run eval … README example is dry-run-checked on dev86 (all short flags resolve; limits/retries/timeouts resolve).
  • First-class packages: from harnesses.rlm import RLMHarness / from tasksets.harbor_v1 import HarborTaskset (and the re-exports from harnesses import RLMHarness / from tasksets import HarborTaskset) resolve from a tmp dir; import tasksets works without textarena; the loader resolves built-in ids (rlmharnesses.rlm, harbor-v1tasksets.harbor_v1, textarena-v1tasksets.textarena_v1) and flat example ids (gsm8k-v1gsm8k_v1); terminal_bench_2_v1 / wordle_v1 import; eval … --harness.id rlm / eval harbor-v1 dry-run resolve.
  • serve @ <serve-config>.toml --dry-run resolves the taskset/harness ids (no longer exits with USAGE).

Note

Medium Risk
Breaking import paths and harbor taskset id affect configs and downstream code; loader resolution change is central to all eval/serve plugin loading.

Overview
Reorganizes built-in v1 plugins into unified harnesses and tasksets packages (harnesses.default / harnesses.rlm, tasksets.harbor_v1 / tasksets.textarena_v1), with package __init__ re-exports and wheel layout updated to ship a single top-level package each. loaders.py now tries find_spec on {group}.{id} before falling back to flat imports for examples and Hub ids.

Breaking: built-in taskset id harborharbor-v1 (e.g. configs/harbor.toml); direct import harbor / import rlm style imports must use tasksets.* / harnesses.*. Example wrappers (terminal-bench-2-v1, wordle-v1) and TextArena user server entrypoint switch to namespaced imports and -m tasksets.textarena_v1.server.

Adds verifiers/v1/README.md (v1 quickstart, patterns, CLI/TOML). serve accepts @ file.toml without a positional taskset (like eval) and routes --id v0 envs through LegacyEnvServer. Bumps prime-pydantic-config to dev86 so README short flags (-n, -r, …) parse correctly. Removes the hello-rlm-v1 example from workspace sources and lockfile.

Reviewed by Cursor Bugbot for commit db03f33. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Reorganize harnesses and tasksets into namespaced packages with updated CLI serve support

  • Moves harnesses and tasksets built-ins under unified namespaced packages (harnesses.*, tasksets.*), adding top-level __init__.py re-exports for each.
  • Updates plugin loader in loaders.py to prefer the namespaced import form (e.g. tasksets.<id>) via importlib.util.find_spec, falling back to the bare module name.
  • Updates serve.py to support legacy v0 environments via --id or configs with is_legacy=true, constructing a LegacyEnvServer in those cases.
  • Removes the hello-rlm-v1 example and renames the harbor taskset id to harbor-v1 throughout.
  • Behavioral Change: existing code importing from harbor import ... or from textarena_v1 import ... must update to the namespaced paths (e.g. from tasksets.harbor_v1 import ...).

Macroscope summarized db03f33.

mikasenghaas and others added 10 commits June 10, 2026 00:43
Adapt the vf-nano README into verifiers/v1/README.md (the vendored v1 framework), keeping
its command-driven structure and folding in the features that landed since: the modal
runtime, per-rollout limits + native retries, hub-installable ids, the v0 backwards-compat
eval (`--id`), rollout-id resource naming + guaranteed teardown, and the user simulator.
Every `uv run eval ...` example is dry-run-verified against the current CLI.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The vendored vf-nano README advertises -n/-r/-m/...; dev83 only accepted them as --n
(single-dash was parsed as a value). dev86 supports single-dash short aliases.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…cle wording

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ompatibility last

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ackwards-compat

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The serve CLI now branches on config.is_legacy to LegacyEnvServer, so a classic v0 env can
be served over ZMQ with `uv run serve --id <env>` (parity with `eval --id`). Verified:
`serve --id reverse-text` brings up the env server (1000 tasks).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…; drop TODOs

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… runtime; re-add Harbor section

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mikasenghaas
mikasenghaas marked this pull request as ready for review June 10, 2026 01:04
Comment thread verifiers/v1/cli/serve.py Outdated
@macroscopeapp

macroscopeapp Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR reorganizes harness/taskset packages and adds documentation. However, an unresolved review comment identifies that the new plugin resolution logic could silently load built-in plugins instead of hub-installed ones with the same normalized name, which warrants human review.

You can customize Macroscope's approvability policy. Learn more.

mikasenghaas and others added 6 commits June 10, 2026 01:56
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Nest the built-in plugins under namespace packages (harnesses/{default,rlm}, tasksets/{harbor,textarena_v1}), each with an __init__ exposing a lazy REGISTRY (id -> dotted module). The loader resolves a built-in id through its group registry to the namespaced module, falling back to a flat import for local examples and hub ids. User-facing ids are unchanged (--harness.id rlm, eval harbor, ...); class names keep the <Name>Harness/<Name>Taskset convention.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
serve rejected config-only argv with USAGE before parsing, even though @ file.toml supplies the ids. Mirror eval's references_config_file check so a saved config runs with just @ file.toml.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drop the hello-rlm-v1 example package and its pyproject source/group + lock entries.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
tool_servers -> the tools() method; remove the User simulation section; split the examples enumeration into tasksets/harnesses (matching examples/{tasksets,harnesses}).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…arbor-v1

- harnesses/tasksets __init__ re-export their plugins' classes instead of a REGISTRY dict; the loader resolves the namespaced module directly via find_spec (flat fallback for local/hub ids). textarena_v1 stays lazy (optional textarena dep) so 'import tasksets' doesn't require it.

- rename the built-in taskset harbor -> harbor-v1 (module tasksets.harbor_v1), consistent with textarena-v1 and the -v1 examples; update configs + README.

- fix flat imports broken by namespacing: terminal-bench-2-v1 and wordle-v1 import from tasksets.{harbor_v1,textarena_v1}; the textarena user sim launches '-m tasksets.textarena_v1.server', which imports from tasksets.textarena_v1.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mikasenghaas mikasenghaas changed the title docs: add a verifiers.v1 README feat: first-class v1 harnesses/tasksets packages (+ README, serve/CLI fixes) Jun 10, 2026
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
macroscopeapp[bot]
macroscopeapp Bot previously approved these changes Jun 10, 2026
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@macroscopeapp
macroscopeapp Bot dismissed their stale review June 10, 2026 02:23

Dismissing prior approval to re-evaluate db03f33

@mikasenghaas
mikasenghaas merged commit 6c4499a into feat/nano-as-v1 Jun 10, 2026
5 checks passed

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit db03f33. Configure here.

Comment thread verifiers/v1/loaders.py
demand; any other is a local package (hyphens → underscores)."""
module = ensure_installed(plugin_id)
namespaced = f"{group}.{module}"
target = namespaced if importlib.util.find_spec(namespaced) else module

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hub ids shadowed by builtins

Medium Severity

_import_plugin always prefers tasksets.{module} / harnesses.{module} whenever find_spec succeeds, using only the normalized name from ensure_installed. Environments Hub ids like org/harbor-v1 or org/rlm normalize to the same module names as built-ins, so hub installs can silently load the vendored plugin instead of the hub package.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit db03f33. Configure here.

pull Bot pushed a commit to Stars1233/verifiers that referenced this pull request Jun 23, 2026
… fixes) (PrimeIntellect-ai#1600)

* docs(v1): add a verifiers.v1 README

Adapt the vf-nano README into verifiers/v1/README.md (the vendored v1 framework), keeping
its command-driven structure and folding in the features that landed since: the modal
runtime, per-rollout limits + native retries, hub-installable ids, the v0 backwards-compat
eval (`--id`), rollout-id resource naming + guaranteed teardown, and the user simulator.
Every `uv run eval ...` example is dry-run-verified against the current CLI.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(v1): frame v1 as the new version; Highlights header; drop rl extra

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: bump prime-pydantic-config to dev86 for single-dash short flags

The vendored vf-nano README advertises -n/-r/-m/...; dev83 only accepted them as --n
(single-dash was parsed as a value). dev86 supports single-dash short aliases.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(v1): single-dash aliases, advanced configs in quickstart, lifecycle wording

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(v1): restore Limits & retries; drop Installable ids; Backwards compatibility last

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(v1): note v0 is untouched (old entrypoints fully supported) in backwards-compat

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(v1): serve a v0 env via --id (legacy bridge), mirroring eval

The serve CLI now branches on config.is_legacy to LegacyEnvServer, so a classic v0 env can
be served over ZMQ with `uv run serve --id <env>` (parity with `eval --id`). Verified:
`serve --id reverse-text` brings up the env server (1000 tasks).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(v1): tasksets/harnesses section (packages vs examples); serve v0; drop TODOs

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: drop inline comment on the prime-pydantic-config pin

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(v1): lead Highlights with composable taskset×harness + swappable runtime; re-add Harbor section

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(v1): say packages, not plugins

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(v1): first-class harnesses/tasksets packages with a registry

Nest the built-in plugins under namespace packages (harnesses/{default,rlm}, tasksets/{harbor,textarena_v1}), each with an __init__ exposing a lazy REGISTRY (id -> dotted module). The loader resolves a built-in id through its group registry to the namespaced module, falling back to a flat import for local examples and hub ids. User-facing ids are unchanged (--harness.id rlm, eval harbor, ...); class names keep the <Name>Harness/<Name>Taskset convention.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(v1): let serve accept @ file.toml

serve rejected config-only argv with USAGE before parsing, even though @ file.toml supplies the ids. Mirror eval's references_config_file check so a saved config runs with just @ file.toml.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore(v1): remove hello-rlm example

Drop the hello-rlm-v1 example package and its pyproject source/group + lock entries.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(v1): fix tools API ref, drop user-sim section, split examples table

tool_servers -> the tools() method; remove the User simulation section; split the examples enumeration into tasksets/harnesses (matching examples/{tasksets,harnesses}).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(v1): re-export built-ins (drop registry), rename harbor -> harbor-v1

- harnesses/tasksets __init__ re-export their plugins' classes instead of a REGISTRY dict; the loader resolves the namespaced module directly via find_spec (flat fallback for local/hub ids). textarena_v1 stays lazy (optional textarena dep) so 'import tasksets' doesn't require it.

- rename the built-in taskset harbor -> harbor-v1 (module tasksets.harbor_v1), consistent with textarena-v1 and the -v1 examples; update configs + README.

- fix flat imports broken by namespacing: terminal-bench-2-v1 and wordle-v1 import from tasksets.{harbor_v1,textarena_v1}; the textarena user sim launches '-m tasksets.textarena_v1.server', which imports from tasksets.textarena_v1.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(v1): note the harbor CLI prerequisite for harbor-v1

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* style(v1): ruff format serve.py

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant