Quick start
Every command below was executed on a checkout of this repository (Ster 0.13.0, macOS arm64, CPU). The walkthrough uses a tiny offline toy checkpoint so it needs no download, no GPU, and no Hugging Face account. The toy model's weights are
Start from an existing pair set#
If you already have Ster contrastive data, import it instead of creating demonstration rows. The file must be the canonical pair-set JSON documented below; import performs the complete loader validation before it changes the workspace.
ster workspace import-pairs ./my-pairs.json
ster workspace show
ster train --model <MODEL> --output direction.ster.jsonThe third command omits --pairs and uses the active accepted import. You can also do the first step from first use with ster onboarding --import-pairs ./my-pairs.json. Skipping import leaves an empty, usable workspace.
Overview#
Every command below was executed on a checkout of this repository (Ster 0.13.0, macOS arm64, CPU). The walkthrough uses a tiny offline toy checkpoint so it needs no download, no GPU, and no Hugging Face account. The toy model's weights are seeded random numbers — its text is deterministic gibberish, and that is the point: the mechanics (reading, training, gating, steering) are identical to a real model's, just instant. To do the same on a real model, substitute --model meta-llama/Llama-3.2-1B (or any local Safetensors directory of a supported family) everywhere toy-llama appears.
1. Install#
From this checkout:
cargo install --path . --lockedOr from GitHub: cargo install --git https://github.com/wisent-ai/ster --locked. Add --features metal or --features cuda for GPU backends — they are compile-time choices, not flags (configuration).
$ ster --version
ster 0.13.02. Make an offline toy model#
WORK=$(mktemp -d)
cd "$WORK"
python3 <ster-repo>/docs/examples/make-toy-model.py toy-llamaThis writes config.json (model_type: "llama", 4 layers, hidden width 64), a WordLevel tokenizer.json, and model.safetensors — the exact three inputs model resolution requires from a local directory.
3. Define the trait as contrast#
A trait is a contrastive pair set: matched prompts that differ only in the trait. Save as pairs.json (this corpus trains a toy "calm vs stormy" trait; the toy tokenizer only knows its own ~60 words, so pairs stick to that vocabulary):
{
"trait_name": "calm",
"pairs": [
{
"positive": "the sea is calm and quiet tonight .",
"negative": "the storm waves crash loud against the rocks ."
},
{
"positive": "the water lies still in the harbor .",
"negative": "the wind howls hard over the dark hills ."
}
]
}The full executed set has 8 pairs and is checked in as `examples/pairs.json` — enough for ster vector optimize to hold out pairs on both sides of its split.
4. Train#
$ ster vector train --model toy-llama --pairs pairs.json --layers 1..3 --method caa --output calm.ster.json
this model publishes no chat template, so prompts and completions are encoded as raw text
reading pair 1/8
...
reading pair 8/8
{
"artifact": {
"chat_template": "absent",
"hidden_size": 64,
"layers": [
{
"layer": 1,
"norm": 1.0000000062843015,
"train_accuracy": 0.875,
"train_margin": 0.5598376393318176,
"width": 64
},
{
"layer": 2,
"norm": 1.0000000878582571,
"train_accuracy": 0.875,
"train_margin": 0.7613550424575806,
"width": 64
}
],
"metadata": {},
"method": "caa",
"model": "toy-llama",
"model_revision": null,
"precision": "f32",
"product": "ster",
"schema_version": 1,
"trait_name": "calm"
},
"chat_template": "absent"
}Progress goes to stderr; the summary JSON goes to stdout; the full steering artifact (including the vectors) is in calm.ster.json. --layers 1..3 is a half-open range: layers 1 and 2 (layer selection). The first stderr line is what --chat-template auto decided: this toy publishes no template, so the pairs were read as raw text, and the artifact records that as absent so a later evaluate can tell (chat template).
5. Evaluate#
$ ster vector evaluate --model toy-llama --pairs pairs.json --vector calm.ster.json
{
"chat_template": "absent",
"layers": [
{ "layer": 1, "accuracy": 0.875, "margin": 0.5598376393318176 },
{ "layer": 2, "accuracy": 0.875, "margin": 0.7613550424575806 }
],
"method": "caa",
"model": "toy-llama",
"pair_count": 8,
"trait_name": "calm"
}Accuracy is the fraction of pairs whose positive prompt projects higher onto the direction than its negative; margin is the mean projection gap (evaluation). Evaluate on held-out pairs, not the training set, when the number matters. --chat-template and --precision should also match the run that trained the artifact: the artifact records both, so a mismatch is warned about on stderr rather than left to be noticed.
6. Generate — baseline, then steered#
$ ster generate --model toy-llama --prompt "describe the evening lake ." \
--max-new-tokens 12 --temperature 0 --seed 42
loud sea hard hard , white , white , white loud loud
$ ster generate --model toy-llama --vector calm.ster.json --strength 1.0 \
--prompt "describe the evening lake ." --max-new-tokens 12 --temperature 0 --seed 42
white white white howls howls howls drifts , white white white whiteThese two runs were recorded when temperature 0 and seed 42 were the defaults; Ster now has no default for either, so the commands state the values the recorded runs used. At temperature 0 decoding is argmax and the seed does not change the text.
Same prompt, same seed — the added direction visibly changes the token distribution (on a real model, it changes the trait; on this toy it changes gibberish). Strength is linear and signed; pass negative values as --strength=-2.0 (with =, or the CLI parses -2.0 as a flag). Large strengths dominate the stream entirely — at --strength 2.0 the toy model emits one token forever, and past that it can hit end-of-sequence immediately and return an empty line. Calibrate: intervention.
7. Where to go next#
- The full command surface, argument by argument: cli.
- Method-and-layer selection with
ster vector optimize, artifact gating, and activation export, all executed: walkthrough-steering. - The same engine for desktop apps, one process per operation: desktop request reference.
- Every refusal sentence you might hit on the way: runbook.