Skip to main content
Every prime-rl entrypoint uses pydantic-config: TOML files for reproducible base configs, CLI flags for one-off overrides.
AI agents working in this repo: the equivalent runbook is at skills/configs/SKILL.md, with extra runtime hints (where config classes live, validator conventions, the trainer-side enable_token_export flag) that aren’t surfaced here.

Table of Contents

Sources and Precedence

Field values come from three sources — Pydantic defaults, TOML files (passed with @), and CLI flags. They’re layered in this order, with later sources winning:
  1. Defaults declared on the Pydantic model.
  2. TOML files passed with @, left to right — later files override earlier ones.
  3. CLI flags in dotted, kebab-case form (--model.name).

TOML Composition

The @ token introduces a TOML file. Multiple @ arguments compose left-to-right, deep-merged — unset fields in an overlay keep the base value:
Mind the space: @ path/to/x.toml, not @path/to/x.toml.

CLI Overrides

CLI flags mirror the TOML tree using dots:
Field names are snake_case in TOML (max_model_len) and kebab-case on the CLI (--max-model-len).
Renamed fields keep their old name as a validation alias — e.g. rollouts_per_example is still accepted in TOML and CLI after being renamed to group_size. Mixing the two names across sources is safe.

Inspecting and Validating

Syntax

Booleans

CLI uses paired flags: bare --flag sets True, --no-flag sets False. TOML must be explicit:

Lists

CLI accepts space-separated values or a JSON literal. TOML uses an array literal. Both forms target the same field:
Overlay TOMLs replace lists wholesale — an overlay that wants to add one item must still spell out the full list. For arrays of tables (e.g. environments), see Environments.

Dicts

CLI takes a JSON literal. TOML uses a table or inline-table. CLI dicts deep-merge with TOML dicts — CLI keys win on conflict but don’t wipe the file’s keys:

Optional Sub-Configs

Many sub-configs are typed SomeConfig | None. Two patterns enable them:
  • Bare flag with defaults: --model.compile or, in TOML, an empty section [model.compile]. The sub-config materializes with all-default values.
  • Enable and set fields together: --model.compile.fullgraph (CLI) or any populated [model.compile] table (TOML).
To disable a sub-config that’s on by default, use --no-<name> on the CLI or assign the string "None" in TOML (see None). This is how [ckpt], [model.lora], [model.compile], [trainer.wandb], etc. are turned on and off.

None

TOML has no null. Use the string "None", which the loader coerces:
On the CLI: --inference.model.max-model-len None.

Discriminated Unions

Loss, advantage, optimizer, scheduler, weight broadcast transport, and several others are discriminated unions. Set the type field to pick a variant:
Omit type to keep the default variant.

Environments ([[orchestrator.train.env]])

Training environments are an array of tables — set one per env, optionally with sampling weights:
ratio defaults to 1 (equal weight per env); values are relative weights normalized to probabilities across envs. Everything environment lives under the env block (verifiers’ [env] shape): env.taskset configures the v1 taskset, and each agent is a field on the env — env.agent.harness selects how the single-agent env’s tasks are run, and per-run caps are per-agent (env.agent.max_turns, env.agent.timeout, env.agent.max_output_tokens). A multi-agent env declares its own seats (env.<role>.*). The same taskset can appear multiple times across train and eval (or with different settings) — useful for evaluating on a held-out split or comparing two configurations side by side. When it is reused, set a distinct name on each entry; name defaults to the taskset id and must be unique across all envs in the same group.

Environment Variables

OS environment variables exported into launched component process(es). In rl configs, top-level [env_vars] applies to trainer, inference, and orchestrator:
Component-specific tables layer on top:
The rl launcher applies these the same way in both single-node and multi-node (SLURM) runs. Precedence, low to high:
  1. The launcher’s own defaults — your env_vars override these.
  2. Your top-level [env_vars].
  3. Your [component.env_vars].
  4. Orchestration-critical vars the launcher always sets last — CUDA_VISIBLE_DEVICES (GPU partitioning) and WANDB_SHARED_* (the single shared W&B run) — these cannot be overridden from env_vars.
For standalone sft and inference configs, [env_vars] applies to that entrypoint’s process(es). For disaggregated P/D inference, the role-specific deployment.{prefill,decode}_env_vars layer on top of any shared inference env vars.

Examples

The shipped end-to-end examples in examples/ are the canonical, kept-up-to-date references — the rest of the repo’s TOMLs (under configs/) are CI- and debug-internal and may drift. Each basic example directory has its own README with the full launch story; the advanced examples are config-only. Basic (1–8 GPUs):
  • Reverse TextQwen3-0.6B reversing a chunk of text. Tiny single-turn SFT + RL; runs on a single consumer GPU in minutes.
  • WordleQwen3-1.7B playing Wordle. Multi-turn SFT + RL; 2–4 H100s.
  • Alphabet SortQwen3-4B-Instruct-2507 sorting names alphabetically. Multi-turn LoRA RL without SFT warmup; one H100.
  • Wiki SearchQwen3-4B-Instruct-2507 answering trivia by searching a Wikipedia corpus. Multi-turn with tool use.
  • Hendrycks SanityDeepSeek-R1-Distill-Qwen-1.5B on a filtered MATH subset. Useful for algorithm ablations.
Advanced (32–2048 GPUs, SLURM):

Worked Example: Compose, Override, Dry-Run

Start from a shipped base config, override two fields on the CLI, and dry-run:
Then inspect the resolved config:
Each per-process TOML reflects the final, validated configuration that the actual run would consume — exactly what each process sees when started standalone (uv run trainer @ /tmp/reverse-dry/configs/trainer.toml, etc.). This is the easiest way to bisect a misbehaving config: dry-run a known-good base, dry-run your overlay, diff the two.