Docs · how to

Grade an episode with a separate verifier

Declare a verifier in the compose file and run denv verify so the grader never shares a process tree with the agent.

1. Declare the agent service and the verifier

x-denv:
  kind: rl-environment
  agent:
    service: box                       # must set a non-root user
  verifier:
    image: ghcr.io/you/grader:1.2      # or `service: <name>` to grade inside a service of the fork
    command: ["/grade.sh"]
    collect: ["/home/agent/answer.txt", "/home/agent/out"]
    timeout_sec: 300

collect paths are absolute paths inside the agent service. They are copied to a root-owned directory before anything is graded.

2. Write the grader

The grader sees the copy at /submission, read-only, and writes the reward:

#!/bin/sh
# /grade.sh inside ghcr.io/you/grader:1.2
mkdir -p /logs/verifier
if diff -q /submission/home/agent/answer.txt /expected.txt >/dev/null; then
  echo 1 > /logs/verifier/reward.txt
else
  echo 0 > /logs/verifier/reward.txt
fi

If reward.txt is absent, the last line of stdout is parsed as the reward. The grader runs on the fork's network, so it can query the fork's database too; it runs as root in its own container, with the agent's processes already stopped.

3. Run it

denv verify <env>
denv verify --resume <env>    # unfreeze the agent afterwards

From Python:

from denv import Client
v = Client().verify(env_id)
print(v.reward, v.source, v.refused)

What the record shows

Field Meaning
reward the number the grader produced; null if the verify failed
source reward.txt, stdout, or refused
refused paths that were not regular files or directories, with the reason: symlink, fifo, device, socket, or over the size and depth limits. Any refusal scores 0 and the grader does not run
missing declared paths that did not exist
agent_frozen whether the agent's container was left frozen for inspection

The grader's fork is destroyed at the verdict. The agent's environment is left as it was.