CLI reference
The zero-CLI principle. Nothing on this page is required.
Every command here is also reachable from inside the TUI — open the palette
with ^p and start the line with : to get the
command console, which runs any of these in place and shows the output.
This reference exists for scripts, automation, and power use.
One binary, no daemon. Run keel with no arguments inside a
series folder and the TUI opens; run it with a subcommand and it does one
thing and exits. Every command fails loudly — error messages carry the
reason, the object, and usually the cure.
Workspace & revisions
The strict-RCS core: check out, edit plain text, check in. Reads never
need a lock; edits always do.
| init NAME [--author A] | Create a series workspace under the current directory, fully seeded (spine, calendar, frames, ledger). Author defaults to your OS username. |
| co ID | Check out: take the exclusive lock, pull the head revision into checked-out/ as plain text. |
| co -l | List what you are holding, with lock ages. |
| ci ID -m MSG [--changeset a-N] | Check in: new immutable revision, release the lock. Structured content is validated first; leaves get Plank-formatted. With --changeset, the revision lands pending inside an open amendment. |
| log ID | The full revision trail — rev, date, author, status, message. |
| diff ID [A..B] | Word-level diff between two revisions; defaults to previous..head. |
| status | Every open checkout with holder and age, the spine frontier, stale amendment debt, and unproofread leaves. |
$ keel init "The Long Year" --author reza
$ cd the-long-year
$ keel co s-0001
checked out s-0001 r1 → checked-out\s-0001.md
$ keel ci s-0001 -m "the ferryman scene"
checked in s-0001 r2
$ keel diff s-0001 # word-level: [-removed-] and +added+
$ keel log s-0001
$ keel status
Spine & structure
Position is encoded in the id — arc-v1.2,
mv-v1.2.1, b-v1.2.1.1 — and parents must exist
first. Leaves are gated: no leaf outside a specified-or-better beat.
| new ID [--title T] | Create an arc, movement, or beat (beats arrive as stubs — not writeable until specified). For entities: new e-slug [--name N] [--category character|location|faction|lore]. For leaves: new s-#### --beat b-… — the write gate checks the beat's status. |
| synopsis | The whole spine stitched into continuous prose — the book before it is written — plus the frontier. |
| frames | Chapters over beats with word budgets and real printed-page estimates. |
$ keel new arc-v1.2 --title "Salt and Ash"
$ keel new mv-v1.2.1 --title "The Crossing"
$ keel new b-v1.2.1.1 --title "The River"
created b-v1.2.1.1 — "The River" (stub · not writeable until specified)
$ keel new s-0002 --beat b-v1.2.1.1
keel: the write gate refuses this: beat b-v1.2.1.1 is Stub…
$ keel new e-kael --name Kael --category character
$ keel synopsis
$ keel frames
Writing & proofreading
| proofread LEAF | Run the strict AI copy-edit pass and show the corrections as a word diff. Nothing is written. |
| proofread LEAF --accept | Apply the corrections as a new revision and mark it proofread. |
| proofread LEAF --mark-only | Record a human proofread of the current head — no AI. Marks are per-revision; any edit clears them. |
| plank fmt ID | Expand bare @end to @end name in the working file (also happens on every check-in). |
| plank strip ID | Print the leaf as clean CommonMark — markup collapsed, @cut interiors gone. |
| plank check ID | Report Plank issues; structural markup in prose and unclosed blocks are errors. |
$ keel proofread s-0001
s-0001 r2 — corrections ([-…-] +…+):
He [-walkked-]+walked+ to the gate.
$ keel proofread s-0001 --accept
$ keel plank check s-0001
s-0001: clean (4 plank tokens)
The Ledger & amendments
Facts and promises are canon memory; amendments are migrations with a
computed blast radius, landed atomically.
| fact add --subject S --statement T --scene L [--year Y] [--day D] [--quote Q] | Record a fact with provenance; validity defaults to the establishing beat's story time. |
| fact list | Every fact with subject, source, and reveal position. |
| promise add --statement T --opened-in B [--due-arc N] | Open a promise (setup, question, threat) with a due-by. |
| promise pay ID --in B | Mark it discharged by a beat. Paying twice is refused. |
| promise list | Paid and hanging promises, with due arcs. |
| extract LEAF [--accept all|1,3] | Propose facts from @fact/@ref markup (always) and the AI extractor (when keyed). Nothing lands without --accept — human triage is the design. |
| amend BEAT -m MSG | Diff your edited beat card, compute the blast radius, open changeset a-N with the beat as its first member, and print the reconcile tasks. |
| land CS [--waive REASON] | Flip every pending revision canon atomically. Refused while a blocking impact is unreconciled, unless waived with the reason on record. Unreconciled warnings become tracked stale debt. |
| abandon CS | Walk heads back over the retained pending revisions. History is never deleted. |
| changesets | Every amendment with status and pending count. |
$ keel co b-v1.1.1.1 # edit exits_with in the card…
$ keel amend b-v1.1.1.1 -m "the toll is memory"
amendment a-1 opened — b-v1.1.1.1 (exits_with)
blast radius (2 impacts):
⛔ b-v1.1.1.2 enters_with must be re-satisfied
⚠ s-0001 realizes b-v1.1.1.1
$ keel co b-v1.1.1.2 # reconcile the successor…
$ keel ci b-v1.1.1.2 -m "re-satisfy entry" --changeset a-1
$ keel land a-1
a-1 landed — 2 revisions canon
$ keel promise add --statement "whose memory did he lose?" --opened-in b-v1.1.1.1 --due-arc 1
$ keel extract s-0001 --accept all
The book & exports
| render [--open] [--publish] | Typeset the volume to a true B-format PDF via Typst. --open launches your viewer (it reloads on re-render); --publish pushes the PDF to the signed-in Yard, viewable at /preview/<slug>.pdf. |
| export --tree [--out DIR] | The whole series as ordinary files — the portability story, on demand. |
| export --epub | --docx [--out PATH] | E-book and manuscript formats via pandoc. |
| snapshot [NAME] | Pin every object's head under a name; with no name, list snapshots. |
| stats | Words against target, printed pages, weekly pace, and a fourteen-day burn-down. |
$ keel render --open --publish
rendered .keel\render\book.pdf
published — view it at http://localhost:8000/preview/the-long-year.pdf
$ keel export --tree
$ keel export --epub
$ keel snapshot "draft one"
$ keel stats
Search & the index
| search QUERY | Full-text search (FTS5) across every object; rebuilds a missing index automatically. |
| index --rebuild | Reconstruct the derived index (search, refs) and the project dictionary from the store alone — byte-identical every time. |
| geometry | The derived page geometry: trim, text block, ~62 characters × 34 lines, ~300 words per printed page. |
$ keel search "poured pewter"
s-0001 scene … the river went past them the colour of [poured pewter] …
$ keel index --rebuild
$ keel geometry
Davy & voice
| ai draft LEAF -i ASK | Davy from the CLI: assembles the full context recipe, streams the draft to stdout, logs usage. Nothing is written to the store. |
| ai usage | Today's and the month's AI spend from the usage log. |
| voice seed FILE | Store ~1,500 words of your own prose as the voice profile Davy writes toward. |
$ keel voice seed my-old-story.txt
$ keel ai draft s-0002 -i "He realises the toll was a name. No dialogue."
$ keel ai usage
today $0.14
Session & meta
| login --url U --username N --password P | Sign in to the Yard and lock the TUI to it. The password flag is the MVP test login only. |
| logout | Sign out; the TUI returns to local dev mode. |
| changelog | Print the changelog — the same text the TUI overlay and the Yard show. |
| auto-novel TITLE [--pages N] [--setting S] [--world W] [--characters A,B] [--author A] [--offline] | Build a complete sample series from minimal input — every layer populated, deterministic offline, Davy-drafted when keyed. Educational. |
$ keel login --url http://localhost:8000 --username admin --password mvp
signed in to the Yard at http://localhost:8000 (v0.9.0) as admin
$ keel auto-novel "The Salt Ledger" --pages 24 --characters "Kael,Vess,Immy"
$ keel changelog
$ keel logout
Exit codes are meaningful: 0 success ·
1 error · 2 usage · 3 lock conflict ·
4 integrity violation (the loud, should-be-impossible one).
Scripts can branch on them.