feat: first-class v1 harnesses/tasksets packages (+ README, serve/CLI fixes) - #1600
Conversation
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>
ApprovabilityVerdict: 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. |
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>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Dismissing prior approval to re-evaluate db03f33
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ 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.
| 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 |
There was a problem hiding this comment.
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.
Reviewed by Cursor Bugbot for commit db03f33. Configure here.
… 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>


Summary
packages/harnessesandpackages/tasksetsare 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_v1stays lazily imported (it pulls the optionaltextarenadep), soimport tasksetsdoesn't require it. Package descriptions are just "Built-in harnesses" / "Built-in tasksets".harbortaskset →harbor-v1(moduletasksets.harbor_v1), consistent withtextarena-v1and the-v1examples.verifiers/v1/README.md— the README for the v1 framework (originallyvf-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 onfeat/nano-as-v1(modal runtime + managed runtime lifecycle; per-rollout limits + native retries + wall-clock timeouts; hub ids; v0--idbridge;vf.User; token-id/logprob traces).serveaccepts@ file.toml— serve rejected config-only argv withUSAGEbefore parsing even though@ file.tomlsupplies the ids; now mirrors eval'sreferences_config_file. (Also: the legacy--id <env-id>path for serving v0 envs throughLegacyEnvServer.)-n/-r/ …); ondev83those parsed as values. Bumped (lock + a>=0.3.0.dev86floor) so they work.tool_servers→ thetools()method; removed the User-simulation section; split the examples enumeration into tasksets/harnesses (matchingexamples/{tasksets,harnesses}).hello-rlm-v1example — dropped the example package + its pyproject source/group + lock entries.Breaking
import rlm/default/harbor/textarena_v1); they're nowharnesses.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.harbortaskset id →harbor-v1(e.g.eval harbor→eval harbor-v1).hello-rlm-v1example removed.Verification
uv run eval …README example is dry-run-checked ondev86(all short flags resolve; limits/retries/timeouts resolve).from harnesses.rlm import RLMHarness/from tasksets.harbor_v1 import HarborTaskset(and the re-exportsfrom harnesses import RLMHarness/from tasksets import HarborTaskset) resolve from a tmp dir;import tasksetsworks withouttextarena; the loader resolves built-in ids (rlm→harnesses.rlm,harbor-v1→tasksets.harbor_v1,textarena-v1→tasksets.textarena_v1) and flat example ids (gsm8k-v1→gsm8k_v1);terminal_bench_2_v1/wordle_v1import;eval … --harness.id rlm/eval harbor-v1dry-run resolve.serve @ <serve-config>.toml --dry-runresolves the taskset/harness ids (no longer exits withUSAGE).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
harnessesandtasksetspackages (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.pynow triesfind_specon{group}.{id}before falling back to flat imports for examples and Hub ids.Breaking: built-in taskset id
harbor→harbor-v1(e.g.configs/harbor.toml); directimport harbor/import rlmstyle imports must usetasksets.*/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).serveaccepts@ file.tomlwithout a positional taskset (like eval) and routes--idv0 envs throughLegacyEnvServer. Bumpsprime-pydantic-configto dev86 so README short flags (-n,-r, …) parse correctly. Removes thehello-rlm-v1example 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
harnessesandtasksetsbuilt-ins under unified namespaced packages (harnesses.*,tasksets.*), adding top-level__init__.pyre-exports for each.tasksets.<id>) viaimportlib.util.find_spec, falling back to the bare module name.--idor configs withis_legacy=true, constructing aLegacyEnvServerin those cases.hello-rlm-v1example and renames theharbortaskset id toharbor-v1throughout.from harbor import ...orfrom textarena_v1 import ...must update to the namespaced paths (e.g.from tasksets.harbor_v1 import ...).Macroscope summarized db03f33.