Train
Start a training run on the dataset. This quickstart trains one run so it
finishes quickly on the docs pipeline. For your own data, the default way to
train is a training study: POST /training-studies
with the dataset_id trains a fixed grid of eight runs, picks the winner on
validation data only, and evaluates that winner once. A single run, as below,
is the POST /runs path. Normally it is a one-liner — pick a tier and go:
curl -X POST "$TESSERA_API_BASE/runs" -H "Authorization: Bearer $TESSERA_API_KEY" \
-d '{"dataset_id": "'$DATASET_ID'", "model_config_tier": "S"}'
The executable sample below adds overrides and trainer settings from
ci-train-profile.json — the documented CI profile that shrinks tier S
(d_model 32, one encoder layer each) and bounds the run to ≤ 50 optimizer
steps so the docs pipeline genuinely trains this model on a CPU runner
for every change. Drop both keys for a real run; everything else is
identical. One visible consequence: the served embedding dimension equals
d_model — 32 under this profile, 256 for stock tier S.
- curl
- Python SDK (planned)
#!/usr/bin/env bash
# Quickstart step 6 — start a training run and follow it to an evaluated model.
#
# The normal invocation is just:
# POST /runs {"dataset_id": "...", "model_config_tier": "S"}
# This executable copy layers on ci-train-profile.json — the documented CI
# override profile (reduced dims, <= 50 steps, CPU) — so the docs pipeline
# really trains this model on every change.
set -euo pipefail
: "${TESSERA_API_BASE:?e.g. https://api.staging.tessera.zone/v1}"
: "${TESSERA_API_KEY:?your tsk_test_… key}"
: "${TESSERA_STATE_DIR:=.}"
AUTH=(-H "Authorization: Bearer $TESSERA_API_KEY")
DATASET_ID="$(cat "$TESSERA_STATE_DIR/dataset_id")"
BODY="$(python3 -c '
import json, sys
profile = json.load(open("ci-train-profile.json"))
profile.pop("_comment", None)
profile["dataset_id"] = sys.argv[1]
print(json.dumps(profile))
' "$DATASET_ID")"
RUN="$(curl -sS -X POST "$TESSERA_API_BASE/runs" "${AUTH[@]}" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: quickstart-train" \
-d "$BODY")"
RUN_ID="$(printf '%s' "$RUN" | python3 -c 'import json,sys; print(json.load(sys.stdin)["run_id"])')"
echo "run $RUN_ID started"
for _ in $(seq 1 600); do
RUN="$(curl -sS "$TESSERA_API_BASE/runs/$RUN_ID" "${AUTH[@]}")"
STATUS="$(printf '%s' "$RUN" | python3 -c 'import json,sys; print(json.load(sys.stdin)["status"])')"
case "$STATUS" in succeeded|failed|cancelled) break ;; esac
sleep 2
done
printf '%s' "$RUN" | python3 -c '
import json, sys
run = json.load(sys.stdin)
print(json.dumps({k: run.get(k) for k in ("run_id", "status", "total_steps", "model_id")}, indent=2))
'
MODEL_ID="$(printf '%s' "$RUN" | python3 -c 'import json,sys; print(json.load(sys.stdin)["model_id"])')"
# Evaluation runs automatically after training: the model version moves to
# `evaluated` once the six promotion gates (G1-G6) have been computed.
for _ in $(seq 1 600); do
MODEL="$(curl -sS "$TESSERA_API_BASE/models/$MODEL_ID" "${AUTH[@]}")"
MODEL_STATUS="$(printf '%s' "$MODEL" | python3 -c 'import json,sys; print(json.load(sys.stdin)["status"])')"
case "$MODEL_STATUS" in evaluated|promoted|archived) break ;; esac
sleep 2
done
echo "model $MODEL_ID: $MODEL_STATUS"
curl -sS "$TESSERA_API_BASE/models/$MODEL_ID/eval-report" "${AUTH[@]}" | python3 -c '
import json, sys
report = json.load(sys.stdin)
for gate in sorted(report["gates"]):
print("gate %s: %s" % (gate, report["gates"][gate]["status"]))
'
printf '%s' "$MODEL_ID" > "$TESSERA_STATE_DIR/model_id"
Download quickstart/06-train.sh — this exact file runs in CI on every change (hosts shown are for this environment).
"""Quickstart step 6 (planned Python SDK) — train and follow the run to evaluation.
The normal invocation is one line:
client.api.create_run(models.TrainingRunRequest(dataset_id=..., model_config_tier="S"))
This executable copy layers on ci-train-profile.json — the documented CI
override profile (reduced dims, <= 50 steps, CPU) — so the docs pipeline
really trains this model on every change.
"""
import json
import os
import time
from pathlib import Path
from tessera import Tessera
from tessera._generated import models
client = Tessera(base_url=os.environ["TESSERA_API_BASE"])
state_dir = Path(os.environ.get("TESSERA_STATE_DIR", "."))
dataset_id = (state_dir / "dataset_id").read_text().strip()
profile = json.loads(Path("../quickstart/ci-train-profile.json").read_text())
profile.pop("_comment", None)
run = client.api.create_run(models.TrainingRunRequest(dataset_id=dataset_id, **profile))
print(f"run started: tier={profile['model_config_tier']}")
for _ in range(600):
run = client.api.get_run(run.run_id)
if run.status.value in ("succeeded", "failed", "cancelled"):
break
time.sleep(2)
print(f"run: {run.status.value} total_steps={run.total_steps}")
model_id = str(run.model_id)
for _ in range(600):
model = client.api.get_model(model_id)
if model.status.value in ("evaluated", "promoted", "archived"):
break
time.sleep(2)
print(f"model: {model.status.value}")
report = client.api.get_model_eval_report(model_id)
for gate in sorted(report.gates.keys()):
print(f"gate {gate}: {report.gates[gate]['status']}")
(state_dir / "model_id").write_text(model_id)
client.close()
Download quickstart-sdk/06-train.py — this exact file runs in CI on every change (hosts shown are for this environment).
The full CI profile
{
"_comment": "The documented quickstart training profile: tier S with reduced dims and a token budget that keeps total_steps <= 50 so the quickstart really trains, end to end, on a CPU runner. Ten epochs and a 24,000-token global batch put both deterministic quickstart datasets on the intended 50-step horizon using their exact persisted train-token totals. Production runs simply omit `overrides` and `trainer`. The served embedding dimension equals d_model (32 here; 256 for stock tier S).",
"model_config_tier": "S",
"overrides": {
"d_token": 16,
"d_model": 32,
"d_embed": 8,
"event_layers": 1,
"event_heads": 2,
"seq_layers": 1,
"seq_heads": 2,
"B_attr": 1024,
"B_val": 4096,
"B_etype": 128,
"num_negatives": 32,
"max_sampled_tokens": 8
},
"trainer": {
"epochs": 10,
"global_batch_tokens": 24000,
"max_tokens_per_microbatch": 16384,
"checkpoint_every_steps": 20,
"val_every_steps": 10,
"compile": false,
"learning_rate": 0.025
},
"seed": 0
}
Download quickstart/ci-train-profile.json — this exact file runs in CI on every change (hosts shown are for this environment).
While it runs, GET /runs/{id}/metrics streams loss curves and throughput
(?after_step= for incremental polling). The run ends as a model
version, and evaluation follows automatically: six promotion gates
computed on the test split — label quality against a trivial baseline,
calibration, count-invariance of the embeddings, tokenizer parity between
the training and serving paths, an independent recomputation of every
supervision mask, and a drift baseline for production monitors. The next
step reads the server-resolved promotion verdict. G1-G3 quality failures are
advisory by default and require an explicit, audited acknowledgement; G4-G6
integrity failures — including leakage — always block. This quickstart's
fixture passes without an acknowledgement. See
Promotion gates for policy and remediation details.
Next: activate and score.