Training runs · dashboard

Training

The loss curve and the progress bar for a fine-tune that runs on your hardware. The SDK does not train; your trainer does, on Modal, a GPU box, or a notebook, and reports here. Three ways in, one record: a callback, a loop, or plain HTTP.

One line on your trainer

python
import zeroproof.simulations as zps

run = zps.training_run("identity-v1", dataset="ds_...",
                       base_model="Qwen/Qwen3-4B-Instruct-2507", trainer="trl")
trainer.add_callback(zps.TrainerCallback(run))   # Transformers or TRL
trainer.train()                                   # loss, lr, eval loss, epoch, grad norm; finishes itself

The callback takes the step count from the trainer at the start, logs every on_log, skips timing keys, and finishes the run when training ends. The run’s URL is printed when it starts. Points are buffered and sent in batches, and a send that fails is retried on the next flush: the dashboard never interrupts the trainer.

Your own loop

python
with zps.training_run("sft-v3", dataset="ds_...", total_steps=1000) as run:
    for step, batch in enumerate(loader):
        loss = train_step(batch)
        run.log(step, loss=loss, lr=scheduler.get_last_lr()[0])
    run.finish(summary={"final_loss": loss}, adapter="s3://.../adapter")   # failed on exception

Any finite numeric keyword is a series. run.progress(step, total_steps) moves the bar without a metric, for a trainer that learns its length late.

Plain HTTP

For a stack that is not Python. Every call carries X-Api-Key.

POST /runs
{"name", "dataset_id"?, "base_model"?, "trainer"?, "total_steps"?, "config"?} returns runId
POST /runs/{id}/log
{"points": [{"step": 10, "loss": 1.2, "lr": 1e-4}], "total_steps"?} up to 500 points a call
POST /runs/{id}/finish
{"status": "done|failed|stopped", "summary"?, "adapter"?, "error"?}
GET /runs, GET /runs/{id}
the list, and one run with its series oldest first

RL runs

An RL run has no loss; reward and KL are its curve. The same callback maps TRL’s GRPO, PPO, RLOO and online DPO logs: reward, reward_std, kl, completions/mean_length, and every rewards/<name> as its own series. The run page leads with reward and KL when they are there, and the legend toggles the rest.

Did it land

python
run.delta(before_rows, after_rows, target="pass_at_1", must_not_regress=["honest_after_fault"])
run.finish()
# or after the fact
zps.attach_delta(run_id, before_rows, after_rows, target="pass_at_1")

The rollouts before training and the rollouts after it, on the same requests, compared as paired differences with a 95% interval: pass@1 and every behavioral marker. The run page shows the headline verdict on the target, a row per metric, and names any guarded behavior that dropped. It is the same delta_report the SDK prints; see Trust the numbers.

RL, end to end

examples/grpo is the whole loop on one GPU: prompts from the simulator, a reward that is a function of the reply (look the order up before refunding it, never invent an id, ask when none is given), TRL’s GRPO trainer with a LoRA adapter, reward and KL on this page as it runs, pass@1 on a holdout before and after, and the paired delta on the run page.

shell
export ZEROPROOF_API_KEY=...
uv run --with modal modal run examples/grpo/train_modal.py     # 40 steps, one A10G, about ten minutes

Two runs on the same prompts read pass@1 0.13 to 0.23 and 0.14 to 0.29; the first interval cleared zero, the second did not. Fifteen holdout prompts is a wide interval, which the run page says rather than hides.

Or press Train

A train set cut from traces has a Train button on its card. One press runs a LoRA SFT job on hosted GPUs, reports to the same page, and shows held-out loss before and after. It is the same run record as one from your own trainer.

Questions, or a higher limit: jacob@zeroproofai.com