On this page

Quick start

From clone to a scored and rewritten text. Commands that need credentials show the exact refusal you get without them, so you know the setup is working before you spend a detector call.

1. Build

Rust 1.85+, edition 2024. TLS is rustls — no system dependencies.

git clone https://github.com/wisent-ai/skryba
cd skryba
cargo build --release

The binary is target/release/skryba. cargo install --path . puts it on ~/.cargo/bin (which the desktop app also searches).

2. Prove the binary answers

skryba --help

The commands it lists are the command tree: draft, score, corpus, rewrite, benchmark, train, onboarding, writing-style, style, language and database.

3. Reach the fleet database

Everything Skryba keeps — the catalog, drafts, your writing and the score cache — lives in its fleet database, found through Stado and Skarbiec. With stado on PATH and the skryba-database-client bearer in ~/.stado/:

skryba database check

prints the tables and their row counts, or the step that failed.

4. Run something that needs no credential

corpus verifies a curated corpus file offline — no credentials, no network. --seed orders the sample and is yours to state:

skryba corpus corpus.json --seed <N>
{
  "corpus": "corpus.json",
  "samples": [
    { "id": "docs-sample-1", "whitespace_words": 19 },
    { "id": "docs-sample-2", "whitespace_words": 23 }
  ],
  "verified_samples": 2
}

(The corpus file format is documented in train and benchmark; tests/fixtures/humanization_samples.json in this repository is a real one.)

Capture your own writing, also with no model credential

writing-style needs no model or detector credential — add reads your files and writes the passages table, in passages of the word window you state:

skryba writing-style add ~/writing --min-words <N> --max-words <N>
skryba writing-style status

status answers with store (stado://database/skryba/skryba), passages, passage_words, preferences, added and skipped.

writing-style train needs no model credential either, but it is not free the way these two are: it hands the export to the installed ster binary, which maps a checkpoint — fetching it from the Hugging Face hub when it is not cached — and then trains for as long as the gradient takes. Install Ster first with cargo install --git https://github.com/wisent-ai/ster --locked.

The full command tree is skryba writing-style; a real ingest, export, and Ster training run is the writing-style walkthrough.

Teach it how you text, and keep it learning

Your messages and notes are writing too, and they keep coming. Register them once and let Stado read them every night:

skryba writing-style harvest add my-messages --kind messages \
  --path ~/Library/Messages/chat.db --min-words 8 --max-words 200
skryba writing-style harvest add my-notes --kind notes \
  --path "~/Library/Group Containers/group.com.apple.notes/NoteStore.sqlite" \
  --min-words 30 --max-words 300
skryba writing-style harvest run
skryba writing-style harvest schedule set --cron "0 3 * * *" --tz Europe/Warsaw --host <HOST>

Each run adds only what is new since the last one. Every kind, path and refusal: writing-style harvest.

Find out which samples to rewrite

An adapter learns most from your rewrite of a machine's text. Ask how many pairs each kind and length of your writing needs, have the model write them, and rewrite each one:

skryba writing-style samples plan --pairs 200 --length-bands 4
skryba --brama-url "$BRAMA_URL" --model "$SKRYBA_MODEL" \
  writing-style samples generate --pairs 200 --length-bands 4 --temperature 0.8 --seed 7
skryba writing-style samples show <ID>
printf '{"sample":"<ID>","kept":"How I would have said it."}' | skryba writing-style keep

The plan counts every kept sample and writes only what is still missing: writing-style samples.

Hold every rewrite to your own sentence length

Measure how you write, then make it a rule every rewrite candidate is counted against:

skryba writing-style profile --quantile 0.9
skryba rule add short-sentences --metric sentence-words --max 22
skryba rule add no-delve --metric phrase --max 0 --phrase delve
skryba rule check draft.md

Every metric and refusal: skryba rule.

5. Configure credentials

Skryba refuses precisely when a credential is missing. Without any detector key:

echo "Some text." | skryba score
Error: no detector credentials found; configure GPTZERO_API_KEY, WINSTON_API_KEY, ORIGINALITY_API_KEY, or SAPLING_API_KEY

Configure at least one detector credential in the process environment. For generation and judging, configure references to credential roles, not secrets or vault item names. The deployment environment contains:

BRAMA_URL=<published-Brama-endpoint>
SKRYBA_MODEL=<declared-model>
BRAMA_TOKEN_ROLE=<client-token-role>#<field>

The CLI reads its process environment, not an implicit .env file. Have the deployment load these settings; Desktop can read them from its documented ~/.config/skryba/env file. Skryba resolves the token with stado credentials get --role <client-token-role> --field <field>. The role must already grant this caller access to the Brama client token. If the route requires agent authentication, configure SKRYBA_AGENT_ID and SKRYBA_AGENT_AUTH_SECRET_ROLE=<agent-secret-role>#<field> together.

Without Stado, explicitly select an owner-only JSON credentials file with SKRYBA_CREDENTIALS_FILE; its shape is role → field → value. This is a chosen credential source, not a fallback after a failed resolver. BRAMA_TOKEN and SKRYBA_AGENT_AUTH_SECRET are not read.

The full variable table is configuration. The detector ensemble is inferred from which keys are set; --detectors gptzero,sapling selects explicitly.

6. Score

echo "Additionally, the study found that participants who received the intervention reported higher satisfaction." | skryba score

Real output (captured against a local Sapling-shaped endpoint; with a real key the number is the detector's verdict, the shape is identical):

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

Run the same text again and "cached": true — the score came from the score cache in the fleet database and cost nothing.

7. Rewrite

skryba --minimum-quality <Q> rewrite draft.txt --generator brama \
  --candidates <N> --max-words-per-chunk <N> --temperature <T> --seed <N> --report report.json

Every number is yours to state; Skryba assumes none. The command prints the rewritten text to stdout and writes every per-chunk, per-candidate score to report.json. A real end-to-end run — including what the JSON looks like — is captured in the offline rewrite walkthrough. INPUT is a file path or - for stdin (the default) on score and rewrite alike.

8. Where next

  • Full flag reference: cli.
  • Training an adapter that writes like you: skryba writing-style and the walkthrough.
  • Training a policy on your own corpus: train and benchmark.
  • Paying a person to rewrite the text instead: that is HandToHuman's job, not Skryba's — price it with handtohuman quote --kind humanization --words N --turnaround-minutes M and run it on the marketplace ledger with handtohuman market.
  • Every refusal sentence and its fix: runbook.

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