The Problem
Training and evaluating large‑language‑model (LLM) agents requires a repeatable harness: a dataset, a tool‑enabled runtime, and a scoring rubric. Maintaining these pieces across many tasks quickly becomes ad‑hoc, leading to duplicated scripts, fragile imports, and opaque build artefacts.
What This Does
verifiers is a modular library that packages environments, rubrics, and utility helpers for LLM reinforcement‑learning. The repository is a portfolio of five self‑contained projects:
| Project | Core purpose | Key files |
|---|---|---|
verifiers/ | Core SDK – types, environment base classes, rubric API | verifiers/__init__.py, verifiers/types.py, verifiers/envs/environment.py, verifiers/rubrics/rubric.py |
environments/ | Ready‑made RL tasks (e.g., alphabet_sort, browser_cua_example) | environments/*/pyproject.toml, environments/openenv_echo/proj/server/app.py |
packages/ | Optional extensions (e.g., verifiers-rl) | packages/verifiers-rl/verifiers_rl/scripts/rl.py |
scripts/ | CLI utilities for inspection and TUI | verifiers/scripts/tui.py |
configs/ | Global configuration scaffolding | configs/endpoints.py |
Each environment ships a small Flask server (see environments/openenv_echo/proj/server/app.py) that loads the dataset, instantiates a verifiers.envs.Environment subclass, and registers a verifiers.rubrics.Rubric for reward calculation.
How It Is Wired
Execution begins at the Flask entry point in environments/openenv_echo/proj/server/app.py (function main). The call graph shows:
main→load_environment(creates the concreteEnvironmentsubclass).load_environment→Rubric(adds reward functions, seeverifiers/rubrics/rubric.py).Rubricis the most‑used hub (imported by 79 modules) and subsequently invoked by the rollout loop inverifiers/envs/environment.py(rollout→make_input→Parser).
The most blast‑radius functions are Rubric.__init__ (112 callers) and make_input (79 callers). They sit in the hub module verifiers/__init__.py, which also participates in a circular import chain with verifiers/utils/save_utils.py and verifiers/rubrics/rubric.py. The cycle inflates the instability metric (0.28 for __init__, 0.54 for save_utils) and makes refactoring risky.
File‑system interaction occurs chiefly in verifiers/scripts/tui.py (metadata loading, result discovery) and verifiers/envs/experimental/rlm_env.py (tool merging, external command execution). Network calls are limited to the Flask servers and a few outbound client.post requests in the rollout path.
How To Use It
# Clone the repo
git clone https://github.com/moses-y/verifiers
cd verifiers
# Install Python dependencies (uv is the recommended manager)
uv sync # reads the pyproject.toml files in envs/* and verifiers/
# Build the browser‑CUA template (optional UI component)
cd assets/templates/browserbase/cua
docker build -f Dockerfile.build -t verifiers-cua:latest .
To run a sample environment locally:
# Open a Flask server for the echo environment
cd environments/openenv_echo/proj/server
uv run app.py # starts the server on http://localhost:5000
The server will automatically load the environment, instantiate its rubric, and expose /rollout endpoints used by the RL trainer (packages/verifiers-rl/...).
Real‑World Use
A downstream RL pipeline imports verifiers.envs.Environment to create a training loop:
from verifiers.envs import SimpleEnvironment
from verifiers.rubrics import Rubric
env = SimpleEnvironment(dataset="my_dataset")
rubric = Rubric()
env.attach_rubric(rubric)
for episode in range(1000):
traj = env.rollout(agent)
reward = rubric.score(traj)
trainer.update(traj, reward)
The SimpleEnvironment class lives in verifiers/envs/environment.py; the rubric scoring path goes through verifiers/rubrics/rubric.py, the same hub that other environments share, guaranteeing consistent metric definitions across projects.
Code Health & Issues
Measured findings (static analysis)
- Import cycles (high) – 25 files, e.g.,
verifiers/__init__.py,verifiers/utils/save_utils.py,verifiers/rubrics/rubric.py. Break cycles by extracting shared types or deferring imports. - Deep nesting (high) – up to 6‑level indentation in
verifiers/types.pyandverifiers/envs/environment.py. Refactor with guard clauses. - Hub module (high) –
verifiers/__init__.pyis imported by 79 modules; keep it minimal. - Oversized files (high) –
verifiers/envs/environment.py(>1 200 LOC). Split by responsibility.
Health audit (repo‑level)
- HIGH Pin GitHub Actions to commit SHAs –
.github/workflows/*. - HIGH Add lockfile for
assets/templates/browserbase/cua/package.json. - MEDIUM Declare least‑privilege
GITHUB_TOKENpermissions –publish-envs.yml. - MEDIUM Enable Dependabot / Renovate for 28 manifests.
- MEDIUM Pin Docker base image by digest –
Dockerfile.build. - MEDIUM Add dependency‑vulnerability scan step in CI.
- MEDIUM Set
persist-credentials: falseon checkout –test.yml. - MEDIUM Add non‑root
USERto Dockerfile. - LOW Set
timeout-minuteson workflow jobs –publish-envs.yml.
Other hygiene: tests and CI are present, a license file exists, but no lockfile for the Node template and no explicit least‑privilege token settings.
The Bottom Line
verifiers offers a concrete, reusable stack for LLM RL environments, with clear separation of datasets, runtimes, and rubrics. The codebase is functional but suffers from circular imports, oversized core modules, and several CI‑security gaps that should be addressed before production deployment. Teams comfortable with Python/Flask and container builds will find the library extensible; fixing the highlighted health issues will markedly improve maintainability and supply‑chain safety.