# 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.

```bash
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](https://docs.divergentlabs.xyz/compute/cli/exit-codes.md) has the whole table.

```bash
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`](https://docs.divergentlabs.xyz/compute/cli/result.md) prints and a [check](https://docs.divergentlabs.xyz/compute/cli/run.md#checks) is judged against.

```python
json.dump({"metrics": {"accuracy": acc}}, open(os.environ["DIVERGENT_RESULT_PATH"], "w"))
```

```bash
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:

```bash
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:

```text
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:

```bash
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.

```bash
export DIVERGENT_API_KEY=dv_live_...
```

See [Configuration](https://docs.divergentlabs.xyz/compute/cli/configuration.md) for everything else that can be set this way.
