Driving div from a script
What goes to stdout, what goes to stderr, what div exits with, and which flags make it answer in JSON.
div is the surface an agent drives, so its output is split by whose it is. A shell script, a CI job and an agent can all branch on what it does without reading a word of what it says.
stdout is the run’s
The run’s own output goes to stdout and stderr exactly as the container wrote them — stdout on stdout, stderr on stderr — and nothing of ours goes in between. Everything div says itself goes to stderr.
div logs run-7 -f | grep loss
div run --gpu h100 eval.py > eval.log # eval.log is the run's output and nothing else
div storage get training-volume-1 log/training.jsonl - | tail -5
Exit codes are the run’s
A run that exits 3 makes div run exit 3. The same holds for div logs -f once the run has finished. A command typed wrong exits 2 and names the flag; the API refusing exits 1. Exit codes and errors has the whole table.
if ! div run --gpu h100 train.py::run --max-spend 20; then
echo "training failed with $?" >&2
fi
A run can answer, not just exit
An exit code says whether the run crashed. What it measured goes in its result: a JSON object written to DIVERGENT_RESULT_PATH before it exits, which div result prints and a check is judged against.
json.dump({"metrics": {"accuracy": acc}}, open(os.environ["DIVERGENT_RESULT_PATH"], "w"))
div run --json eval.py --check 'metrics.accuracy>=0.8' > run.json # exits with the run's own code
jq -e 'all(.checks[]; .verdict == "passed")' run.json > /dev/null || echo "the experiment did not pass" >&2
div result "$(jq -r .name run.json)" metrics.accuracy
The exit code says whether the run worked; the checks say whether the experiment did. They are kept apart on purpose, so a script can tell a crash from a result it did not like.
JSON when you want a structure
| Command | What --json prints |
|---|---|
div run --json |
the run as it ended, as the API sent it |
div run --detach --json |
the run as it was placed, then returns |
div logs --json |
the log lines with their sequence numbers |
div runs --json |
the runs, newest first, as the API sent them |
div stop --json |
the run as it stopped |
div catalog --json |
GET /catalog, as the API sent it |
div whoami --json |
GET /me, as the API sent it |
div limits --json |
GET /billing/summary, as the API sent it |
The CLI keeps every field it does not name, so --json prints what the API sent — including fields added after this build of div.
Placing and walking away
--detach prints the run’s name on stdout and returns as soon as the run is placed:
name=$(div run --detach --gpu h200 --gpus 8 finetune.py::lora --max-spend 400)
div logs "$name" -f
Ctrl-C does the same thing to a run you are attached to — it detaches, leaving the run going to its ceiling, and prints on the way out:
detached. run-k4t9 is still running at $4.95/h and stops at its $5.00 ceiling.
watch it again with div logs run-k4t9 -f
stop it with div stop run-k4t9
Finding and stopping what is running
div runs prints one run per line with the name first and no header, so it pipes. div stop exits 0 whether it stopped the run or the run had already finished, so a script does not have to check first:
div runs --status active # what is holding hardware now
div runs --status active | cut -d' ' -f1 | xargs -n1 div stop # stop all of it
Colour
Colour is switched off when stdout is not a terminal. When it is on it follows the product’s rule: green for a run that is running, oxblood for one that failed, mustard for a ceiling that caught up, and grey for a clean finish.
A key without a login
On a machine nobody sits at, skip div login and set the key in the environment. A key made in the dashboard under Settings works the same as one div login collected.
export DIVERGENT_API_KEY=dv_live_...
See Configuration for everything else that can be set this way.