Skip to content

Architecture

A 60-second map of how the pieces fit. The design goal throughout: the brain on disk is the checkpoint, so runs are resumable without a graph framework or a running server.

Interfaces shell/ (interactive TUI — Rich + prompt_toolkit;
branding · help · commands · dashboard · chat ·
dispatch · slash · session · repl)
cli/ (one-shot CLI / python writingagent.py — a package)
webui/ (local web dashboard — stdlib ThreadingHTTPServer + SSE;
127.0.0.1 only, no auth, one job at a time)
Orchestrator orchestrator/ — durable on-disk state machine
(common · book · article · export · manage · review)
chapters/sections → consolidate → production → learn
(prefetches unit n+1's inputs · parallel commit batch)
agentic/ opt-in self-directing controller + learned trace policy (plan §21)
LLM layer nodes.py planner · writer · critic · judge · verifier · summarizer
extractor · humanizer · researcher · learner · diagram
craft/voice register · field · persona · emotion via the compositor (plan §22–23)
llm.py retry/backoff · JSON-repair retry · token telemetry
seo.py / promote.py SEO keyword pack + on-page audit · promo/restyle variants
OpenRouter DeepSeek V4 Pro / Flash, per-node routing (models.yaml)
Research (opt-in) search.py DuckDuckGo snippets
deep_research.py multi-query fan-out + full-page fetch (Scrapo / stdlib)
images.py Wikimedia Commons images
diagram.py deterministic SVG layout (built-in) + optional D2 / ELK
cache.py 7-day disk cache
The brain on disk brain/ markdown chapters · summaries · canon · skills · prefs
run_state.json atomic writes + resume guard
store.py SQLite FTS5 index + entity graph
Export export.py PDF · EPUB · DOCX · HTML · TXT · MD

Every step persists to the brain before the state machine advances. The unit chain is sequential (each unit reads the previous summary for continuity); everything independent of prose - research, images, skills, and the humanize/summarize/extract commit batch - runs concurrently.

ModuleResponsibility
orchestrator/The durable on-disk state machine - the brain is the checkpoint. A package behind a stable orchestrator/__init__.py facade (submodules: common · book · article · export · manage · review); orchestrator.X imports are unchanged
nodes.pyAll LLM node functions (planner, writer, critic, humanizer, …)
prompts.pyEvery system prompt, including the wrap_untrusted injection fence
schemas.pyPydantic structured-output schemas (validated with a repair retry)
llm.pyOpenRouter wrapper: retry/backoff, timeout, repair, token budget, cost tallies
telemetry.pyPer-call JSONL records with per-node + per-unit cost attribution + the /dashboard aggregation
seo.pyDeterministic on-page audit + a one-call flash keyword pack → seo_report.md (local artifact only - never posts)
promote.pyPlatform-native repurposing (x-thread, LinkedIn, …), voice restyle, and headline variants (local artifacts only)
brain.py / store.pyMarkdown filesystem layout + SQLite/FTS canon & entity graph
search.py / deep_research.py / images.py / cache.pyThe optional research stack
registers.py / craft.py / exemplars.py / fields.py / gold/*.mdThe craft engine - genre register profiles, deterministic craft metrics, few-shot exemplars, structural templates, and the gold style corpus (plan §22)
compositor.py / personas.py (+ personas/*.md) / emotions.pyThe voice cascade (register ⊃ field ⊃ persona ⊃ emotion ⊃ skills): selects one voice + resolves conflicts; 46 personas, 12 anti-cliché emotions (plan §23)
agentic/The opt-in self-directing controller - policies (default · llm · trace), an action trace, in-generation tools, and the learned policy (plan §21)
shell/ / cli/ / ui.pyRich TUI, one-shot CLI (both packages), and the 11-theme registry. shell/ is a package behind a stable shell/__init__.py facade (submodules: branding · help · commands · dashboard · chat · dispatch · slash · session · repl); shell.X imports are unchanged
webui/The local web dashboard (writing-agent web): a stdlib ThreadingHTTPServer + Server-Sent Events streaming a single-page app over the same engine - 127.0.0.1 only, no auth, one background job at a time
export.pyPDF · EPUB · DOCX · HTML · TXT · MD renderers (HTML sanitized)
brain/users/<user>/
profile.md prefs/ skills/
books/<book-id>/
plan.json book_plan.md toc.json run_state.json manuscript.md
chapters/ eval/ reviews/ instructions/
canon/characters/ world_rules.md timeline.md
frontmatter/ backmatter/ consolidation/
articles/<article-id>/
outline.json run_state.json manuscript.md sources.json
images/ ← SVG diagrams
config/
models.yaml ← per-agent model routing
settings.yaml ← all tunable knobs
.index/telemetry/ ← per-call JSONL records (local only)
seeds/skills/ ← built-in craft skills
DecisionWhat we choseWhy
OrchestrationDurable on-disk state machineBrain on disk = checkpoint; resumable runs without a graph framework
NodesDeterministic single-purpose LLM callsThe fixed pipeline’s nodes are deterministic and the orchestrator decides the sequence; the opt-in agentic controller (plan §21) layers self-direction on top, with the fixed pipeline as its fallback
Skill retrievalLexical (BM25) by defaultNo hard dependency on embeddings; clean seam to enable use_embeddings
CostBudget cost mode by defaultPins the spend-heavy knobs lean, routes judgment nodes (critic/judge/verifier/consolidation/diagram) to the cheaper flash tier, and applies a per-unit token budget - targeting ≤100k tokens/article with standard available when quality outranks spend
Prompt cachingNo context compressionContext-compression “headroom” was removed - it perturbed the cacheable prompt prefix and hurt the DeepSeek prompt-cache hit rate for ~no payoff on single-turn payloads
Diagram layoutModel authors a spec; Python lays it out (built-in), or D2 + ELK when installedNo overflow/overlap by construction; the built-in engine keeps it zero-dependency
FiguresDeterministic reconciliationGenerated diagrams are embedded into the manuscript deterministically; unused images and dropped items go to rejected.jsonl for review (the web Rejected tab), not silently discarded
Cross-platformpathlib, atomic os.replace, no required shelling outCI runs the full suite on Linux · macOS · Windows, Python 3.10–3.13
Module sizeorchestrator/ and shell/ are packages behind stable facadesA behavior-preserving split (preceded by a book↔article de-duplication of shared draft/critique/finalize/learner scaffolding); no file now exceeds ~1k lines, and orchestrator.X / shell.X imports are unchanged for callers

The conceptual flow that runs on top of this is in How it works. Contributors should start with plan.md (the spec) and the Contributing guide.