Long-form story-writer with canon-keeping, sequel-continuity, and self-hosted narration. Database-is-source-of-truth — writer is the tooling.
Find a file
Cobb Hayes 346cea515d Public-flip audit: env-driven paths, scrub audit-ticket prefixes, terser README
Lucy bind paths + LAN host pins replaced with env defaults. Repository URLs
→ git.sulkta.com. Audit-changelog scaffolding stripped from inline comments
(technical reasoning preserved). README sheds marketing scaffolding. AI-speak
in load-bearing prompts/SOULs left alone — that IS the product.
2026-05-27 11:42:58 -07:00
docs Public-flip audit: env-driven paths, scrub audit-ticket prefixes, terser README 2026-05-27 11:42:58 -07:00
engines Public-flip audit: env-driven paths, scrub audit-ticket prefixes, terser README 2026-05-27 11:42:58 -07:00
migrations forge: dedup pass — the fix half of the audit loop 2026-05-15 14:49:08 -07:00
seeds/authors v0.3 step 2: Orson Black soul + author-aware forge + skald continue CLI 2026-05-13 12:06:28 -07:00
skald Public-flip audit: env-driven paths, scrub audit-ticket prefixes, terser README 2026-05-27 11:42:58 -07:00
skald-core Public-flip audit: env-driven paths, scrub audit-ticket prefixes, terser README 2026-05-27 11:42:58 -07:00
vendor/clawdforge forge: always --effort max + multi-chapter batch (cap 20) 2026-05-13 14:26:53 -07:00
.gitignore scaffold v0.1: postgres+pgvector inside-container, schema, markdown ingest, CLI 2026-05-13 09:04:28 -07:00
Cargo.lock multi-voice: per-character dialogue rendering 2026-05-14 08:35:33 -07:00
Cargo.toml Public-flip audit: env-driven paths, scrub audit-ticket prefixes, terser README 2026-05-27 11:42:58 -07:00
compose.yml Public-flip audit: env-driven paths, scrub audit-ticket prefixes, terser README 2026-05-27 11:42:58 -07:00
Dockerfile Public-flip audit: env-driven paths, scrub audit-ticket prefixes, terser README 2026-05-27 11:42:58 -07:00
entrypoint.sh Public-flip audit: env-driven paths, scrub audit-ticket prefixes, terser README 2026-05-27 11:42:58 -07:00
LICENSE Public-flip audit: env-driven paths, scrub audit-ticket prefixes, terser README 2026-05-27 11:42:58 -07:00
README.md Public-flip audit: env-driven paths, scrub audit-ticket prefixes, terser README 2026-05-27 11:42:58 -07:00

skald

Long-form story-writer with canon-keeping, sequel continuity, and self-hosted audiobook narration. The database is the source of truth; the binary is the tooling.

Named for the Old Norse poets who composed and memorized kings' sagas across generations.

What's wired

  • Rust workspace (skald-core + skald)
  • Postgres schema for stories, characters, canon facts, chapters, passages, generation runs, audit findings, tags
  • pgvector for future similarity search
  • skald import-markdown ingests a story file (chapters + bible)
  • skald serve exposes /health + the web inspector and runs migrations on boot
  • skald continue runs gen → cleanup → audit per chapter, with multi-chapter batching (cap 20)
  • skald rewrite re-authors a chapter in a named author's voice
  • skald audit runs whole-story prose-quality audit; skald dedup is the surgical fix half of the loop
  • skald prepare-narration annotates a chapter with [breath] / [pause:Xs] / [scene] beats and per-character [voice:...] tags
  • skald narrate renders a chapter to audio via one of three TTS engines (F5-TTS, Kokoro-82M, Tortoise-TTS) — see engines/
  • Named-author "soul" personas via skald authors seed; author voice replaces the model's base system prompt for gen/cleanup/ rewrite/dedup/narrate_prep

Schema (cheat sheet)

stories             meta + status + parent/root for series
authors             persona identity (slug, display_name, model)
author_revisions    versioned souls; one current per author
characters          real or fictional, story-scoped, voice-mappable
canon_facts         setting, mystery, theme, rule, historical_anchor, hook
chapters            full prose body + optional body_md_tts annotation
chapter_summaries   short summaries for cheap context loading
passages            paragraph-level + embedding vector(1536)
voices              TTS voice rows (F5 ref clips / Kokoro / Tortoise names)
pronunciation_overrides  per-story + global respellings for proper nouns
generation_runs     every LLM call logged
audit_findings      audit pass output (severity + area)
narration_runs      per-chapter TTS renders

Quickstart

docker compose up -d
docker exec skald skald import-markdown --path /seed/<story>.md \
    --title "<title>"
curl http://localhost:7780/health

The compose file expects POSTGRES_PASSWORD and (optionally) CLAWDFORGE_URL + CLAWDFORGE_TOKEN in .env. Story markdown goes into ./seed/; postgres data persists in ./pgdata/.

Architecture

v0.1 ships postgres inside the skald container — singleton until the tool stabilises. To extract postgres later, swap the runtime base to debian:bookworm-slim, drop entrypoint.sh, and point DATABASE_URL at the external pg. The binary doesn't care where the DB lives.

The generation passes call out to clawdforge (a bearer-token-gated HTTP wrapper around claude -p). The Rust client is vendored at vendor/clawdforge/. TTS calls go HTTP+JSON to the per-engine sidecars under engines/.

License

MIT — see LICENSE.