On this page
CLI reference — train and benchmark
Both commands exercise the generator and judge; global options
(cli) select models, detectors, cache, and the
quality gate. Training needs BRAMA_TOKEN and detector keys;
benchmark needs only BRAMA_TOKEN — it judges quality and never calls a
detector.
skryba train <SOURCE> [OPTIONS]
Native GRPO (Group Relative Policy Optimization) over the rewrite-strategy
distribution — no Python, no external ML runtime (src/training.rs,
src/policy.rs).
For every training text, the policy samples --generations strategies,
one candidate is generated per sample, and each candidate is rewarded
reward = (detector_weight * (1 - ai_probability) + quality_weight * quality_score)
/ (detector_weight + quality_weight)
- quality_failure_penalty (only when the judge fails the candidate)
Rewards are normalized against the group mean into advantages, and the
policy logits are updated with Adam (β₁ 0.9, β₂ 0.999, ε 1e-8, logits
re-centered after every step) under a PPO-style ratio clip and a KL
penalty against the reference (initial) policy, for --inner-iterations
steps per group. The policy is saved to --output-policy after every
group — an interrupted run keeps its progress. Details:
policy.
| Flag | Default | Meaning |
|---|---|---|
--text-column <NAME> |
ai_text |
field holding the AI text in JSON/JSONL rows |
--policy <PATH> |
built-in uniform | starting policy |
--output-policy <PATH> |
outputs/policy.json |
where the trained policy is written (atomically, via a .json.tmp rename) |
--epochs <N> |
1 |
passes over the corpus; 0 is refused |
--generations <N> |
8 |
group size; below 2 is refused (training requires at least one epoch and two generations per group) |
--learning-rate <F> |
0.05 |
Adam step size; must be > 0 |
--beta <F> |
0.001 |
KL penalty weight; must be >= 0 |
--clip-epsilon <F> |
0.2 |
PPO clip; must be in [0, 1) |
--inner-iterations <N> |
4 |
optimization steps per group; must be > 0 |
--temperature <F> |
0.9 |
generator temperature |
--seed <N> |
42 |
seeds strategy sampling |
--detector-weight <F> |
0.6 |
detectability weight in the reward |
--quality-weight <F> |
0.4 |
quality weight in the reward |
--quality-failure-penalty <F> |
1 |
subtracted when the judge fails a candidate |
Weights must be non-negative with a positive sum, and the penalty
non-negative (training reward weights and penalty are invalid).
Training data formats
SOURCE's extension decides the parser:
.json— a JSON array; each row is a string or an object..jsonl— one JSON value per non-empty line..txt(or no extension) — plain text split on blank lines, one example per paragraph block.- anything else —
unsupported training data extension "<ext>"; use .json, .jsonl, or .txt.
For object rows, the text is the first non-empty string among
--text-column, ai_text, text, generated_text, completion. An
empty corpus is training data contains no text examples.
Output
Each group prints one JSON line on stderr (progress you can tee to a log):
{"epoch":1,"example":1,"metrics":{"mean_reward":0.59768,"reward_std_dev":0.0,"baseline":0.59768,"kl_divergence":0.0,"updates":4},"probabilities":[0.16666666666666666,0.16666666666666666,0.16666666666666666,0.16666666666666666,0.16666666666666666,0.16666666666666666],"mean_detector_reward":0.356,"mean_quality_score":0.9601999999999999,"quality_pass_rate":1.0}
The final summary goes to stdout:
{
"examples": 2,
"epochs": 1,
"groups": 2,
"final_mean_reward": 0.77528,
"output_policy": "outputs/policy.json",
"probabilities": [0.16666666666666666, "…"]
}
(Both captured from a real run; see the offline rewrite walkthrough.)
skryba benchmark [ROOTS...] [OPTIONS]
Evaluate rewrite quality (not detectability) over passages: generate
--candidates per passage, judge every candidate and the source itself,
select the highest quality score, and report per-dimension means. Because
selection is quality-only, no detector keys are needed.
Passages come from exactly one of:
--corpus <file>— a curated corpus (verified first, exactly likeskryba corpus), or- one or more documentation roots — README/docs Markdown files are walked
and one passage of
--min-words..--max-wordsis extracted per file, skipping code fences, tables, images, HTML, and bare links.
Neither is benchmark needs --corpus or at least one documentation root;
both is
benchmark accepts either --corpus or documentation roots, never both.
Passage selection is deterministic: candidates are ordered by
sha256(seed, path-or-id) and truncated to --samples.
| Flag | Default | Meaning |
|---|---|---|
--corpus <PATH> |
— | curated corpus instead of documentation roots |
--output <PATH> |
outputs/docs-quality-benchmark.json |
full report destination |
--policy <PATH> |
built-in uniform | policy whose strategies are sampled |
--samples <N> |
10 |
passages to evaluate |
--candidates <N> |
4 |
candidates per passage |
--min-words <N> / --max-words <N> |
80 / 300 |
documentation passage bounds (roots mode only) |
--temperature <F> |
0.9 |
generator temperature |
--seed <N> |
42 |
seeds selection and sampling |
The summary is printed to stdout; the full report (per-entry sources,
candidates, and evaluations, schema_version: 2) goes to --output.
Captured real summary:
{
"samples": 2,
"quality_pass_rate": 1.0,
"critical_error_rate": 0.0,
"mean_source_quality": 0.9601999999999999,
"mean_rewrite_quality": 0.9601999999999999,
"mean_quality_delta": 0.0,
"mean_meaning_preservation": 0.97,
"mean_factual_consistency": 0.96,
"mean_grammar": 0.98,
"mean_coherence": 0.95,
"mean_naturalness": 0.93,
"mean_readability": 0.94
}
Curated corpus format
Consumed by corpus, benchmark --corpus, and suitable as training data
(.json array is a different shape — a curated corpus is an object):
{
"samples": [
{
"id": "docs-sample-1",
"whitespace_words": 19,
"input_sha256": "09c1dc49…",
"input": "The committee reviewed the proposal…"
}
]
}
whitespace_words must equal input.split_whitespace().count(), and
input_sha256 the lowercase hex SHA-256 of input's bytes. Extra fields
(title, language, …) are allowed and ignored.
tests/fixtures/humanization_samples.json is the repository's own curated
corpus. Verification failures name the sample; see
runbook.
Maintained as part of the website-owned Skryba documentation corpus.