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:

ProjectCore purposeKey files
verifiers/Core SDK – types, environment base classes, rubric APIverifiers/__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 TUIverifiers/scripts/tui.py
configs/Global configuration scaffoldingconfigs/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:

  1. main → load_environment (creates the concrete Environment subclass).
  2. load_environment → Rubric (adds reward functions, see verifiers/rubrics/rubric.py).
  3. Rubric is the most‑used hub (imported by 79 modules) and subsequently invoked by the rollout loop in verifiers/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.py and verifiers/envs/environment.py. Refactor with guard clauses.
  • Hub module (high) – verifiers/__init__.py is 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_TOKEN permissions – 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: false on checkout – test.yml.
  • MEDIUM Add non‑root USER to Dockerfile.
  • LOW Set timeout-minutes on 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.