Narrarium Framework is a local-first writing stack built around three pieces:
- a strict but extensible repository convention where the repository is the book
- a local MCP server that teaches OpenCode or Claude how to create, search, validate, and enrich that repository
- an Astro-based reader that turns the repository into a browsable site and EPUB pipeline
packages/core: schemas, templates, repo scaffolding, search, validation, and EPUB export helperspackages/sdk-typescript: dedicated TypeScript SDK package for remote GitHub and Azure DevOps book accesspackages/mcp-server: local stdio MCP server for OpenCode, Claude Desktop, and compatible clientspackages/create-narrarium-book: starter CLI to scaffold a new book repository from the terminalpackages/astro-reader: Astro reader with spoiler-safe public mode, full canon opt-in, EPUB export, and doctor tooling
The intended workflow is local-first:
- OpenCode runs with the local Narrarium MCP server enabled.
- You ask for book tasks in natural language.
- OpenCode calls Narrarium MCP tools to scaffold the repository, create entities, create chapters, search canon, validate metadata, and optionally fetch Wikipedia research.
- The same repository can then be rendered as a website or exported to EPUB.
This keeps the actual writing artifacts in your filesystem instead of hiding them inside a hosted app.
If you just want to use Narrarium, start from the published packages:
npx create-narrarium-book my-book --title "My Book" --language en
cd my-book
npm run dev
npm run doctorThis scaffolds a book repo, creates reader/ by default, installs the reader dependencies, prepares OpenCode config, and gives you a live reading site plus EPUB export while you write.
The generated root scripts include npm run dev, npm run build, npm run export:epub, and npm run doctor.
If you want sample content from the start:
npx create-narrarium-book my-book --title "My Book" --language en --sampleIf you want a book repo without the reader scaffold:
npx create-narrarium-book my-book --title "My Book" --language en --no-readerThe starter also has an interactive mode:
npx create-narrarium-bookTo refresh the managed Narrarium scaffolding inside an existing repo:
npx create-narrarium-book --upgrade .The upgrade also migrates legacy story prose links like [Mariamne](../../characters/mariamne-ii/) into plain-text canon mentions so the reader can link visible names itself.
Add --with-reader if you also want to refresh the generated reader scaffold and root convenience files.
npx narrarium-mcp-serverIf the package is already installed in the project or globally, the binary is:
narrarium-mcpCreate a standalone Astro reader app inside or beside a book repo:
npx narrarium-astro-reader reader --book-root .. --package-name my-book-reader
cd reader
npm install
npm run devThe reader includes dedicated indexes for chapters, characters, locations, factions, items, secrets, and timeline events. npm run dev watches the linked book repo, refreshes the EPUB, and triggers a full browser reload when canon changes.
By default the generated reader runs in a spoiler-safe public mode:
- secret pages stay out of the public atlas and nav
- direct canon pages fall back to teaser or locked views when
known_fromorreveal_insay the lore is not safe yet - search, popups, and canon backlinks respect the same thresholds
- chapter and scene prose should keep canon names as plain text; the reader upgrades visible mentions into spoiler-safe popups and links automatically, including legacy internal canon links during runtime
For author-only or spoiler-friendly deployments, set one of these before building or running the reader:
NARRARIUM_READER_CANON_MODE=full
# or
NARRARIUM_READER_ALLOW_FULL_CANON=trueIf you want EPUBCheck validation during export or build, also set one of these:
EPUBCHECK_CMD=epubcheck
# or
EPUBCHECK_JAR=/absolute/path/to/epubcheck.jarThese commands are for working on the Narrarium framework repository itself:
npm install
npm run buildRun the automated test suite with:
npm run testFor a publish-ready workspace check:
npm run release:checkBuild the GitHub Pages documentation site locally with:
npm run docs:buildRepo-only helper commands:
npm run create:book -- my-book --title "My Book" --language en --sample
npm run dev:mcp
npm run reader:init -- reader --book-root .. --package-name my-book-readerIf you want the public HTTP version locally, for Vercel-style setup and research flows:
npm run dev:http -w narrarium-mcp-serverThis serves:
http://localhost:3000/mcphttp://localhost:3000/health
An example project config lives in opencode.jsonc and points OpenCode to the local MCP server build output.
It also tunes the default build and plan agents for book work with higher reasoning effort, detailed summaries, and more verbose responses while keeping temperature moderate for canon consistency.
Generated book repos also point instructions to .github/copilot-instructions.md, so OpenCode and Copilot share the same repository-specific writing workflow.
Generated book repos also include context.md for stable historical, geographic, social, and world-context notes that should stay visible while writing chapters and scenes.
Generated book repos also include ideas.md, story-design.md, notes.md, and promoted.md so unstable ideas, reviewed notes, structural design, and promoted archive items stay separate. Chapter-local variants live under drafts/<chapter>/ and are created when draft work starts.
Generated book repos now use guidelines/writing-style.md as the single always-on writing and review guide. Optional chapter-specific writing-style.md files can live beside a chapter or chapter draft when that chapter needs a local override.
The Astro reader now exposes an author-facing Workshop area in full canon mode so you can inspect drafts, ideas, notes, story design, and promoted items alongside the published canon pages.
Book repos also include conversations/ as a portable place to keep exported writing chats.
The generated .opencode/plugins/conversation-export.js plugin updates conversations/RESUME.md, conversations/CONTINUATION.md, and per-session exports automatically when OpenCode sessions go idle.
The generated /resume-book command and MCP tool resume_book_context help you restart from repo state on a fresh machine or session, including context.md, plot.md, resumes/, and state/ snapshots when present. /resume-book also supports scoped targets such as a chapter or paragraph, for example /resume-book chapter:002-ledger-suspicion 002-tense-exchange.
Project-level OpenCode and agent rules live in AGENTS.md.
These are the main building blocks exposed by the local MCP server:
init_book_repo: scaffold a book repository in a target foldersetup_framework: return the exactnpxcommands to bootstrap a new Narrarium projectrepository_spec: return the repo model and canon rulescharacter_wizard: return the checklist of fields needed for a full charactercreate_character: create a rich character file with voice, role, backstory, and function in booklocation_wizard,faction_wizard,item_wizard,secret_wizard: return the checklist for each canon typetimeline_event_wizard,chapter_wizard,paragraph_wizard: return the checklist for those creation flowschapter_writing_context,paragraph_writing_context,resume_book_context: assemble the context to resume or write book prose safelycreate_location,create_faction,create_item,create_secret,create_timeline_event: create rich canonical files for those typesstart_wizard,wizard_answer,wizard_status,wizard_finalize,wizard_cancel: run a true multi-step guided creation sessioncreate_entity: create faster stubs for other canon filesupdate_chapter,update_paragraph: update existing chapter and scene files without structural migrationupdate_entity: patch frontmatter and body on existing canon filescreate_asset_prompt,register_asset,generate_asset_image: manage canonical art prompts and image filesrename_entity,rename_chapter,rename_paragraph: rename canon safely and move matching asset folders toosearch_book: search the repository before inventing canonquery_canon: answer natural-language canon questions using state, resumes, chapters, and fallback search, including locations, knowledge, inventory, relationships, conditions, open loops, secret holders, first appearances, and chapter-range evolution queriesrevise_paragraph: propose a targeted editorial pass for a final scene without writing files, and suggeststate_changesreview when continuity-sensitive beats are involvedrevise_chapter: propose a chapter-level editorial pass with diagnosis and scene-by-scene suggestions, again without writing files automaticallylist_related_canon: find files that reference an id or conceptsync_resume: refresh chapter or total summaries from current filessync_all_resumes: refresh all chapter resumes plus the total summary in one passevaluate_chapter: refresh a full chapter evaluation using all paragraph text, active style rules, scores, and next stepsevaluate_paragraph: refresh one paragraph evaluation while still reading the whole chapter as contextevaluate_book: refresh the full-book evaluation and optionally all chapter and paragraph evaluationswikipedia_searchandwikipedia_page: research factual or historical materialexport_epub: turn the repository into an EPUB
Final chapter and paragraph mutations through the MCP layer auto-refresh plot.md, the per-chapter resumes, and resumes/total.md. Structured story state stays manual on purpose: rewrites mark state/status.md as dirty, then you decide when to run sync_story_state. Evaluations stay manual so critique remains explicit.
For factual or historical work, Narrarium now checks existing research/wikipedia/ snapshots first and reuses them before fetching Wikipedia again when it can. If you need a refresh, use forceWikipediaRefresh or limit reuse with maxWikipediaSnapshotAgeDays.
Narrarium now separates two continuity layers:
resumes/stays human-readable and narrative-firststate/stores structured continuity snapshots for agents, checks, and continuity review
The intended workflow is:
- Write or revise chapter and paragraph prose.
- Let Narrarium auto-refresh
plot.mdand the resume files. - Record chapter-specific structured deltas in
resumes/chapters/<slug>.mdunderstate_changesfrontmatter. - Run
sync_story_statemanually when you want refreshed continuity snapshots.
That produces:
state/status.md: whether story state is stale, when it was last mutated, and which files changedstate/current.md: the latest consolidated continuity snapshotstate/chapters/*.md: per-chapter structured snapshots after applying each chapter delta in order
Recommended state_changes keys in chapter resumes:
locationsknowledge_gainandknowledge_lossinventory_addandinventory_removerelationship_updatesconditionswoundsopen_loops_addandopen_loops_resolved
doctorBook() and npm run doctor now warn if state/ is missing or stale, and writing-context tools read state/current.md plus state/status.md when available.
For continuity questions and range-based canon queries, see docs/query-canon.md.
For proposal-only editorial revision passes on final scene files, see docs/revise-paragraph.md.
For chapter-level proposal-only editorial passes, see docs/revise-chapter.md.
For explicit per-chapter style overrides with book-level fallback, see docs/style-profiles.md.
With the local MCP server and OPENAI_API_KEY configured, a typical image workflow looks like this.
| Use case | Subject | Asset path | Typical tool flow |
|---|---|---|---|
| Book cover | book |
assets/book/cover.* |
register_asset or generate_asset_image |
| Character portrait | character:lyra-vale |
assets/characters/lyra-vale/primary.* |
create_asset_prompt -> generate_asset_image |
| Chapter art | chapter:001-the-arrival |
assets/chapters/001-the-arrival/primary.* |
create_asset_prompt -> generate_asset_image |
| Scene art | paragraph:001-the-arrival:001-at-the-gate |
assets/chapters/001-the-arrival/paragraphs/001-at-the-gate/primary.* |
generate_asset_image directly or after create_asset_prompt |
Create a reusable character portrait prompt:
{
"tool": "create_asset_prompt",
"arguments": {
"rootPath": "C:/books/my-book",
"subject": "character:lyra-vale",
"body": "# Intent\n\nPrimary portrait for Lyra.\n\n# Prompt\n\nPortrait of Lyra Vale, guarded expression, harbor fog, muted cinematic palette, portrait composition, 2:3 ratio.\n\n# Notes\n\nKeep facial features consistent across future chapter and scene art.",
"orientation": "portrait",
"aspectRatio": "2:3"
}
}Generate the actual image into assets/characters/lyra-vale/primary.png:
{
"tool": "generate_asset_image",
"arguments": {
"rootPath": "C:/books/my-book",
"subject": "character:lyra-vale",
"provider": "openai",
"model": "gpt-image-1"
}
}Generate a scene image directly for a paragraph:
{
"tool": "generate_asset_image",
"arguments": {
"rootPath": "C:/books/my-book",
"subject": "paragraph:001-the-arrival:001-at-the-gate",
"prompt": "Lyra arriving at Gray Harbor's gate in cold fog, suspicious guards, cinematic portrait framing, book-cover quality illustration, 2:3 ratio.",
"provider": "openai",
"model": "gpt-image-1"
}
}Import an image you created elsewhere into the canonical assets tree:
{
"tool": "register_asset",
"arguments": {
"rootPath": "C:/books/my-book",
"subject": "book",
"assetKind": "cover",
"sourceFilePath": "C:/renders/my-book-cover.png",
"body": "# Intent\n\nMain book cover.\n\n# Prompt\n\nFinal cover prompt used for the external render."
}
}Generate chapter art into assets/chapters/001-the-arrival/primary.png:
{
"tool": "generate_asset_image",
"arguments": {
"rootPath": "C:/books/my-book",
"subject": "chapter:001-the-arrival",
"prompt": "Lyra approaching Gray Harbor through cold fog, chapter-opening illustration, portrait orientation, dramatic negative space, consistent with the book's visual language.",
"provider": "openai",
"model": "gpt-image-1"
}
}The recommended place for reusable style rules and prompt templates is guidelines/images.md.
When you store asset metadata, prefer adding alt_text and caption in the asset markdown frontmatter so the web reader and EPUB can render accessible descriptions and captions consistently.
The Astro reader now auto-renders these canonical assets when present for:
bookcover on the home page- entity detail pages such as characters, locations, factions, items, secrets, and timeline events
- chapter pages and paragraph or scene sections
In public reader mode, those canon surfaces still respect known_from and reveal_in before exposing full details.
If you later rename canon with rename_entity, rename_chapter, or rename_paragraph, Narrarium also moves the matching asset folders.
The current repository convention is documented in docs/repository-spec.md.
The final public package set is:
narrariumnarrarium-sdknarrarium-mcp-servercreate-narrarium-booknarrarium-astro-reader
The public package line started at 0.1.0; current workspace versions may be newer.
Publishing notes and release order live in docs/publishing.md.
Two workflows are included:
.github/workflows/ci.yml: runs build, validation, and tests on pushes and pull requests.github/workflows/publish-npm.yml: auto-publishes bumped package versions onmain, with manual dispatch and GitHub Release as fallbacks.github/workflows/deploy-vercel-mcp.yml: deploys the public HTTP MCP endpoint to Vercel.github/workflows/deploy-docs-pages.yml: builds and publishes the documentation site to GitHub Pages
Current production domains:
- docs site:
https://narrarium.net - public MCP endpoint:
https://narrarium.space/mcp - public MCP health:
https://narrarium.space/health
To enable npm publishing from GitHub:
- Add the repository secret
NPM_TOKENusing an npm Automation token - Ensure the npm account behind the token can publish the chosen unscoped package names
- Bump the package versions and merge that change to
main
On main, the publish workflow compares local package versions against npm and only publishes versions that are not already online.
When it finds unpublished versions, it runs npm run release:check first, then publishes in dependency order.
If GitHub Actions fails with EOTP, the token is not suitable for CI publish with 2FA enabled. Replace it with an npm Automation token or move this repo to npm Trusted Publishing.
If GitHub Actions fails with E404 while publishing narrarium or the other public packages, double-check the package names, registry, and authenticated npm account.
For the Vercel deploy workflow, add this repository secret:
VERCEL_TOKEN
The workflow is already pinned to:
VERCEL_ORG_ID=team_Jut3umUxSp1D1Z1sqmv4iUjcVERCEL_PROJECT_ID=prj_b9bxn0P4ilMmG40DiZoZ057qA1Zj
For local or CI image generation with generate_asset_image, also set:
OPENAI_API_KEY
This repository now includes a Vercel-ready public MCP endpoint:
api/mcp.tsapi/health.tsvercel.json
After deploying the repo to Vercel, the public endpoints are:
/mcp/health
Important: the Vercel deployment is intended for setup guidance, repository spec guidance, and Wikipedia research. Actual local filesystem writing still belongs to the local stdio MCP server.