divergent/docs
printf %s "$HF_TOKEN" | div secrets set HF_TOKEN
div secrets set WANDB_API_KEY --from-env
div secrets
div secrets rm HF_TOKEN

A secret is a named value the org keeps for its runs. Every run the org places has every secret as an environment variable, so train.py reads os.environ["HF_TOKEN"] and nothing on the command line names it.

Usage

div secrets
div secrets set <name> [--from-env]
div secrets rm <name>

set

set takes the value on stdin:

printf %s "$HF_TOKEN" | div secrets set HF_TOKEN
div secrets set GCP_KEY < key.json

or, with --from-env, from this shell’s variable of the same name:

div secrets set WANDB_API_KEY --from-env

Never as an argument. An argument stays in shell history, and in ps for as long as the command runs, so div secrets set HF_TOKEN hf_… is refused. So is a terminal on stdin, because what you typed would be on screen.

One trailing newline is dropped, since that is what echo and a file’s last line add. Everything else is kept exactly as it arrived.

Setting a name that already exists replaces its value:

created HF_TOKEN. Every run placed from now on has it
replaced HF_TOKEN. Every run placed from now on has it

A name is letters, digits and underscores, and cannot start with a digit, because it becomes an environment variable. Names starting with DIVERGENT_ are ours. A value can be up to 64 KiB.

Listing

div secrets prints each name and the day it was last set. There is no way to read a value back, here or in the dashboard. We keep it sealed, and open it only to hand it to a run.

HF_TOKEN       2026-09-22
WANDB_API_KEY  2026-09-20

The name is the first column on its own, so div secrets | cut -d' ' -f1 is a list of names. --json prints the list the API returned.

rm

rm deletes a secret. Runs already placed keep what they were given. Runs placed afterwards do not get it.

In a run

A run gets the org’s secrets when it is placed, and its log says which ones:

placed with 2 secrets: HF_TOKEN, WANDB_API_KEY

The run’s own --env wins over a secret of the same name. --env values are kept with the run and shown back in the dashboard, so a credential belongs here instead.

If a run prints a secret’s value, the log shows •••• in its place. That covers values of six bytes or more. Masking anything shorter would mask every 1 in the output.

Keys

A key needs the secrets:write scope to set or delete a secret, and secrets:read to list them. Keys made by div login carry both. A key made before secrets existed does not. div says so, and div login makes one that does.

esc