On this page
Training boundary
Skryba owns the person's text and the rewrite loop. Ster owns the weights and
the gradient. Skryba calls Ster rather than reimplementing it: it writes the
training file, spawns the installed ster binary, and reports what came back.
Which product owns what
Skryba holds the store, decides what a passage is, builds the training file, chooses candidates, scores them against detectors, and gates them on quality. It maps no checkpoint in its own process, links no tensor library, and carries no tokenizer — that work belongs to Ster, which maps the checkpoint, runs the forward and backward passes, and writes the LoRA adapter. Reimplementing a trainer inside Skryba would duplicate Ster and give a text tool a GPU dependency it has no other use for; calling Ster costs one process.
Skryba resolves ster the way Skryba Desktop resolves skryba: every PATH
entry first, then ~/.cargo/bin, ~/.local/bin, ~/.stado/bin,
/opt/homebrew/bin and /usr/local/bin. When it is missing, Skryba says so in
one sentence and names the install command rather than failing obscurely.
Ster's own words reach the operator unchanged. A training run streams both of Ster's streams to Skryba's stderr, so its progress and its refusals print as Ster writes them while Skryba's stdout stays the one JSON report; a captured run carries Ster's message through verbatim. Skryba never rewords a refusal it did not produce.
From the store to an adapter, in one command
skryba writing-style add ~/writing ~/notes --min-words <N> --max-words <N>
skryba writing-style train \
--model <checkpoint> \
--output my-prose.safetensors \
--rank <N> --alpha <A> --epochs <N> --learning-rate <F> --accumulation <N> \
--max-sequence <TOKENS> --batch-size <N> --seed <N> --lead-words <N>
train exports the held text, runs ster tune sft over it, and reports where
the adapter landed together with the exact ster command it ran, so the run
can be repeated by hand. --method dpo trains the preference objective from
the pairs the person resolved themselves and runs ster tune dpo instead.
--model, --revision, --device, --precision, --rank, --alpha,
--epochs, --learning-rate, --accumulation, --max-sequence,
--batch-size, --seed and, for DPO, --beta pass straight through to Ster
rather than being hidden; every number is required, because Ster assumes none
and so does Skryba.
The export is kept, not discarded: it is written beside the adapter as
<adapter-stem>-sft.json or -dpo.json unless --export names a path.
writing-style export still exists for anyone who wants the file alone.
The two shapes, and which command reads each
--format sft — and --method sft — writes what ster tune sft deserializes:
{
"name": "my-prose",
"examples": [
{ "prompt": "…", "completion": "…" }
]
}
The completion is the person's own prose. The prompt is one fixed line of
framing, Continue this passage in the same voice:, followed by the
passage's own opening sentences — --lead-words words (required for sft), cut at
the first sentence end at or after that count. Ster masks the prompt out of
the loss and trains only on the completion, so nothing is learned from the
lead as a target; it is the distribution the adapter answers.
Two other prompts were available and are worse. A synthesized instruction would need a model call — a Brama request and a credential — to capture your own writing, and it would collapse into a handful of templated sentences repeated across the corpus, which is exactly what Skryba's six hard-coded strategies already are: the same words for every user on earth. The AI-written version of the same passage is a rewrite prompt rather than a writing prompt, it exists only where a rewrite was run, and where it does exist it is a preference — which is the other format, below.
--format dpo writes what ster tune dpo deserializes:
{
"trait_name": "my-prose",
"pairs": [
{ "positive": "…", "negative": "…" }
]
}
positive is what the person kept, negative what the model produced. Ster
scores a pair whole and carries no prompt field, so both sides are complete
texts of the same passage. --name sets name in the SFT set and
trait_name in the pair set.
A pair set is not only a preference input. ster train, ster optimize,
ster evaluate, ster tune dpo and ster tune reward all deserialize the
same PairSet, so one --format dpo file feeds the steering half of Ster as
well as the preference half, unchanged.
Rewriting through the model that was trained
An adapter nobody generates with is a file. rewrite takes a generator:
skryba --minimum-quality <Q> rewrite \
--generator local \
--local-model <checkpoint> \
--adapter my-prose.safetensors \
--candidates <N> --max-words-per-chunk <N> --temperature <T> --seed <N> \
< passage.txt
--generator brama is the other route — one chat completion per candidate, no weights
anywhere near the machine. --generator local runs ster generate with the
personal adapter attached, so the rewrite is written by the model that learned
the person's prose. The rest of the loop is unchanged: the same six
strategies, the same detector ensemble, the same quality gate, the same
least-detectable selection.
One candidate is one ster generate process, and each process maps the
checkpoint again. That cost is real, and it is why the local route is chosen
rather than assumed; a small --candidates keeps a local group affordable.
What each side still refuses
- Skryba refuses to invent examples: a training run uses only rows the person
put in the store, and a passage too short to split into a lead and a
completion is counted in
skippedrather than padded. - Skryba refuses to claim a success Ster did not report: if
ster tunereturns zero but no adapter exists at--output,trainfails. - Ster refuses to truncate: an example longer than
--max-sequencetokens is skipped and named on stderr, because a cut completion would teach the model to stop early. - Ster refuses a mismatched adapter: an adapter trained for another checkpoint is rejected rather than applied to the wrong residual stream.
Maintained as part of the website-owned Skryba documentation corpus.