The file footprint
The complete footprint of the solution — every file, and what it is for. Seven Rust crates make the binary, one Django app makes the Yard, and a small tools directory holds the vendored assets. Nothing else is hiding anywhere.
The repo root
C:\ai\workspace\keel\
Cargo.toml the workspace: members, shared deps, THE version (x.y.z single source)
Cargo.lock pinned dependency graph
CHANGELOG.md the recorded history — shown by keel changelog, the TUI overlay, and /changelog
BACKLOG.md decisions, milestones, the owner's kept feature picks
docker-compose.yml the Yard + Postgres 16, one `docker compose up` from zero
start-keel.ps1 the one-file entry: builds, starts the Yard if needed, opens the sample
.gitignore target/, novels/, .keel-home/, python artifacts
.dockerignore keeps target/ and git out of the image
novels\ your series live here (git-ignored)
.keel-home\ credentials/session when launched via the starter (git-ignored)
temp\ untracked scratch (screenshots) — not part of the solution
crates/keel-core — the pure domain
Everything Keel knows lives here, with zero I/O: the spine, the ledger, Plank, page geometry, the canonical file forms. Its test suite runs with no fixtures on disk — the design's testability anchor.
crates\keel-core\
Cargo.toml deps: serde, yaml/toml, similar, thiserror — no I/O crates, by rule
src\lib.rs module map + re-exports
src\id.rs ObjectId + kinds — filename-safe ids, prefix carries the kind
src\model.rs BeatCard, statuses, the write-gate functions, entities, frames
src\spine.rs SpinePath (position from id), Spine, frontier, synopsis, sparkline
src\time.rs StoryTime with era precision; unix formatting; day parts
src\calendar.rs the five-era calendar, story-time validation, the total order
src\ledger.rs facts, promises, refs, the two clocks, blast radius
src\plank.rs the markup: parser events, fmt (bare @end), strip (CommonMark)
src\typst.rs Plank → Typst emission for the book pipeline
src\context.rs Davy's recipe: pinnable sections S1–T2, token estimates
src\geometry.rs trim/margins/face → 62 chars × 34 lines × ~300 words/page
src\files.rs canonical parse/serialize for every file form + the seeds
src\diff.rs word-level diff (line diffs on prose are unreadable)
crates/keel-store — strict RCS over SQLite
crates\keel-store\
Cargo.toml rusqlite (bundled), zstd, blake3
src\lib.rs module map
src\store.rs the Store trait — one schema, Local now, Yard next
src\schema.sql objects · revisions · locks · changesets, monotonicity trigger
src\local.rs LocalStore: exclusive locks, MAX(rev)+1, loud stale-base, changesets
src\error.rs every failure named: Locked, StaleBase, PendingInChangeset…
crates/keel-prose — the Helm, the editor
The hand-built prose widget — the project's flagged biggest risk, fenced to six requirements and finished.
crates\keel-prose\
Cargo.toml ropey, ratatui, unicode-width
src\lib.rs the pinned public surface
src\view.rs the Helm state: rope, cursor, selection, decorations, focus
src\wrap.rs soft wrap at display columns, per-line cache
src\keys.rs vim-lite modal keys (normal/insert/visual, the fenced set)
src\journal.rs flat undo/redo with same-word coalescing
src\render.rs typewriter offset, decoration merge, cursor cell
tests\the Helm.rs the public-API suite: motions, undo, search, wrap, dimming
tests\markup_api.rs selection wrap + block insertion (the ^m palette's hooks)
crates/keel-tui — the C shell
crates\keel-tui\
Cargo.toml ratatui, crossterm, spellbook, keel-prose, keel-client
src\lib.rs AppData assembly from the store; run_at / run_standalone
src\app.rs the pure reducer: views, lenses, palettes, overlays — all testable
src\event.rs the blocking loop: key routing, DAVY drain, F5 render, refresh
src\session.rs WriteSession: checkout/resume/read-only, save, spell tick, ✎%
src\login.rs the centered editor login (F2 dev mode, Esc quit)
src\picker.rs the series picker for a bare keel.exe outside any workspace
src\console.rs the : command console — any keel command, run in place
src\DAVY.rs recipe gathering + the live stream state + provenance
src\spell.rs spellbook + the project dictionary → misspelling ranges
src\editor.rs $EDITOR handoff (suspend, spawn, reload)
src\term.rs TerminalGuard: restore on exit AND on panic
src\ui\mod.rs layout: bordered head/rail/content/foot, panels, overlays
src\ui\head.rs breadcrumb, mode badge, the beat contract line, ◉ editor
src\ui\rail.rs lens tabs + per-lens content + the split detail box
src\ui\foot.rs words · rev · lock · flags · key hints
src\ui\views.rs per-view centers: map preview, codex, ledger, review, write
src\ui\worldline.rs the era-segmented timeline, both modes, scroll math
src\ui\DAVY.rs the ^g panel: instruct/inspect/stream/review
src\ui\markup.rs the ^m contextual markup palette with preview
src\ui\palette.rs the ^p command palette
src\ui\console.rs the console output overlay
src\ui\help.rs the ? help — the manual inside the tool
src\ui\changelog.rs the changelog overlay (embedded at build time)
crates/keel-client — AI and the Yard, over the wire
crates\keel-client\
Cargo.toml tokio, reqwest, eventsource-stream — async lives HERE only
src\lib.rs module map
src\provider.rs the AiProvider contract: stream events over a sync channel
src\direct.rs the raw Messages API: JSON + SSE, cache_control, no SDK
src\mock.rs the offline provider (KEEL_AI_MOCK) — every test runs without a key
src\usage.rs model routing per agent + the cost meter's math and log
src\creds.rs stored Yard credentials (shared by login and the TUI screen)
src\yard.rs Yard HTTP: token login, session validation
src\context_cache.rs small pure helpers (day boundaries for the meter)
tests\mock_stream.rs byte-exact mock streaming + provider selection
crates/keel-index — derived data, rebuildable
crates\keel-index\
Cargo.toml rusqlite
src\lib.rs deterministic rebuild: docs + FTS5 + refs; search; dict.txt
tests\determinism.rs byte-identical rebuilds — the discipline test
tests\search.rs bm25 hits, snippets, query wrapping
tests\dict.rs sorted dictionary generation from the loft
crates/keel — the binary
crates\keel\
Cargo.toml clap + every crate above
src\main.rs entry: color-eyre, dispatch, exit codes
src\cli.rs the whole command surface (see the CLI reference)
src\exit.rs error → exit-code mapping (3 locks, 4 integrity)
src\workspace.rs workspace discovery, working-file paths, identity
src\spine_load.rs store → Spine, loudly
src\ledger_io.rs ledger load/save under locks, next-id, narrative positions
src\commands\ one file per verb:
init.rs co.rs ci.rs log.rs diff.rs status.rs the RCS lifecycle
new.rs synopsis.rs frames.rs the spine
proofread.rs plank.rs the writing chain
fact.rs promise.rs extract.rs the ledger
amend.rs blast radius · land · abandon · list
render.rs export.rs snapshot.rs stats.rs the book and its numbers
search.rs index.rs geometry.rs derived data
ai.rs voice.rs Davy from the CLI
login.rs changelog.rs auto_novel.rs session · history · the sample
tests\ end-to-end against the real binary:
cli_roundtrip.rs index_determinism.rs M0 acceptance
m1_loft.rs m2_spine.rs m3_plank.rs per-milestone suites
m5_ai.rs m6_ledger.rs m7_launch.rs
m7_proofread.rs m8_login.rs m8_auto_novel.rs
typst_geometry.rs 62×34 vs real renders (ignored by default)
yard/ — the web admin
yard\
Dockerfile python-slim image: migrate, seed admin, serve
manage.py Django entry
requirements.txt django, django-ninja, psycopg, blake3, zstandard, pytest-django
pytest.ini test config (sqlite for speed)
yard\settings.py DATABASE_URL or sqlite; version parsed from Cargo.toml
yard\urls.py admin · api · docs · changelog · preview routes
yard\asgi.py wsgi.py servers' entries
core\apps.py the app config
core\models.py Series, KeelObject, Revision, Lock, Changeset, Token, PreviewPdf
core\store.py the semantics engine — mirrors local.rs checkin exactly
core\api.py django-ninja endpoints with machine-readable error codes
core\admin.py KEEL-branded Django admin registrations
core\views.py docs sections, changelog page, preview serving
core\context_processors.py the version into every template
core\management\commands\seed_admin.py the idempotent MVP login
core\migrations\ 0001 the schema · 0002 preview PDFs
core\tests\test_api.py parity + auth + preview (pytest)
templates\base.html the site shell: palette, favicon, header, version
templates\changelog.html the rendered changelog
templates\docs.html superseded placeholder (pre-docs-shell; unused)
templates\docs\ THIS documentation: base_docs.html + one file per chapter
templates\admin\base_site.html admin branding + palette
templates\admin\login.html the login page: home link + the test credentials
tools/ and docs/ — assets and the founding papers
tools\
typst\book.typ the book template: B-format, running heads, the 13.6pt grid
typst\geometry-check.typ the acceptance harness that pins 62×34 against real renders
fonts\EBGaramond\ the book face, vendored (OFL license alongside)
dictionaries\en\ hunspell en dictionary powering spellcheck (index.aff/.dic)
docs\
keel-spec.html the design spec, rev 0.7 — where all of this was decided
keel-surfaces.html the three surface mocks the UI was built to
calendar-draft.yaml the settled world-calendar structure
verification-m0.md the M0 acceptance walkthrough
Reading order for the curious:
keel-core/src/model.rs for the shape of the thing, keel-store/src/local.rs
for how nothing is ever lost, then keel-tui/src/app.rs for how it all
drives. The spec in docs/ is the long answer to every "why".