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.
79 lines
3 KiB
Markdown
79 lines
3 KiB
Markdown
# 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
|
|
|
|
```sh
|
|
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`.
|