Ster/Docs

CLI reference

Ster's commands, including durable pair-set import, onboarding replay, and workspace inspection.

Overview#

The ster binary exposes model workflows, pair authoring, tuning, onboarding, and a durable local pair-set workspace. Imported data is optional: without an active import, commands that consume pairs still require --pairs.

text
Usage: ster <COMMAND>

Commands:
  vector      Train, select, score, read, and compare steering vectors: the directions every steered run adds to the residual stream
  generate    Generate text with an optional steering artifact
  extract     Export hidden representations for arbitrary prompts
  onboarding  Import existing contrastive data during first use, or replay the walkthrough
  decide      Answer typed questions about a state from one forward pass, with a probability for every option
  calibrate   Fit the temperature that makes decision probabilities honest, from labelled examples
  decisions   Get, split, and benchmark labelled decisions: the pipeline around a decision model
  workspace   Import and inspect Ster's persistent local workspace
  pairs       Author, inspect, and synthesize contrastive pair sets
  tune        Train, merge, score, and inspect LoRA adapters
  request     Run one JSON request from a desktop app to completion: the body on stdin, NDJSON log events and one result event on stdout, and the result's status as the exit status
  help        Print this message or the help of the given subcommand(s)

Every public command has its own reference page:

Conventions that hold everywhere:

  • Exit code is 0 on success, non-zero on any refusal; the refusal is one Error: <sentence> on stderr (runbook lists them all).
  • stdout carries exactly the command's result document (JSON for every vector subcommand, decide, calibrate, every pairs, decisions, tune and workspace subcommand; generated text for generate; the output path for extract and toy-model; NDJSON events for request). Progress lines (reading pair 3/8, extracting prompt 1/2, synthesizing pair 3/20 (attempt 7)) go to stderr, as does the one line every model-loading command prints about what it decided to do with the chat template.
  • `--text`, a global flag accepted before or after any subcommand, prints the same answer as one path: value line per leaf field for a person — nested keys joined with dots, list items indexed (report.layers[0].accuracy: 0.875), an empty list as [], a null as - — instead of the JSON document; the data is the same, and a file a command also writes is written as JSON either way. generate, extract, toy-model and request already print for the reader they have and take no other form.
  • Negative numeric values must be attached with = (--strength=-2.0); clap otherwise reads -2.0 as a flag and exits 2 with error: unexpected argument '-2' found.

Shared model arguments#

vector train, vector optimize, vector evaluate, generate, extract, and pairs synthesize all load a model first, with the same three arguments (ModelArgs):

ArgumentDefaultMeaning
--model <MODEL>requiredHugging Face model id, or a local directory containing config.json, tokenizer.json, and Safetensors weights. A path that exists as a directory is used in place; anything else is treated as a Hub id and fetched.
--revision <REVISION>main (Hub) / none (local)Immutable Hub revision (branch, tag, or commit SHA). For Hub models the resolved commit SHA is recorded in artifacts regardless; for local directories the value is recorded verbatim if given.
--device <DEVICE>cpucpu, metal, or cuda. The GPU values only work in binaries built with the matching feature; otherwise: this Ster binary was built without the metal feature.

Loading refuses any checkpoint whose config.json is not model_type: "llama" — see model resolution.

--precision <f32|f16|bf16> joins them on every command that maps a checkpoint — vector train, vector optimize, vector evaluate, generate, extract, pairs synthesize, and the five ster tune subcommands that load a model. It defaults to f32 and names the frozen base weights only; bf16 is refused on cpu at load, before a weight is mapped, because Candle's CPU matmul has no bf16 kernel (precision). tune merge and tune inspect take none: neither builds a decoder.

--chat-template <auto|off> joins them on every command that turns prose into tokens — vector train, vector optimize, vector evaluate, generate, extract, pairs synthesize, and the five ster tune subcommands that load a model. It defaults to auto, which applies the checkpoint's own conversation format when it publishes one and encodes raw text when it does not; off encodes raw text always. There is no on, because a checkpoint that publishes no template cannot be forced into one. Each run says which of the two it did, in one sentence on stderr, and records the word in whatever it writes (chat template). pairs synthesize --generator brama accepts the flag and ignores it: the gateway is already a chat API. tune merge and tune inspect take none, for the same reason they take no precision.

ster vector train#

text
Usage: ster vector train [OPTIONS] --model <MODEL> --output <OUTPUT>

      --pairs <PAIRS>                  JSON file with trait_name and contrastive pairs
      --output <OUTPUT>                Output Ster steering artifact
      --layers <LAYERS>                Comma-separated layers, half-open ranges such as 8..16, or all [default: all]
      --method <METHOD>                Direction training method: caa, pca, or logistic [default: caa]
      --chat-template <CHAT_TEMPLATE>  [default: auto]

Captures both activations per pair per selected layer, trains one unit-normalized direction per layer with --method, self-scores each on the training pairs, and writes one steering artifact containing all selected layers. Stdout is a summary (widths, norms and scores, no vector values); the inner chat_template is what the artifact records, the outer one is what this run encoded in:

json
{ "artifact": { "chat_template": "absent", "hidden_size": 64,
  "layers": [ { "layer": 1, "norm": 1.0000000062843015, "width": 64,
    "train_accuracy": 0.875, "train_margin": 0.5598376393318176 } ],
  "metadata": {}, "method": "caa", "model": "toy-llama",
  "model_revision": null, "precision": "f32", "product": "ster",
  "schema_version": 1, "trait_name": "calm" },
  "chat_template": "absent" }

--method takes caa, pca or logistic. Layer grammar: layer selection.

The toy checkpoint publishes no template, which is why auto reports absent here rather than applied.

ster vector optimize#

text
Usage: ster vector optimize [OPTIONS] --model <MODEL> --output <OUTPUT> --holdout <HOLDOUT>

      --pairs <PAIRS>                
      --output <OUTPUT>              
      --layers <LAYERS>                [default: all]
      --chat-template <CHAT_TEMPLATE>  [default: auto]
      --holdout <HOLDOUT>              Fraction of the pairs held out to rank candidates on, above zero and below one; Ster assumes none

Grid search over all three methods × every selected layer. The last --holdout fraction of the pairs in file order, rounded to whole pairs, is held out; each candidate trains on the rest and is scored on the holdout; the winner is the highest holdout accuracy, ties broken by margin. The winning (method, layer) is then retrained on all pairs and written as a single-layer artifact whose metadata.selection names the search — chosen over 12 candidates on a 2-pair holdout, then refitted on all 8 pairs on the eight-pair toy set over all four layers at --holdout 0.2. A fraction that leaves either side without a pair is refused (a held-out fraction of <F> over <N> contrastive pairs leaves <FIT> pairs to fit and <HELD> to rank on; both need at least one). Stdout is the same summary shape as train, plus a selection object carrying holdout (fraction, fit_pairs, holdout_pairs) and one candidates row per layer and method with its holdout_accuracy, holdout_margin, and a selected flag true on exactly one row (`ster vector optimize`).

Stderr adds fitting each candidate on 6 pairs and ranking on a 2-pair holdout, and, when the split leaves one pair, a one-pair holdout scores every candidate 0 or 1, so this ranking separates almost nothing; add pairs to make the choice mean something.

ster vector evaluate#

text
Usage: ster vector evaluate [OPTIONS] --model <MODEL> --vector <VECTOR>

      --pairs <PAIRS>                
      --vector <VECTOR>              
      --chat-template <CHAT_TEMPLATE>  [default: auto]

Loads an existing artifact, re-captures activations for --pairs at exactly the artifact's layers, and reports per-layer pair-ordering accuracy and mean margin (evaluation). Refuses an artifact whose model string differs from --model (artifact model "toy-llama" does not match runtime model "toy-llama-copy"). It does not refuse an artifact fitted in a different space; it warns, on stderr, before the first pair is read — warning: this direction was trained with chat template absent and this run encodes off, so the number below describes a format it was not trained in. chat_template in the report is what this run encoded in. Stdout:

json
{ "model": "toy-llama", "trait_name": "calm", "method": "caa",
  "pair_count": 8, "chat_template": "off",
  "layers": [ { "layer": 2, "accuracy": 0.875,
  "margin": 0.7613550424575806 } ] }

ster generate#

text
Usage: ster generate [OPTIONS] --model <MODEL> --prompt <PROMPT> --max-new-tokens <MAX_NEW_TOKENS> --temperature <TEMPERATURE> --seed <SEED>

      --prompt <PROMPT>
      --vector <VECTOR>                  Steering artifact to add during generation; repeat it to steer several traits at once, each with the --strength in the same place
      --adapter <ADAPTER>
      --chat-template <CHAT_TEMPLATE>    [default: auto]
      --strength <STRENGTH>              Scale on the --vector in the same place; one per --vector, which it belongs to, and Ster assumes none
      --max-new-tokens <MAX_NEW_TOKENS>
      --temperature <TEMPERATURE>        Zero selects deterministic argmax generation
      --top-p <TOP_P>                    Nucleus mass; omitted samples from the whole distribution
      --seed <SEED>

Autoregressive generation with a KV cache; stdout is the generated text only (prompt excluded, special tokens skipped). Without --vector it is a plain baseline. With one or more, every artifact is gated (schema, product, model string, hidden width, layer range, finiteness) and then applied as an intervention: at each layer any of them carries, the sum of every vector times its strength is added to the residual stream, every step — several traits steered at once.

Sampling: --temperature 0 is deterministic argmax and ignores --top-p and --seed; a positive temperature samples the full distribution, or the top-p nucleus when --top-p is set. --max-new-tokens, --temperature and --seed are required, and every --vector needs its own --strength: Ster assumes none, and leaving one out is refused naming it. Generation stops at --max-new-tokens, at any of the model's EOS token ids, or at the model's context limit, whichever comes first — an immediate EOS yields an empty stdout line. Prompts must be non-empty and shorter than the model's max_position_embeddings.

--chat-template decides what the model is actually handed. It defaults to auto, which renders the prompt as a user turn followed by the marker that opens the assistant's, when the checkpoint publishes a template, and sends raw text when it does not; off sends raw text always. An instruct checkpoint handed a bare question continues the text instead of answering it, which is the whole reason the default is auto (chat template).

ster extract#

text
Usage: ster extract [OPTIONS] --model <MODEL> --input <INPUT> --output <OUTPUT>

      --input <INPUT>                  JSON file shaped as {"prompts": ["..."]}
      --output <OUTPUT>              
      --layers <LAYERS>                [default: all]
      --chat-template <CHAT_TEMPLATE>  [default: auto]

Exports final-token activations for every prompt at every selected layer into one JSON activation artifact (schema_version 1, product "ster", model identity, hidden_size, then one record per prompt with a layers map). Stdout is the output path; progress (extracting prompt 1/2) is on stderr.

--chat-template decides what the model was reading when it reached the states being exported: a user turn it is about to answer under auto, or a document it is continuing under off. The activation artifact records the model identity and hidden width but not that decision, so an export whose encoding matters should be kept with the command that produced it.

ster vector inspect#

text
Usage: ster vector inspect <ARTIFACT>

Loads a steering artifact through the same validation used everywhere else, then prints the summary vector train and vector optimize print: identity, precision, chat_template, metadata, and one layer, width, norm, train_accuracy, train_margin record per layer. It used to serialize the whole document, which on a twenty-two-layer checkpoint is forty-five thousand floats down a terminal; the vectors are still on disk for anything that wants them. No model is loaded — this is the offline check that a file is a well-formed Ster artifact. Failures wrap the refusal: Error: failed to inspect tampered.json … Caused by: artifact belongs to product "other", not Ster.

ster vector compare#

text
Usage: ster vector compare [OPTIONS] --clusters <CLUSTERS> <ARTIFACT>...

Reads two or more steering artifacts fitted on one model and reports how alike their directions are at every layer they share, how much of each the others do not span, and which of them group together when cut into --clusters groups. No model is loaded and Ster chooses no group count. Options and refusals: `ster vector compare`.

ster vector project#

text
Usage: ster vector project [OPTIONS] --model <MODEL> --vector <VECTOR> --layer <LAYER> --strength <STRENGTH> --components <COMPONENTS>

Reads every side of a pair set at --layer, unsteered and with the artifact added at --strength, and projects both onto the first --components principal components of the unsteered reads, with the shift along the artifact's direction and how many negatives moved toward the positives. Ster states none of the three numbers. Options and refusals: `ster vector project`.

ster pairs#

text
Usage: ster pairs <COMMAND>

Commands:
  inspect     Report duplicates, refusals, length balance, and diversity for a set
  add         Append one pair, creating the set when the file does not exist
  remove      Remove one pair by its zero-based index
  synthesize  Generate a contrastive pair set with the loaded model

The pair-set surface: three subcommands that need no model and one that loads one. inspect audits a set — duplicates, refusal-reading sides, length balance, diversity — and prints the report; add and remove author a set in place; synthesize generates one. All four print one pretty JSON document to stdout. Per-subcommand options and refusals: `ster pairs inspect`, `ster pairs add`, `ster pairs remove`, `ster pairs synthesize`.

add and remove write the set back only when it still validates, so a file on disk never becomes something the loader would refuse — removing the last pair refuses and changes nothing. synthesize is the only one that loads a model, and it refuses --temperature 0 before generating: synthesis requires a temperature above zero; argmax generation repeats a single prompt. What it generates and why: synthetic pairs.

ster tune#

text
Usage: ster tune <COMMAND>

Commands:
  sft       Train LoRA adapters on prompt and completion examples
  dpo       Train LoRA adapters to prefer one side of each contrastive pair
  reward    Train a scalar reward head that ranks the two sides of each pair
  grpo      Optimize the policy against a reward, using a sampled group as baseline
  decide    Train LoRA adapters on labelled decisions
  merge     Fold a LoRA adapter into the base weights as a standalone checkpoint
  evaluate  Score a checkpoint on held-out examples: loss and perplexity, no training
  inspect   Print and validate a Ster LoRA adapter artifact
  help      Print this message or the help of the given subcommand(s)

Eight subcommands: five objectives that train an adapter, and three utilities that read one. The base checkpoint is mapped read-only and never registered as trainable, so the only weights any of them train are the low-rank adapters — and, on a reward run, the scalar head that reads them. sft fits prompt-and-completion examples with masked next-token cross-entropy; dpo fits a contrastive pair set with a preference objective, --loss dpo or --loss ipo; reward fits the same pair set with a Bradley-Terry head; grpo samples completions and runs a group-relative policy gradient against a reward; decide fits labelled decisions so the answer letter the model puts its mass on is the labelled one (`ster tune decide`). merge folds a finished adapter into the base weights, evaluate scores a checkpoint without training it, and inspect reads an artifact with no model loaded.

A fresh adapter is the identity, so every run starts from the base model's own behaviour (LoRA adapter) — which is also why the frozen reference dpo and grpo measure against costs nothing but a skipped projection, and why each objective's first loss is a known constant: ln 2 for dpo and reward, (1/(2·beta))² for --loss ipo, and exactly zero for grpo. Every objective writes the same artifact pair, and the sidecar's kind says whether it is a generation adapter or a reward model; applying one where the other belongs is a refusal, not a wrong answer.

Two options are shared by every subcommand that turns prose into tokens. --chat-template auto|off, on sft, dpo, reward, grpo and evaluate, decides whether text is encoded through the checkpoint's own conversation format; it defaults to auto, says which of the two things it did on one progress line, and records it in the report as chat_template (chat template). --batch-size, on sft, dpo, reward and evaluate, folds several rows into one forward pass — examples for the first and last, pairs for the two preference objectives, where a pair is two rows. It defaults to 1, the unbatched pass every run recorded before 0.13 took, and multiplies with --accumulation rather than replacing it. merge and inspect take neither: they read no prose.

--precision is the third shared option, on sft, dpo, reward, grpo and evaluate. It names the dtype the frozen base weights are mapped at — f32 (default), f16 or bf16 — and only that: adapters, a reward run's scalar head and every AdamW moment stay in F32 whatever it says, because a low-rank update below the weight's own ulp rounds to nothing in half precision. bf16 has no CPU matmul kernel in Candle and is refused on cpu before a weight is mapped (precision).

ster request#

text
Usage: ster request <OPERATION>

Arguments:
  <OPERATION>  The operation: vector/train, vector/optimize, vector/curve, vector/evaluate, vector/inspect, vector/compare, vector/project, vector/ablate, generate, extract, parity, decide, calibrate, workspace/import-pairs, workspace/show, workspace/select, workspace/remove, pairs/import, pairs/inspect, pairs/merge, pairs/save, pairs/synthesize, or tune/sft, tune/dpo, tune/reward, tune/grpo, tune/merge, tune/evaluate, tune/inspect

Reads one JSON body on stdin, prints NDJSON log events and one result event on stdout, and exits with the result's status. Every operation reuses the CLI's own code paths. Full surface: desktop request reference.

ster decide and ster calibrate#

text
Usage: ster decide [OPTIONS] --model <MODEL> --request <REQUEST>

      --request <REQUEST>              The request document: a state and its typed questions. `-` reads it from standard input
      --permutations <PERMUTATIONS>    Option orders each question is shown in [default: 0]
      --calibration <CALIBRATION>      A calibration written by `ster calibrate` for this exact model
      --output <OUTPUT>                Also write the response document here
      --explain                        Add per-order detail to the response

Usage: ster calibrate [OPTIONS] --model <MODEL> --examples <EXAMPLES> --output <OUTPUT>

      --examples <EXAMPLES>            Labelled examples: requests with the correct answer to some of their questions
      --output <OUTPUT>                Where the calibration artifact is written

decide answers typed choice, score and yes/no questions about a state from the model's next-token distribution over answer letters — the state read once with the key-value cache, each question's suffix on top of it, every option under every letter — and prints one JSON document with a probability for every option and no text generated. calibrate fits the temperature that makes those probabilities honest from requests a person has answered, and reports a shuffled-state control beside the accuracy. Both take --chat-template and --precision like every model-loading command. Pages: `ster decide`, `ster calibrate`, decision.