LitHarness is an open-source Python system for autonomous, open-ended serial fiction. It coordinates specialised LLM agents across listing, world design, planning, scene drafting, continuity, repair, covers, and release packaging while preserving content-addressed manuscript history and scene-grounded narrative state.
Its product objective is fiction a defined audience voluntarily continues and recommends, with no human in the production loop. The operator may direct a book and accept or reject it at book grain, but does not write, rank candidates, label passages, or train the system.
The hard unsolved problem is perception, not prose plumbing: LitHarness needs an LLM-based cognitive system that perceives literary quality well enough to behave as a readership. A reader prompt is only one possible interface to that capacity. The current mechanism families and their evidence live in the reader-architecture programme; failed approaches and their controls live in the quality-measurement brief.
The production loop is real: it can create a listing and title, build and evolve a world through the Architect, plan and draft scenes against recorded context, reject integrity failures, repair located defects, preserve immutable revisions, and export a book and cover set. No simulated reader mechanism has yet earned the right to certify literary quality. That distinction is the project's most important status line.
For the full objective and roadmap, see PLAN.md §1a and §17. Historical decisions and reversals are preserved in plan/stage-0-decisions.md; they are not an operator manual.
Python 3.11+ and uv are required. The contracts package and golden
fixtures are pinned through uv.lock, so one checkout is enough.
git clone https://github.com/skulitom/LitHarness
cd LitHarness
uv sync --extra dev
uv run python tools/check.py smokeProduction generation uses the signed-in local Claude Code CLI, pinned to the frontier model in
src/litharness/providers/cli.py. There is no automatic weaker fallback: if the provider is
unavailable, work waits rather than silently degrading. Tests cannot reach a billing provider;
for an explicit model-free local run, set LITHARNESS_FAKE_PAD_CHARS=400.
Cover generation is separate. It uses signed-in Codex image-generation sessions, followed by
deterministic local typography, and needs the cover extra:
uv sync --extra coverThe listing loop is the normal entry point. It writes the listing a reader sees, records experimental appetite observations without feeding them back into revision, checks the title for collisions, and creates the empty scenes:
uv run litharness --database book.db listing \
--writer halloran \
--brief "A debt collector discovers every debt is also a spell." \
--scenes 24 \
--out runs/listings/debt-book--writer names a compiled cast writer or any writer the roster has accepted. The roster lives
in the open database unless --roster-database (or LITHARNESS_ROSTER_DATABASE) names the
installation's roster store, which is what lets a writer accepted once draft on every fresh book
database (stage-0 §151).
An empty brief is a valid control. Use new when title and premise already exist, or import for
a contracts fixture or manuscript:
uv run litharness --database book.db new "The Toll Road" \
--premise "A debtor works off an impossible debt along a System-governed road." \
--scenes 24
uv run litharness --database fixture.db import --fixture litrpgThe default 24 scenes are one structurally closed six-chapter arc. Grow the same canonical serial—without resetting character state, promises, numbering, or revision history—with:
uv run litharness --database book.db extend --arcs 1Release “books” are derived packaging windows over that serial, not sequel databases.
Before drafting a new book, let the Architect establish enough world for its opening, inspect the deterministic checks, then accept the proposals into canon:
uv run litharness --database book.db --writer halloran architect seed
uv run litharness --database book.db world check
uv run litharness --database book.db world acceptworld accept is a recorded state transition, not a ranking step. After a chapter, architect grow reconciles and extends the same world through the same constrained tool surface.
One tick performs one bounded, restart-safe unit of work. The ordinary operating model is one
foreground process running ticks until interrupted:
.\tools\run-loop.ps1 -Database book.db -DelaySeconds 15Or run one unit directly:
uv run litharness --database book.db tickAccepted scene revisions, policy decisions, state extraction, follow-up evaluation, events, and library publication are committed through the SQLite store. A killed process leaves a reclaimable lease; replay converges rather than duplicating accepted work.
tick exits 0 after successful work or ordinary idleness, 1 when a unit failed or parked, and
2 for an operational fault. Budget ceilings are global options and are checked before provider
calls:
uv run litharness --database book.db \
--max-invocations-per-day 40 \
--max-tokens-per-day 500000 \
tickUseful operating views:
| Command | Purpose |
|---|---|
status [--json] |
queue depth, attention, daily usage, and spend |
jobs [--status parked] |
queued or blocked work |
why --scene N |
the prompt, decision, and evidence behind one scene |
events |
append-only state-change history |
plans |
immutable plan lineage and its proposals |
state, characters, world summary |
current canon and world state |
prompts [--role ROLE] |
labelled representative requests: role, material, schema, tools, and effective size |
prompts --role scene --scene N |
the exact frozen scene request, provenance, section pressure, omissions, and repeated material |
verify |
rebuild revisions and verify hashes and policy coverage |
backup PATH |
online SQLite backup, safe while ticking |
Run uv run litharness COMMAND --help for the authoritative option list.
Direction enters an inbox and becomes a new immutable plan revision before it can affect prose:
uv run litharness --database book.db directive \
"No combat in the midpoint." --kind constraint
uv run litharness --database book.db directives
uv run litharness --database book.db plansExplicit constraints and vetoes are preserved verbatim and locked. Interpretive notes receive one
bounded proposal whose scope, locks, and base revision are validated outside the model. Locked
author decisions travel at system authority after lower-authority writing aids. Raw chapter-reader
reactions never enter scene drafting or story planning. A qualified reader mechanism may instead produce an
immutable editorial intervention, and only satisfy or subvert interventions enter this same
machine-authored directive and plan-revision path; conflicts with locks are surfaced rather than
silently overridden.
Recovery is explicit:
revive JOB_IDreturns a parked unit to the queue after its blocker is cleared.replanissues still-draftable beats under a fresh plan epoch.revert-plan REVISIONrestores an earlier plan as a new head; history is never rewritten.revert REVISION --book ... --branch ...does the same for manuscript revisions.exceptionsandresolverecord cases policy could not settle; resolving does not requeue.
State records live at stable scene coordinates and retain the evidence span that established them. Model-facing views are projections of that ledger: a writer entering a scene sees the prior boundary; a caller stopped within a scene sees only facts whose evidence has already ended; a Director may see the latest accepted boundary; POV-restricted knowledge reaches only the named character. Superseded wants, standings, and other changing assertions are labelled as history instead of being presented beside their replacements as simultaneously current. The outline sees this projection at the arc's entry. Interpretive planning sees it through the furthest accepted scene together with accepted/draftable scene status and current-hash summaries; that lane cannot revise an accepted scene.
Chapter, arc, and fifty-chapter volume state are therefore derived snapshots, not separate editable sheets. SQLite revisions and events are authoritative. Git is appropriate for reviewed checkpoint exports and disaster recovery, but not as a second mutable canon database.
Character sheets expose only explicit reified actor/performed_by → caused_by → effect links;
a free-text want is never inferred to have caused an action. Promise rows can carry optional exact
opening and payoff spans when the summary answer supplies uniquely locatable quotes. Historical
or unlocated rows remain usable debts, but cannot become hidden answer keys in a reader battery.
Every candidate passes deterministic shape and integrity checks. Existing blocking findings park work before generation; candidate-local findings can trigger bounded, span-limited repair and independent re-detection. Findings below the blocking threshold annotate rather than spend another generation.
The in-process contradiction check runs automatically. The optional six-rule LitRPG pack can be connected through the ContinuityEvaluation executable:
$env:LITHARNESS_CONTINUITY_EVALUATOR = \
"C:\DEV\ContinuityEvaluation\.venv\Scripts\continuity-evaluate.exe"External evaluators enter through a shared EvaluationArtifact:
uv run litharness --database book.db ingest findings.json
uv run litharness --database book.db findings
uv run litharness --database book.db dismiss FINDING_IDdismiss records that an intentional device or false positive should no longer block; it does
not delete the finding.
The simulated readership can stop part-way through the latest drafted scene, or one named scene:
uv run litharness --database book.db readers
uv run litharness --database book.db readers --scene 4
uv run litharness --database book.db readers --historyThe request is no longer a cold scene: it includes earlier scenes in the current chapter, two recent chapters in full, compact current-hash memories from the preceding four chapters, and that same reader's previous stopping-point memory. The window stays bounded as the serial grows and never includes prose after the stop point. Reader output is behavioural—continuation, anticipation, abandonment—not a literary score. Reader roles are split between steering and measurement pools so a book shaped by a reader cannot later be certified by that reader. The architecture is wired, but its ability to perceive quality is still under validation; see the reader-architecture programme for current work rather than inferring validity from the existence of the command.
Automatic chapter checkpoints are opt-in:
uv run litharness --database book.db --reader-checkpoints tickThe four steering requests are frozen as durable jobs when the final scene of a chapter is
accepted. Their observations record the exact mechanism version, source revision and content
hash, persona/prompt/system/schema/context digests, provider, model, and response. The bundled
reader.anticipation.v0 mechanism is registered as experimental, so these records are inert:
they cannot enqueue editorial interpretation or affect planning. A later mechanism version may
be registered as qualified only with an evidence digest. Complete qualified panels are reduced
to one decision—satisfy, defer, subvert, refuse, or challenge_lock—before any direction
can reach the plan. A deterministic fingerprint check refuses directive bodies that repeat a
reader's six-word phrase (or an eight-word span from a longer answer), preventing the old
reader-vocabulary transcription failure from returning through the controller. Experimental and
qualified observations remain separate records even when they read the same scene. Registering a
new withdrawn version closes both future panels and already-queued controller work before spend.
Accepted target scenes record a durable realization linking intervention, directive, plan
revision, manuscript revision, and content hash; this proves the intervention reached prose, not
that it improved prose.
The remaining research boundary is executable without a model:
uv run litharness --database book.db reader-evidence-audit --out generated/reader-audit
uv run litharness --database book.db reader-mechanism status
uv run litharness --database book.db reader-mechanism qualify --evidence qualification.json
uv run litharness --database book.db reader-mechanism withdraw --reason "transfer regressed"The audit validates current-revision evidence spans, counts state, event, progression, character,
and promise candidates independently, classifies their anchor distance from adjacent chapter
through growing serial, and emits a prose-free registration manifest, unlabeled
battery.public.json packets, and a physically separate battery.private.json scoring key.
Damage and sham siblings must have identical shallow edit fingerprints. Qualification
accepts one closed evidence-artifact shape and requires held-out books and transformations,
memorisation and fingerprint controls, full-volume/cross-volume/growing-prefix results, transfer,
and the fixed operator acceptance test all to have passed. It never runs or trusts a model by
itself. The bundled mechanism remains experimental until such an artifact exists.
Listing appetite answers are likewise experimental evidence only. They remain in listing.json
but no longer have a renderer or revision path back into the listing writer.
Real readers are the reason to publish the books, but their behaviour never feeds generation, planning, selection, calibration, or gating.
Generate several independent cover options after the book exists:
uv run litharness --database book.db cover --variants 4
uv run litharness --database book.db cover --volume 2 --variants 4Codex produces text-free 2:3 art; LitHarness adds the exact title and publication author locally
and writes 400×600 PNGs plus a manifest under the book's library shelf. A volume run writes its
own set under volumes/VolumeN/covers/, marks that release in the prompt and manifest, and keeps
the same canonical book and revision identity. The default author is Skulitom. Use --art to
finish existing art without another generation, --reference for a layout reference, and
--art-direction or --description-file for volume-specific visual context. Covers are
generated, not ranked or critiqued.
The derived library is refreshed after each tick and skipped when the book head has not moved:
uv run litharness --database book.db library
uv run litharness --database book.db export book.md
uv run litharness --database book.db export book.htmlThe library contains a whole-serial reading copy, paste-ready chapter fragments, and derived
release volumes in globally numbered fifty-chapter windows. Change only the packaging with
--volume-chapters; state, promises, characters, revision identity, and chapter numbering remain
continuous across every boundary. An incomplete final volume means work in progress, not an
ending. Incomplete chapters are withheld from paste-ready output while reading copies show their
gaps explicitly. The library is a file handoff, not a posting scheduler or publication platform.
src/litharness/domain/— rules and value objects; imports only inward.src/litharness/application/— workflows over structural ports.src/litharness/adapters/— SQLite persistence and artifact translation.src/litharness/providers/— pinned model transport and deterministic fake.migrations/— append-only, checksummed SQLite migrations.tests/— behavior, architecture, replay, and safety contracts.research/quality-measurement/— isolated experiments and committed text-free results.plan/— active designs, experiment registrations, and historical decisions.runs/,book-library*/,exports/, and*.db— ignored local artifacts.
Read AGENTS.md and CONTRIBUTING.md before changing code. Use the four-second core loop for immediate feedback, or let the checker select a conservative slice from the working tree:
uv run python tools/check.py smoke
uv run python tools/check.py changedThe broader lanes are explicit and identical across platforms:
uv run python tools/check.py quick
uv run python tools/check.py fullBefore committing or handing off a completed change, run the comprehensive check:
uv run python tools/check.py handoffDirect pytest commands remain useful while debugging one failure; use -n 0 when ordering or
captured output matters. The architecture suite enforces dependency direction and import-cycle
freedom. Tests set LITHARNESS_ENV=test, which makes resolving a billing provider an error;
live provider tests are opt-in through LITHARNESS_LIVE_PROVIDERS=1.
