Skip to main content
Veri’s managed methods (GRPO, SFT, DPO) own the training loop for you. When you want whole control (your own framework, your own loop), use a custom script: you bring the code, Veri provisions the GPU, runs your command, and shows you exactly what is happening (live logs, GPU utilization, checkpoints, reward curves) next to your managed jobs and deployments. Use this for OpenRLHF, slime, verl, a plain torchrun loop, or anything you can launch with a command.

How it works

You supply four things: Veri runs your entrypoint inside the base image on the GPU, with a set of VERI_* environment variables injected: Exit code 0 marks the job completed; a non-zero exit marks it failed.

When your script fails

A failed job’s error is your script’s own output: the exit status, then the last 20 lines your script wrote to stderr (up to 4 KiB). For example:
Python tracebacks already go to stderr; print your own errors there too so they land in the job’s error. Status 137 means the container was killed for running out of memory, and the error says so: try a smaller batch or a bigger GPU shape. The error shows on the job page and in veri jobs get <id>; the full output (stdout and stderr) is in veri jobs logs <id>.

Keeping the job alive

The worker that runs your script tells Veri the job is alive at least once a minute for as long as the worker runs, whether or not your script prints anything or finishes a step. A quiet script (a long data load, a step that takes an hour, a run that never logs a metric) is not failed for being quiet. That report only says your script is still running. Progress and checkpoints have to come from your script:
  • Progress: append one JSON line per step to $VERI_METRICS_FILE, for example {"step": 40, "loss": 1.21}, or call veri_sdk.log_metrics. The job’s current step and its curves come only from this file; without it the job shows no step.
  • Checkpoints: write checkpoint-<step>/ directories into $VERI_CHECKPOINT_DIR during the run (see Checkpoints). $VERI_OUTPUT_DIR is captured only when your script exits with status 0, so a run that dies midway keeps only the checkpoints it already wrote to $VERI_CHECKPOINT_DIR.
If the worker itself goes silent for more than 15 minutes (900 s), for example because the machine ran out of memory and the worker was killed, or the host went away, Veri fails the job with error.code worker_failed and terminates the instance. The error says how long the worker was silent and the last status and step it reported:
no step reported in place of the step means your script never wrote $VERI_METRICS_FILE. The job’s error.attribution is platform, and Veri reviews it for a credit.

Base images

Pick the base that matches your stack. Each prebakes the slow, compiled pieces so cold start stays fast; you layer light dependencies on top.
Custom scripts run on NVIDIA GPUs only for now: the base-image catalog is CUDA-tier. A submit with an AMD gpu_type (e.g. MI300X-192GB) returns a 400. AMD support is planned.
Custom scripts run on AWS and DigitalOcean, not on Vast: Vast runs managed methods (GRPO, SFT, DPO) only, so veri run-script --provider vast returns a 400 at submit, before any GPU is rented.

Example: a minimal training run

A small project directory:
train.py reads the Veri contract, trains, logs metrics, and writes a checkpoint:
train.py
requirements.txt layers your extra dependencies on top of the base image:
requirements.txt
Submit it with the CLI:
The CLI uploads your code, submits the job, and prints the job id and dashboard link. Keep the entrypoint in single quotes so $VERI_NUM_GPUS reaches the GPU machine instead of being expanded (to nothing) by your local shell. For more than one GPU, start with --gpu-type L4-24GB --gpu-count 4 or --gpu-type A10G-24GB --gpu-count 4 on AWS (the default provider, 96 GB across four GPUs, usually on a box within two minutes). Use --provider digitalocean --gpu-type H100-80GB --gpu-count 1 only when a single GPU must hold 80 GB: its capacity comes and goes.

Multi-node

Multi-node gangs are not enabled yet — a --num-nodes of 2 or more currently returns a “coming soon” 400 while the feature finishes hardware validation. Single-node (--num-nodes 1, the default) is unaffected.
For runs that do not fit on one box, launch a multi-node gang with --num-nodes. Veri provisions all nodes together as a single unit, wires the topology into the VERI_* env above, and runs your entrypoint on every node. Your script drives the distributed launch (torchrun, with c10d rendezvous on rank 0). Constraints:
  • Whole-box only: each node is an 8-GPU box, so set --gpu-count 8 with --gpu-type A100-80GB or --gpu-type H100-80GB. Other shapes are rejected.
  • AWS only: multi-node runs on AWS.
  • Custom script only: managed methods (GRPO, SFT, DPO) are single-node.
  • Exact node count or fail: --num-nodes must be one of 1, 2, 4, 8, 16. The gang launches at exactly that size or the submit fails fast (no silent cap-down).
Point torchrun at the injected topology. Rank 0 is the rendezvous host (VERI_HEAD_IP), every node reads its own VERI_NODE_RANK, and VERI_JOB_ID is the rendezvous id:
train.py
Your entrypoint is the torchrun launch line, consuming the injected topology directly:
Submit a 2-node H100 gang (16 GPUs total):

Checkpoints across nodes

Everything written under VERI_OUTPUT_DIR is captured, the same as single node. With N nodes you must avoid each rank writing the same path:
  • Rank 0 saves (shown above): the simplest pattern. Gate the write on rank == 0 and use a dist.barrier() so other ranks wait for the save to finish.
  • Sharded checkpoints: for large models, torch.distributed.checkpoint (DCP) writes one shard per rank under VERI_OUTPUT_DIR, so no two ranks collide and you reload the shards on resume.
Each node writes to its own VERI_OUTPUT_DIR; a shared filesystem across nodes is not provided yet.

Observability

Everything shows up in the Veri UI for the job, alongside your managed jobs and deployments:
  • Live logs: your script’s stdout and stderr stream in real time.
  • GPU metrics: utilization, memory, and power.
  • Checkpoints: whatever you write under VERI_OUTPUT_DIR.
  • Reward curves: two ways, pick either.
For reward and loss curves you have two options:
  1. veri_sdk.log_metrics (shown above): append {"step": n, "reward": ..., "loss": ...} records and Veri renders them natively. Add veri-sdk to your requirements.txt.
  2. Weights & Biases: connect your W&B account once (veri wandb set) and Veri injects WANDB_API_KEY, WANDB_PROJECT, and WANDB_RUN_ID into the container, so your framework’s existing wandb logging flows to your own W&B account with no code change (OpenRLHF, verl, slime, and TRL all support it out of the box). Veri deep-links the run from the job page. Any WANDB_* value you set yourself in env takes precedence.

Limits

  • Node counts are exact: 1, 2, 4, 8, or 16. A gang launches at the requested size or the submit fails fast (no cap-down to fewer nodes).
  • Multi-node is whole-box, AWS, custom script only: --gpu-count 8 with --gpu-type A100-80GB or H100-80GB on AWS. Managed methods (GRPO, SFT, DPO) are single-node.
  • No shared filesystem across nodes yet: each node writes to its own VERI_OUTPUT_DIR. Have rank 0 save, or shard with torch.distributed.checkpoint.
  • Four base images (above). If your stack does not fit, a bring-your-own container image is the escape hatch (coming soon).