SWE-Lego-RL

Agent Plugin

Validate, launch, and diagnose runs through a coding agent — or fall back to the same commands by hand

SWE-Lego-RL's operator-facing surface is an agent plugin: a set of control skills for Claude Code, shipped in this repo at .claude/plugins/rl-plugin/ and exposed as /rl:* slash commands. The technical report describes this layer as the operations pillar — an RL run is treated as a composition of reusable blocks, and the plugin drives the validate → launch → diagnose cycle over them.

Launch model

Every workload follows the same two-phase model, whichever path you take:

  1. Form a config. Copy a template (from scripts/train/templates/, scripts/eval/templates/, or scripts/infer/templates/) into the matching configs/ directory and fill in the CHANGEME lines. The config is the single source of truth for the run.
  2. Run it — either through the agent (/rl:run <config>), which validates first and asks for explicit confirmation, or by hand (bash scripts/train/train.sh <config>, same for eval/infer), which runs the same validation inline.
# once: form the config
cp scripts/train/templates/sync_k8s_ohsdk_qwen35a3b.env \
   scripts/train/configs/my_run.env
$EDITOR scripts/train/configs/my_run.env        # fill the CHANGEME lines
# then, in Claude Code opened from the repo root:
/rl:check train/configs/my_run.env      # safe to launch right now?
/rl:run   train/configs/my_run.env      # validate → confirm → background launch
/rl:status                              # is the live run healthy?
/rl:dashboard                           # serve the training board

The skills are not a second implementation: they shell out to the same runners and the same scripts/lib/preflight.sh a manual launch uses, adding the judgement a config-only script cannot provide — a run already in flight, foreign GPUs, a taken port — and one structured report instead of scrollback.

ManualThrough the agent
ValidatePREFLIGHT_ONLY=1 bash scripts/train/train.sh <config>/rl:check <config>
Launchbash scripts/train/train.sh <config>/rl:run <config>
Watchtail -F logs/<exp>.log/rl:status
Serve the dashboardbash webui/start_dashboard.sh/rl:dashboard

Run validation

The report names this stage run validation and divides it into four blocks under a strict division of labor — deterministic checks belong to scripts, judgement belongs to an operator (human or agent):

BlockWhat it doesImplemented by
ConfigurationThe resolved configuration is stated in full before anything starts — model, scaffold, parallelism, context budgets, sandbox and data settings — so what will be launched is stated rather than re-guessedthe runner's config summary
Constraint checkingCross-parameter rules distilled from real incidents fail fast on confirmed misconfiguration and warn on suspicious settingsscripts/lib/preflight.sh — see Preflight
Resource inspectionA read-only report of live facts about the machine: colliding runs, GPU and port occupancy, disk and shared-memory headroomscripts/lib/live_probe.sh
ConfirmationThese facts become a launch or a refusalyou — or /rl:run's explicit yes/no gate

Skills

/rl:check

Answers "is it safe to launch right now?" — read-only, two layers, one verdict:

SAFE TO RUN: ✅ YES — 0 blockers · 2 warnings

| Layer | Check     | Status | Detail                               |
|-------|-----------|:------:|--------------------------------------|
| det   | preflight |   ✓    | ok=23  warn=2  fatal=0               |
| live  | job       |   ✓    | job:none                             |
| live  | gpu       |   ✓    | gpu:idle — 8× free                   |
| live  | port      |   ✓    | 6379 / 8265 free                     |
| live  | imports   |   ✓    | verl / veomni import OK              |
  1. DeterministicPREFLIGHT_ONLY=1 through the runner itself, so every assertion is the same one a manual launch would hit: tool_parser × model × scaffold, topology, device mesh, VRAM, veomni constraints, R3 × engine × verl, image source, lr_scheduler, path existence.
  2. Livescripts/lib/live_probe.sh prints local facts and the skill judges ownership: is a trainer already running, is that 130 GB of GPU memory yours or a foreign vLLM, is the port this run needs taken, do veomni / verl import.

You get a SAFE TO RUN: ✅ YES / ❌ NO line, a status table, the resolved run parameters verbatim, and numbered next steps. Exactly five things block a launch — a ✗ FATAL, a run already in flight, foreign GPUs, a port conflict, a missing import. Warnings never flip the verdict.

Shared machines

On a shared machine the common blocker is not a bad config but someone else's vLLM holding all 8 GPUs. /rl:check walks the process parent chain to decide whether those processes belong to your run tree, and reports the PID and memory so the owner can be identified.

/rl:run

Runs /rl:check first and refuses on any blocking failure; there is no force flag. On a pass it prints the resolved run configuration, highlights the fields that determine whether the GPU hours are well spent (data indexes, scale, resume behavior, naming), and requires a confirmation before launching.

Launch defaults to the background (nohup setsid): these runs last hours, and a foreground launch would hold the session. It then reports the real exp_name — the runner derives it at launch time, so it differs from the name preflight printed — plus the PIDs, the log paths, and the first-step gates to check (pearson ≈ 0.999, lr non-zero, reward and num_turns non-zero).

For a multi-node train or infer run it prints the per-node command to run on each node. It never SSHes anywhere.

/rl:status

Read-only diagnosis of a run in flight: which run is alive, how far it has got, and whether its numbers are sound. It reads the process table, the step lines in the run log and the trials directory, then matches the metrics against the failure signatures this stack keeps producing:

SignatureEvidence it looks for
R3 misalignmentrollout_actor_probs_pearson_corr below 0.99
Frozen modelactor/lr is 0
Gradient starvationactor/grad_norm an order below this run's own earlier steps
Env avalanchetrajectory_filter/reason/env_setup_failed climbing across steps
Val fake-zeroval metrics all 0 while train reward is healthy
No-tool-call collapsenum_turns/mean falling toward 1 as reward falls
Deadlockprocess alive, log mtime old, no new step line

It only claims a signature when that specific evidence is present — otherwise it says so, rather than forcing a match and sending you after the wrong layer.

/rl:dashboard

Brings up webui/ here, adapting to this machine rather than assuming the paths in this repo: it ranks candidate log directories by how many runs they actually hold, picks a free port, rebuilds dist/ only when it is stale, and leaves any instance it did not start alone. A public tunnel is opt-in. See Dashboard.

The skills never mutate a run

/rl:check and /rl:status change nothing at all, and /rl:run only ever launches — after you say yes. None of them kill a process, edit a config, clear /dev/shm, delete a log, or touch the cluster. When something needs stopping they give you the PID and let you decide.

Other workloads

The same contract covers all three workload kinds — the plugin validates and launches eval and infer configs exactly as it does training:

GoalRunnerGuide
Train a policyscripts/train/train.shGetting Started
Score a checkpoint on a held-out setscripts/eval/eval.shEvaluation
Batch-generate trajectories over an indexscripts/infer/infer.shBatch Inference

On this page