On this page

Rewrite

A rewrite is Skryba's complete detector-directed transformation of one input text. It is not a single model response. Skryba generates several candidates for each chunk, measures every candidate with the configured detector ensemble and the quality judge, then selects the least detectable candidate that passes quality, style, and language checks.

Shape

skryba rewrite --json and --report serialize a RewriteResult:

  • text: selected chunk texts joined with a blank line;
  • profile: the resolved style and language names and the style_instruction and language_instruction the catalog held for them when the run started;
  • chunks[]: the source chunk, selected CandidateScore, all generated candidates, and used_source_fallback;
  • each candidate: strategy index and name, text, ensemble ai_probability, quality_score (the weakest judged dimension), quality_passed, full quality evaluation including style_matched and language_matched, and per-detector results.

The complete wire field list is in the CLI reference.

Lifecycle

  1. Resolve --style and --language in the catalog; refuse a name it does not hold, before any credential is read. Reject empty input, a zero candidate count, a zero chunk limit, nonfinite or negative temperature, or minimum quality outside 0..=1. Skryba imposes no temperature ceiling; the model route owns any upper bound. The candidate count, chunk limit, temperature, seed and minimum quality are the caller's; none has a default.
  2. Split the input into chunks.
  3. For each chunk, sample --candidates strategy indices from the policy, using --seed.
  4. Ask the chosen generator for one rewrite per sampled strategy: one Brama chat completion each under --generator brama, or one ster generate process each under --generator local, with the person's own --adapter attached (training boundary). The required profile applies to every candidate and overrides a conflicting strategy or learned voice.
  5. Drop any local candidate ster generate returned as whitespace, naming it on stderr; the group is then smaller than --candidates.
  6. Score all generated candidates with every configured detector and ask the Brama-backed quality judge to evaluate them, once each. Each distinct candidate text is measured once and shared by every position holding that text, so duplicate candidates do not pay for duplicate measurements within the group.
  7. Keep only candidates whose six quality dimensions meet their thresholds, whose critical_error is false, and whose style_matched and language_matched are true.
  8. Select the survivor with the lowest ai_probability. If none survives, judge the original chunk against the requested profile. Only if both profile checks pass, detector-score it and select a synthetic source-fallback candidate. Otherwise fail with the chunk number, requested profile, source match booleans, candidate rejection counts, and source judge issues.
  9. Join selected texts. Print text or JSON and optionally write --output and --report files.

Candidates are processed chunk by chunk. Detector calls for a candidate set run concurrently, while each detector still keeps its own cache and the pause --detector-interval-ms states, if any. Brama candidates are generated concurrently too; local candidates are generated one after another on purpose, because each ster generate maps the checkpoint and a parallel group would hold one copy of the weights per candidate.

Selection invariants

  • Quality, required style, and output language are hard gates for generated candidates, not ranking preferences.
  • Detectability decides only among candidates that passed every gate.
  • A detector failure fails the rewrite; Skryba never changes the ensemble silently.
  • The original is not an unconditional fallback. It must already satisfy the requested style and language; it need not pass every numeric quality threshold.
  • A profile refusal happens before final output and report writes. Existing destination files remain untouched; earlier model calls and detector-cache writes are not rolled back.
  • --seed controls strategy sampling, not remote model determinism. It is not the local generator's seed either: each ster generate is seeded with its own candidate index, 0 for the first candidate in a chunk, so the local route repeats itself without --seed reaching it.
  • --policy is loaded and validated; a missing or invalid policy is an error, not a fallback to the built-in policy.

Refusals

  • style "<NAME>" is not in <CATALOG>; available styles: <NAMES>; add it with `skryba style add <NAME> --instruction <TEXT>` — and the same sentence for language; exit 1 before the pipeline runs.
  • --minimum-quality is required: the quality score a rewrite must reach is the caller's to state
  • input text cannot be empty
  • candidate count must be positive
  • maximum words per chunk must be positive
  • temperature must be a finite number of at least 0; a ceiling is the route's own, and Brama states its refusal in its own words
  • minimum quality must be between 0 and 1
  • BRAMA_TOKEN_ROLE is required for Brama inference: ROLE#FIELD of the vault role holding the client token — on the local route too, because the quality judge is Brama's. See credential boundary for Stado resolution and the explicit owner-only file alternative; BRAMA_TOKEN is not read.
  • --generator local needs --local-model naming the checkpoint Ster maps
  • --generator local needs --local-max-new-tokens; Ster assumes no token budget
  • --local-max-new-tokens must be positive
  • chunk <N>: no candidate passed every check for the requested style '<STYLE>' and language '<LANGUAGE>'; source fallback refused ... — no candidate passed the combined gates, and the original cannot fulfill the profile either. A candidate may match style and language but fail content quality. Style, language, and all-quality rejection counts may overlap; they are not separate candidate groups.

The earlier offline rewrite walkthrough used stand-ins. It is historical output, not evidence that the current style and language contract passes real model and detector flows.

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