On this page

CLI reference — global options, score, rewrite, corpus

The binary is skryba (src/main.rs). Every command prints JSON on stdout, except rewrite which prints the rewritten text unless --json is set. Errors are printed by anyhow as Error: <message> (with Caused by: chains) on stderr, exit status 1. Success is exit 0. Training and benchmark are on their own page; RentAHuman on cli-rentahuman.

Global options

Global options come before the subcommand (skryba --detectors sapling score). Each env: variable is read by clap, so the flag always wins over the environment.

Flag Env Default Meaning
--brama-url <URL> BRAMA_URL https://brama.wisent.com Brama base URL; /v1/chat/completions is appended
--model <MODEL> SKRYBA_MODEL claude-code-subscription generator model name passed to Brama
--judge-model <MODEL> SKRYBA_JUDGE_MODEL generator model quality-judge model; defaults to --model
--minimum-quality <F> 0.9 quality gate; see quality judge
--detectors <NAMES> inferred from keys comma-separated subset of gptzero, winston, originality, sapling
--cache <PATH> SKRYBA_CACHE ~/.cache/skryba/detector-scores.sqlite3 detector score cache; ~ is expanded
--detector-interval-ms <N> 250 minimum spacing between requests to one detector

Detector selection: with --detectors, names are lowercased and must all be known; an unknown name is unknown detector "<name>"; available detectors: gptzero, originality, sapling, winston, and every named detector's key must be set (GPTZERO_API_KEY is required for gptzero). Without --detectors, the ensemble is every detector whose key is a non-empty environment variable; none set is no detector credentials found; configure GPTZERO_API_KEY, WINSTON_API_KEY, ORIGINALITY_API_KEY, or SAPLING_API_KEY.

Input convention

score, rewrite, and rentahuman create take [INPUT]: a file path or - for stdin. The default is -. ~ in paths is expanded against HOME. Reading a missing file fails with reading <path>.

skryba score [INPUT]

Measure detector AI probabilities. Builds the detector ensemble, scores the text once with every detector concurrently (each detector obeys its own rate limit and cache), and prints:

{
  "ai_probability": 0.7835,
  "detectors": [
    { "ai_probability": 0.7835, "cached": false, "detector": "sapling" }
  ]
}

ai_probability is the unweighted mean of the per-detector probabilities. cached: true means the number came from the local SQLite cache and no request was sent. Needs at least one detector key; does not need BRAMA_TOKEN. Empty or whitespace-only input is refused per detector: <name> cannot score empty text.

skryba rewrite [OPTIONS] [INPUT]

The full pipeline: chunk → generate candidates through Brama → score with detectors and the quality judge → select per chunk (rewrite). Needs BRAMA_TOKEN and at least one detector key.

Flag Default Meaning
--output <PATH> write the rewritten text (plus trailing newline) to a file instead of stdout
--report <PATH> write the complete RewriteResult JSON to a file
--json off print the complete RewriteResult JSON to stdout
--policy <PATH> built-in uniform policy load a trained policy JSON; missing/invalid file is an error, not a fallback
--candidates <N> 8 candidates generated per chunk; 0 is refused (candidate count must be positive)
--max-words-per-chunk <N> 400 chunk budget; 0 is refused
--temperature <F> 0.9 generator sampling temperature; outside [0, 2] is refused
--seed <N> 42 seeds strategy sampling — the same seed, policy, and candidate count sample the same strategies

Output modes combine: --output suppresses the text on stdout; --json prints the JSON to stdout regardless; --report writes the same JSON to a file. With none of the three, stdout is the rewritten text alone.

The RewriteResult JSON (--json/--report):

text                       final text: selected chunk texts joined by blank lines
chunks[]                   one per chunk
  source                   the original chunk
  selected                 the winning CandidateScore
  candidates[]             every generated CandidateScore
  used_source_fallback     true when no candidate passed and the source was kept
CandidateScore:
  strategy_index           index into the policy's strategies; null for the source fallback
  strategy                 strategy name, or "source-fallback"
  text                     candidate text
  ai_probability           ensemble mean for this candidate
  quality_score            weighted judge score (see quality judge)
  quality_passed           the per-dimension gate verdict
  quality                  the full judge evaluation (six dimensions, critical_error, issues, rationale)
  detectors[]              per-detector {detector, ai_probability, cached}

A captured real example is in the offline rewrite walkthrough.

skryba corpus <PATH> [--samples N] [--seed N]

Verify a curated corpus file offline: every sample's declared whitespace_words and input_sha256 must match its input text. Prints the verified sample list:

{
  "corpus": "corpus.json",
  "samples": [ { "id": "docs-sample-1", "whitespace_words": 19 } ],
  "verified_samples": 1
}

--samples (default: all) truncates after a deterministic shuffle keyed by --seed (default 42) — the same order benchmark --corpus uses, so corpus previews exactly which samples a benchmark would take. Any mismatch is a refusal naming the sample, e.g. curated sample docs-sample-1 declares 5 words and carries 19. The file format is defined in train and benchmark.

Exit status

0 on success; 1 on any error, with the message on stderr. There are no other exit codes.

Maintained as part of the website-owned Skryba documentation corpus.