# modgrad: send training metrics to a live dashboard at https://app.modgrad.com QUICKSTART (curl and python3 are enough; no account, no install) 1. Token. An anonymous project: unlisted, its token expires in 30 days. curl -sX POST https://app.modgrad.com/api/v1/projects -d '{"name": "myproj"}' -> {"project": "anon-myproj-<16 hex>", "token": "obsp_...", "board": ""} export MODGRAD_URL=https://app.modgrad.com MODGRAD_TOKEN=obsp_... "name" is optional (1-24 of a-z 0-9 -). A run id without "/" lands in the token's project: run "exp1" is stored as "anon-myproj-/exp1". 2. Send metrics. Pick one. wrap (stdlib Python; runs your command, streams every 5 s, records its exit code): curl -fsSo modgrad_pipe.py https://app.modgrad.com/pipe.py python3 modgrad_pipe.py exp1 -- python -u train.py 10-second demo (open the board URL first and watch the curve grow): python3 modgrad_pipe.py demo -- python3 -uc "import time,math;[print(f'step {s} loss {math.exp(-s/5):.4f}') or time.sleep(0.5) for s in range(20)]" pipe (any producer; no exit code): python -u train.py 2>&1 | python3 modgrad_pipe.py exp1 cli (see 5; also samples CPU/GPU, spools offline): modgrad run --name exp1 -- python train.py code (one POST per logging step, any language): curl -sX POST https://app.modgrad.com/api/v1/runs/exp1/log -H "Authorization: Bearer $MODGRAD_TOKEN" -d '{"step": 10, "loss": 0.52}' Printed lines that parse: "step 10 loss 0.52 acc 7.5%", "loss=0.52 lr=3e-4", "[epoch 2/10] train_loss: 0.45", HF Trainer dicts, tqdm postfixes. Keys: printed names are lower-cased with spaces and "-" as "_" ("Train Loss" -> train_loss); JSON keys are kept as sent, nested objects joined with "/" ({"train": {"loss": 1}} -> train/loss). "7.5%" is stored as 7.5; text values are skipped and listed under "ignored". Unbuffered Python: -u or PYTHONUNBUFFERED=1. 3. Finish, or the run shows "running" forever. wrap, pipe and cli do it; otherwise: curl -sX POST https://app.modgrad.com/api/v1/runs/exp1/finish -H "Authorization: Bearer $MODGRAD_TOKEN" -d '{"exit_code": 0}' or in the last write: {"rows": [...], "finish": true} to .../log, or .../text?finish=1. 4. Verify, then give the user the board URL from step 1. curl -s "https://app.modgrad.com/api/index?project=anon-myproj-" -> runs, last_step, finished curl -s "https://app.modgrad.com/api/v1/runs/anon-myproj-/exp1/history" (?keys=loss for one; an unknown key lists the real ones) 5. The CLI `modgrad` (optional; cli door, tail, MCP server). No prebuilt binaries yet: cargo install --locked --git https://github.com/rotkonetworks/modgrad.com modgrad-obs (Rust >= 1.89; installs `modgrad`. The server is package modgrad-obs-server.) More: https://app.modgrad.com/api/v1 (full API reference, plain text) · https://app.modgrad.com/skill.md (a Claude Code skill: add modgrad logging to any repo) · https://app.modgrad.com/docs (this page for people). Errors are JSON {"error", "example", "help"} with a corrected request.