Skip to main content
The scripts are in the repository, not in the installed package. Clone it, then cd recipes/03-select/schema before running the commands below. Browse this recipe on GitHub.
Every row the SDK writes is a projection of four objects: Task (the situation), Rollout (one episode of one policy on it), Judgment (a scorer’s verdict), and Marker (a behavior measurement). Evals, SFT, preference pairs, GRPO prompt sets, and OPD / OPSD hints are all views over those four objects, which is why one dataset can feed all of them. These two scripts show the round trip and the projections. Both run offline with a scripted agent, so no key is needed, and both accept any JSONL the SDK ever wrote: a fresh run, a training export, a platform pull, an OTel ingest, or a file from the public Hugging Face set. What you will learn: which of the four objects each training target reads, and the two leaks the split makes impossible (model output in a shipped task file, the eval marker as the training reward). Seconds to run.

Run it

With the defaults (--rows 24, seed 0) migrate.py reports 24 rows over 12 tasks, all already version 1, and project.py writes 9 train and 3 holdout tasks into 6 eval, 3 SFT, 3 preference, 9 GRPO, 3 OPSD and 9 OPD rows. The counts are small because the scripted agent passes about half its tasks; the projections, not the counts, are the point. Both write to out/ (--out changes that). migrate.py --rows N sets how many rows the scripted run simulates; project.py --holdout 0.2 sets the holdout share and --teacher openai/gpt-oss-120b names the OPD teacher.

migrate.py

Reads any row file, reports which legacy shape each row is in (engine, training, platform_pull, otel, hf_flat, or loose when nothing matches; stamped rows are v1), and writes three things: the same rows re-stamped as schema version 1, a tasks.jsonl that holds only the situations (the shippable half: no model output in it), and a report of anything that did not validate. Rows without a stamp are version 0; nothing is rejected, and unknown columns ride through untouched. A line that is not a JSON object is counted under problems as not_a_dict and skipped.

project.py

Takes a v1 row file and writes one file per training target: Two rules the scripts enforce, because the objects make them enforceable:
  • A Task never contains a rollout, so tasks.jsonl and grpo.jsonl can be shipped without leaking any model’s behavior.
  • The eval marker is never the training reward. eval.jsonl scores with the markers; sft.jsonl and preference.jsonl select with the judgment. Same rows, different scorer, on purpose.
opsd.jsonl is the interesting one. The hint is the policy line the task exercises plus the world’s hidden state (the faults the sandbox injected), plus a passing rollout of the same task as the demonstration. The student sees the prompt. The teacher, which is the same model, sees the prompt and the hint. Their per-token divergence on the student’s own rollout is the training signal, and none of it needs a scalar reward.
Last modified on September 19, 2026