Story Maintenance
Overview
Run deterministic maintenance for Story Skills projects. Use the CLI for structure validation, registry rebuilds, word counts, link checks, continuity checks, project reports, next-action reports, pacing, clue, voice, and name checks, revision-pass tracking, Mermaid diagrams, schema migration, entity helpers, manuscript import, and manuscript export and builds. The creative skills still own story decisions; this skill handles mechanical consistency.
CLI Access
Prefer the first available command:
story <command>- when the package bin is installedbun run story -- <command>- when working from this repositorynode scripts/story.js <command>- bundled fallback, resolvingscripts/story.jsrelative to this skill folder
If none of these are available, perform the requested maintenance manually using the conventions in story-init.
Run the installed or bundled CLI in place. Do not copy scripts/story.js into the user's story project, and do not create project-local build scripts, generator scripts, or bulk writer scripts to generate story content. Story projects should remain markdown-first, plus explicitly requested exports such as dist/manuscript.md.
Commands
Run commands from the story project root, or pass the story path explicitly.
story validate .
story reindex .
story wordcount . --write
story links .
story continuity .
story prose .
story voices .
story pacing .
story clues .
story timeline .
story passes .
story passes . --init
story passes . --start structure
story passes . --done structure
story names "Mira" "Kelvos"
story diagram relationships
story diagram locations --out dist/locations.mmd
story diagram timeline
story diagram clues
story diagram arcs
story progress . --log
story compare . --ref draft-1
story compare . --against ../book-draft-1
story compare . --ref beta-round-1 --anchor ch03-p12
story similarity . --against ../book-one
story series .
story import draft.md --title "Title"
story report .
story report . --actionable
story next .
story doctor .
story migrate .
story add character "Name"
story add character "Пётр" --id petr
story add matter "Dedication"
story add research "Tidal bore timing" --source "Tide tables 2024" --used-in chapter-03
story add research "Night shift on a cardiac ward" --method interview --accuracy must-be-accurate --confidence medium --risk medical
story add matter "Acknowledgments" --placement back
story rename character old-id "New Name"
story rename character petr "Пётр Иванов" --id petr-ivanov
story move chapter chapter-04 --number 5
story move scene chapter-03-scene-02 --chapter chapter-05
story move scene chapter-03-scene-02 --scene 1
story remove promise old-promise
story export . --out dist/manuscript.md
story build . --format markdown
story build . --format epub
story build . --format docx
story build . --format shunn
story build . --format docx --shunn
story build . --format html
story build . --format print --trim 6x9
story build . --format narration
story build . --format metadata
story build . --format twee
story build . --format ink
story knowledge sera-voss --at chapter-04
story continuity . --json
story context chapter-04 --budget 6000
story add clue "The silver locket" --planted chapter-02 --payoff chapter-05
story synopsis --pages 1
story synopsis --pages 3 --out dist/synopsis.mdUse:
validateafter initialization and at the end of any multi-file editreindexafter adding, removing, renaming, or moving any entity file. It rebuilds the character, location, system, faction, artifact, arc, chapter, scene, question, promise, clue, and glossary registries.story addreindexes itself; a hand-written file does notwordcount --writeafter writing or revising chapterslinksafter changing character relationships, notable locations, arc participants, or chapter referencescontinuityafter drafting or revising a chapter, and whenever the user asks about contradictions, dead characters appearing, unfired setups, or stale state; it deterministically checksdied-inordering (and warns when a characterdeceasedwith nodied-in, dead before the story, is in a cast;revived-inends the dead window, adied-inoutline chapter is a planned death that may keepstatus: alive, apovalso inmentionsis a posthumous narrator rather than an appearance, and chapters dated on both sides compare by story date, not number; a characterstatusprogression todeceasedwith nodied-incounts as the death for later casts and learning, and a status progression that contradictsdied-inorrevived-inwarns), promise/question chapter ordering, Chekhov gaps, POV/cast consistency,status: cutcharacters still listed in a chapter or scenepov/characters, an arc'scharacters, or a relationship (warnings), andcontinuity/state.mdreferences, plus warnings wherecontinuity/state.mddisagrees with scenestate-changes(acharacter+knowledgechange with noknowledge-stateentry learned by that chapter, an artifactowner/locationset by a later scene), with deaths (knowledge learned after dying,character-statefor a dead character), or with casts (alearned-inchapter that does not list the learner, acharacter-statelocation thecurrent-chapternever visits). It reuses the promise-ordering machinery for the clue ledger (continuity/clues/): payoff before plant is an error (also when the planted chapter is a scheduledchapter-NNnot written yet), and a completed story with planned or planted clues is an error. The Chekhov warning requiresstatus: planted: it fires as soon as a recorded payoff chapter has been drafted, or, with no payoff recorded, once three or more chapter files follow the plant (positions, not chapter numbers).story add clue --planted(andstory add promise --planted) records the chapter and setsstatus: plantedwhen that chapter exists; with--plantednaming a chapter not written yet, or without--planted, the status isplanned, and--statusoverrides either default. A promise or clue withstatus: plannedand aplantedchapter warns ("records planted chapter X but status is still planned") only once chapter X has prose, so--status planned --planted chapter-NNschedules a setup ahead. Both warnings read the named chapter's ownstatus: anoutlineplanted or payoff chapter does not count as drafted, even when later chapters are. A recorded payoff chapter that is not drafted yet suppresses the "no payoff yet" warning.story linksaccepts a scheduledchapter-NNthat has no chapter file yet inpayoff, inplantedwhile the status isplanned, and in a research note'sused-in, unless its number is 0 or belongs to an existing chapter under another id (chapter-1besidechapter-01is reported as missing); once the status isplantedorpaid-offthe planted chapter must exist, and oncepaid-offthe payoff chapter must too. It also checks prop custody — artifacts withdestroyedorloststatus must not be referenced after their destruction chapter (recorded in object-statesince: chapter-NN; later scenes referencing them instate-changesormentionsare errors; an entry with nosincewas destroyed or lost before the story, so any scenestate-changesusing it is an error whilementionsstay allowed; a later entry for the same artifact with another status and a latersinceends a loss) — and clock/time plausibility when scenes or chapters carrydate: YYYY-MM-DD/time: HH:MMfrontmatter (time may bedawn,morning,midday,afternoon,evening, ornight; dated units are scenes, or a chapter with no scene records, in reading order, the same unitsstory timelineshows; a unit that cannot fall after the latest moment reached warns as running backward and does not reset that moment, with named times read as the same spans as the route check and each chapterstrandkeeping its own clock; scenetravel-hours: Nasserts the minimum time since that moment; a character, by scenecharactersorpov(the chapter'spovwhen the scene has none), in two dated scenes at locations linked by locationroutes, with less story time between them than the fastest route, is an error, and so is a character at two different places at the same exactHH:MMwhether or not routes join them. The route check reads scenedate,time, andlocationonly, not chapter dates; a named time is a span such asmorning05:00-11:59, an untimed scene spans its whole day, and only journeys impossible on every reading are reported). Without dates, only malformed dates or times andtravel-hourson an undated scene are reported. Intentional exceptions go incontinuity/exemptions.md(frontmattertype: exemption-log, entries with areasonand the finding'scodeplus itsfileorchapter, as--jsondiagnostics give them;patternmatches message text and still works); exempted findings are reported as dismissed, not errorscompareafter a revision pass, or when the user asks what changed since a draft:--refreads chapters at a git branch, tag, or commit withgit show(it never writes to the repository), and--againstreads another copy of the project. It reports per-chapter word changes, added and removed chapters, and the share of paragraphs unchanged. With--anchor <label>(repeatable) it instead maps review-copy paragraph labels from that draft to the current text, one line per label:ch01-p20 -> ch01-p21 (text unchanged),(edited, NN% similar),not found in the current text ("first words…"), orno such label; use it to resolve reader notes from an older build. See Draft Snapshots in therevision-continuityskill for taking the snapshotsimilaritywhen the user asks whether a passage echoes another text too closely: their earlier books, a previous draft, or a source they worked from.--againsttakes a file, a folder (another story project's chapters, or every.md,.markdown, and.txtfile in it), or a git ref. It reports each run of--min-words(default 8) or more shared words, compared lowercased without punctuation, as asimilarity-shared-passagewarning with the chapter's review-copy label, the reference's location, and the shared words, then per-chapter and total shares. It is advisory and exits 0. Shared text is not proof of copying, so report what it found and where, never a verdict; see theeditorial-reviewskillprogresswhen the user asks how far along the book is, whether they will make a deadline, or after a writing session: it reports words againststory.mdtarget-words, days left todeadlineand words a day needed, chaptertarget-words, and pace fromprogress.md.--logrecords today's total there (--date YYYY-MM-DDto backfill); only log when the user keeps a log or asks for itpacingwhen the user asks about pacing, sagging middles, or chapter endings, and after drafting or restructuring chapters: per chapter it shows words, scene and sequel counts, sceneoutcomes (yes,no,yes-but,no-and), and the chapterhook(cliffhanger,question,revelation,reversal,decision,emotional,resolution). It warns about three or more consecutiveyesoutcomes, four or more scene units with no sequel, chapter length outliers (over 2x or under 0.5x the median once three chapters have prose), three or more consecutive chapters ending onresolution, and drafted chapters with nohook. See theplot-structureandscene-craftskillscluesfor mysteries and any story with a clue ledger: prints a clue-by-chapter matrix (Pplanted,Rpayoff,xboth,.none;~after a clue name marks a red herring) and warns about a payoff with no plant, a late plant (same chapter as the payoff, or the one before), a clue with nocharacters, three or more genuine live clues (not red herrings) with nonesignificance-delayed, and ared-herring: trueclue with nopayoff. See thegenre-craftskillvoiceswhen dialogue voices may blur or during a line pass: attributes quoted lines (straight, curly, or British single quotes) to the character the narration names next to a speech verb ("...," Mara said,said Mara,Mara asked, aliases included; a name before the verb wins), or else to the only character the paragraph names (an action beat). Pronoun tags (she said) are never attributed, so a close-third POV character is often under-counted. It reports lines, words, mean sentence length, contraction, question, and exclamation rates, and signature words. It warns when a character says avoice-avoidword, when two characters with five or more lines have near-identical fingerprints ("X and Y may sound alike: ..."), and when avoice-wordsentry is never said. See thevoice-styleandline-editingskills--jsonwhen you need to read a result rather than show it to the user:validate,links,continuity,series,report,next,doctor,knowledge,context,progress,timeline,prose,pacing,clues,voices, andsimilaritythen print one JSON object on stdout (apiVersion,command,ok,data,diagnostics,writes).okis true exactly when the exit code is 0; each diagnostic hasseverity,file,message,code(the finding's rule, such asstale-word-count, the name astory.mdseverityentry takes), andcheck(the check that raised it).report,next, anddoctoralways haveok: true, so read theirdata.checksor error diagnostics insteadpassesto track named revision passes instory.mdrevision-passes({pass, status}, statuspending,in-progress, ordone).--initwrites the default ladder (structure,character,theme,continuity,pacing,line,copyedit,proof) and keeps existing entries;--start <pass>and--done <pass>update one; with no flag it prints the checklist and the checks each default pass runs. When the storystatusisrevising,nextrecommends the next unfinished pass. See therevision-continuityskillnamesbefore naming a character, place, faction, artifact, system, or glossary term:story names <name...>checks candidates against every existing name and alias. A candidate's given name (first word that is not a title or article such asthe,lord, orcaptain) is compared with each character's given name, and everything else as a whole name; an exact match with either is a clash, an error (exit 1). Look-alikes (the same first four letters, or the same initial within edit distance 1, or 2 when both words have five letters or more) and a given name sharing an initial with a protagonist, antagonist, deuteragonist, or narrator are warnings. Multi-word names are only checked for exact clashes, so pass a multi-word name's distinctive words separately. Pass--path <project>when not in the project rootdiagramwhen the user wants a picture of the story's structure:story diagram <kind>prints Mermaid source generated from frontmatter, or writes it with--out <file>(--path <project>sets the project). Kinds:relationships(character graph, family edges styled distinctly: the family tree),locations(map-graph from locationroutes, edges labelled with hours),timeline(dated scenes and chapters in story-time order),clues(clue plant to reveal flow per chapter), andarcs(arcs to the chapters that advance them). GitHub, many editors, and mermaid.live render it; regenerate rather than hand-edittimelinewhen the user asks what happens when, how flashbacks sit against the main line, whose POV dominates, or where a character drops out: it orders dated scenes (and chapters without scene records) bydateandtime, marks entries told after later events, lists undated scenes in reading order, totals chapters and words per POV, and reports each character's chapter presence, longest absence, and absence from the final chapters. It is read-only;continuityowns clock errorsprosewhen the user asks for a prose check or before sharing a draft: per chapter it counts sentence length and spread, filter words and -ly adverbs per 1,000 narration words, plain and said-bookism dialogue tags, echoed words, watch words, and avoided spellings fromstyle-sheet.md(dialect,preferred,watch-words,allow-words); across the manuscript it lists repeated 4-word phrases and similar character first names. Findings are advisory warnings and the command exits 0 unlessstory.mdseveritypromotes one.--max-filter-words <n>(default 10),--max-adverbs <n>(default 12), and--max-bookisms <n>(default 2) change the warning thresholds. See thevoice-styleskill for acting on themserieswhenstory.mdhasfollowsorprecedeslinks to other books; it orders the linked sequels and prequels by chronology and checks shared canon (characters deceased in an earlier book, cast listings, facts relearned across books, dead characters learning facts, name and pronunciation drift, destroyed artifacts and their later use). Useinit --follows <path>orinit --precedes <path>to start a linked book, and see theseries-continuityskill for carrying canon acrossimportwhen the user has an existing manuscript or chapter drafts and wants a Story Skills project built from them; follow up by creating character and location files from the printed entity candidates, and by settingformandtarget-wordsinstory.md(import refuses--form; without themstory validatenever checks length andstory progresshas no target). Directory sources import in natural file-name order (chapter-2beforechapter-10).import --forceinto an existing directory deletes everychapter-NN.mdinchapters/before writing the imported chapters, so confirm with the user before forcing an import over a project with drafted chaptersreportwhen the user asks for project status, inventory, progress, or a quick health summarynextbefore a drafting session to identify the next deterministic actiondoctorwhen the user asks what is stale, broken, or inconsistentmigratewhen a project has an older schema version or missing v2 pathsadd,rename,move, andremovefor deterministic entity file operations when they fit the requested change.addtakes ids, not names, for reference options (--planted chapter-01,--pov mara-quill), andadd sceneneeds its chapter to exist, so add the chapter first. Ids stay ASCII kebab-case, so a name with no ASCII letters or digits (Пётр,李明) needs the id by hand:story add character "Пётр" --id petrwritescharacters/petr.mdand keepsname: Пётр, andstory rename <kind> <id> "<New Name>" --id <new-id>does the same on a rename.--idis refused for chapters and scenes, whose ids come from their numbers.remove chapterrefuses while scene files point at the chapter, so remove those scenes first; it walks back ledger statuses that relied on the chapter (planted to planned, paid-off to planted or planned, answered or resolved questions to open), so review the ledgers afterwardsmovewhenever a chapter's number or a scene's chapter or position changes, never a hand rename: chapter and scene ids encode their numbers.story move chapter <id> --number <n>renames the chapter and its scene files, setsnumberand the# Chapter N:heading, and rewrites every reference to the old id (scenechapter, clue and promiseplanted/payoff, questionintroduced/resolved, researchused-in,died-in,continuity/state.mdsince/learned-inandcurrent-chapter, markdown links, and bare ids inplot/timeline.mdand arc bodies). A taken number is refused (chapter-05 already exists: move it first. To make room, renumber from the highest chapter down), so to insert a chapter move the later chapters up one, highest first, thenadd chapter --number <n>.story move scene <id> --chapter <chapter-id>moves a scene to the next free number in that chapter (--scene <n>picks the number, and--scenealone reorders within the chapter) and adds its location and characters to the new chapter; give at least one of the two.moveworks only on chapters and scenes (userenamefor other ids), never edits prose or outline beats that mention a chapter number, and reindexes. References are written before the files move, so rerun an interrupted move. See therevision-continuityskill for splits and mergesinit --form <form>recordsforminstory.md(novel,novella,novelette,short-story,flash,serial,picture-book,chapter-book) and sets a defaulttarget-wordswhen none is given;validatewarns whentarget-wordsis outside the form's usual range andreportshows the formadd matterwhen the user wants a dedication, epigraph, copyright page, acknowledgments, author's note, about-the-author, or also-by page. Pages live inmatter/(indexed inmatter/_index.mdby reindex) withtitle,placement(frontorback),order, andheading(pass--heading falsefor a dedication or epigraph, or edit the scaffoldedheading:key; never add a second one). Write the page text directly in the file; unwritten pages are left out of builds andvalidatewarns about them. Never invent acknowledgments, biographical facts, or copyright details: ask the user for them. Matter pages that quote others' work (an epigraph, song lyrics) may recordpermission(not-needed,pending,granted,public-domain),rights-holder, andcredit;validatewarns whenpermission: pendingremains on a complete story and whengrantedhas norights-holder. See theeditorial-reviewskilladd researchwhen the story relies on a real-world fact: notes live inresearch/withstatus(open,verified,disputed), whole-citationsources, andused-inchapter ids, plus optional--accuracy(must-be-accurate,blended,invented),--confidence(high,medium,low),--method(fact,interview,site-visit,expert-review,reading), and repeatable--risk(legal,medical,weapons,safety,cultural,defamation,technical).validatewarns when a final chapter relies on open or disputed research (invented notes never trigger this), and when a note with ariskis used in a final or complete chapter with noreviewed-by. See theresearchskillexportonly when the user asks for a combined manuscript at a specific path; it includes front and back matterbuildwhen the user asks to build the book artifact; supports markdown, EPUB, DOCX, Shunn, HTML, print, narration, metadata, Fountain, Twee, and ink outputs indist/, with front and back matter. For EPUB, setcover: path/to/cover.jpg(inside the project) andauthorinstory.mdto embed a cover image and creatorbuild --format htmlwhen the user wants a review or reading copy for people who never open a terminal: a single HTML file with a table of contents and a paragraph label on every paragraph, shown faintly in the margin as a link labelledch03-p12(chapter 3, paragraph 12), that reviewers cite in notes. A label is the paragraph's position in that build, so any earlier edit renumbers it; add--stamp <round or date>so notes can name the build, and ask reviewers to quote each paragraph's first few words.--note-url <url>adds a Note link beside each label, prefilled withtitle,anchor,build, andquotequery parameters for themanuscript-note.ymlissue form.templates/github/review-copy.ymlpublishes it to GitHub Pages; see thefeedback-triageskillbuild --format printfor a print-ready interior: HTML with CSS paged media, trim size from--trim(5x8,5.25x8,5.5x8.5,6x9,a5; default5.5x8.5), mirrored margins with gutter, running heads (author on verso, chapter title on recto, blank on chapter openings), page numbers at the foot of chapter and back-matter pages, chapters on recto, a raised initial at each chapter opening, widow and orphan control, and a copyright page. Render it to PDF with a paged-media engine the user installs (Paged.js CLIpagedjs-cli, WeasyPrint, or Prince); the CLI does not bundle one. See thepublishingskillbuild --format narrationfor an audiobook narration script: a pronunciation guide table from everypronunciationfield, each chapter with an estimated finished runtime at 155 words per minute, scene breaks as[pause], and a total runtime. See theadaptationskillbuild --format metadatafor a retailer metadata sheet fromstory.md: title, series, authors, ISBN, publisher, date, language, description with its character count against common limits (KDP 4,000), keywords, BISAC subjects, word count, estimated page count, AI disclosure, and a readiness checklist of missing fields. See thepublishingskillbuild --format tweefor a Twine story (Twee 3) of a branching book: one passage per chapter, named by its id, with a[[text->chapter-NN]]link for each entry in the chapter'schoicesfrontmatter (textandto). The first chapter is the start; once any chapter has choices, a chapter without them is an ending, and with none anywhere each chapter links to the next. The IFID comes fromifidinstory.md; without it the build derives one from the story id and warns with theifid:line to add. It refuses to build while a choice is malformed or leads to a missing chapter;story validateandstory linksreport the same problems, andlinkswarns about chapters no choice path reaches. See theadaptationskillbuild --format inkfor the same branching book as an ink story for Inky and inklecate: one knot per chapter (chapter-03becomeschapter_03), a sticky+ [text] -> knotchoice for each entry inchoices,-> ENDfor a chapter without choices, the title, author, and IFID as global tags, and prose escaped so ink reads it as text. It shares the Twee build's rules, checks, and refusals. See theadaptationskillbuild --format epubalso writes EPUB 3 accessibility metadata, language, semantic chapter and matter markup, and a landmarks nav, and uses the optionalstory.mdpublishing fields (cover-alt,isbn,publisher,publication-date,description,subjects,language, andcopyright, which generates a copyright page when no copyright matter page exists)build --format shunnwhen the user wants Shunn manuscript-format markdown: title page, contact block, word count, chapter breaks, and double-spaced prose;story build . --format docx --shunnapplies the same Shunn formatting to the DOCX outputknowledgewhen the user asks what a character knew at a given chapter:story knowledge <character-id> --at <chapter-id>lists knowledge-state entries whoselearned-inchapter is at or before that chapter, plus entries withoutlearned-inas pre-existing knowledgecontextbefore drafting a chapter or scene:story context <chapter-or-scene-id> [--budget <tokens>] [--scenes <n>]prints, as markdown and in priority order until the estimated budget (default 6000 tokens, at 4 tokens per 3 words) runs out, the target's outline and cast, thestory.mdessentials andstyle-sheet.mdrules, the POV character's knowledge and state at that point, cards for the characters on the page and the locations, with their progressions applied at the target, open promises, clues, and questions, and summaries of the previous--scenesscenes (default 5). It includes nothing from later chapters, progressions included; items left out for the budget are listed with the file to read insteadadd cluewhen the user plants a new clue:story add clue "Name" --planted chapter-02 --payoff chapter-05creates the clue ledger entity incontinuity/clues/withstatus: planted(plannedwhen--plantedis omitted or names a chapter not written yet; pass--status plannedif the clue is not on the page yet); omit--payoffwhen the payoff is not yet known, and pass--red-herringfor a clue meant to misleadsynopsiswhen the user wants a mechanical synopsis: the first sentence ofstory.md's## Synopsissection, then each arc's Setup, Rising Action, Climax, and Resolution. One page is 500 words and three pages is 1500.story synopsis [--pages 1|3] [--out file]. The output is a scaffold; thesubmissionskill rewrites it into an agent-ready synopsis
Project CLI Configuration
story.md may carry cli-defaults (default flags per command, such as - command: build with format: html) and severity (named warnings promoted with level: error or silenced with level: off, such as - warning: todo-markers). A flag on the command line always wins. Edit these fields only when the user asks for project-wide defaults or stricter checks, then run story validate: it rejects unknown commands, flags, warning codes, and levels, and while either field is invalid the other commands refuse to run. Every warning line ends with its code in brackets, such as [todo-markers], which is the name a severity entry takes; an error: line ending in a code is a warning the project has promoted. Errors cannot be overridden. docs/cli-reference.md lists every code under Finding codes.
Failure Handling
- Treat CLI errors as actionable maintenance findings.
- Read the exit code to decide what to do next:
1means the check founderror:findings to fix in the project;2means the command line was wrong (fix the command, not the project);3means the path is not a usable story project or a file it needs does not parse (repair that file, or point at the folder withstory.md);4means a write was refused (the target exists, is project source, is locked by another story command, or is not writable), so resolve the conflict rather than forcing it. - Fix broken references, missing required files, stale registries, or incorrect word counts when the requested task implies doing so.
- Do not overwrite creative prose or story content merely to satisfy a mechanical check.
- If a validation warning reflects intentional user data, report it rather than silently changing it.
- If a command stops with
Cannot reindex: fix these files first(orCannot count words: ...,Cannot build: ...), repair the frontmatter of each listed file, then rerun it.rename,move, andremovereport<file>: <error>; nothing was changedfor the same cause, and<file> is missing YAML frontmatter; nothing was changedwhen an entity file, a CLI registry (the_index.mdin an entity folder,matter/, orresearch/), or fixed project file (story.md,style-sheet.md,progress.md,plot/timeline.md,continuity/state.md,continuity/exemptions.md) has none; plain skill notes such ascontinuity/motifs.md, or an_index.mdin a folder of the user's own such asnotes/, do not block them. - A file-system failure reads
Cannot <open|list|check|replace|delete|write to> <path>: <reason>(such aspermission denied); fix the file or folder permissions, or the path, rather than the story content. - If
story reindexfails on a corruptplot/_index.md, do not hand-edit story content to work around it: restore the index frontmatter from git, or deleteplot/_index.mdso reindex rebuilds it, then rerun.