MCP tool reference
The Anthra MCP server is at full parity with the in-app AI writing agent — 243+ tools spanning planning, drafting, prose analysis, the specialist critique panel, worldbuilding & continuity, character craft, structural editing, collaboration, illustration, narration, and publishing.
The authoritative, always-current list lives at the source. Because new tools ship continuously, the canonical catalog — every tool name, description, and JSON Schema — is whatever your client receives on the MCP tools/list request, or from GET /api/v1/tools over the REST tool gateway. The groups below are a representative map; they are generated from the same definitions the server serves, but treat the live list as canonical.
Each tool is gated by the API scope it requires (books:read, books:write, generation:run, publish:write, account:read, analytics:read). Schemas are JSON Schema, exactly as the MCP client sees them. Expand any tool for its input schema and the scope it needs.
Library & books
List, read, create, update, delete, and restore books and their metadata.
list_booksbooks:readList every book in this account (newest first). Returns id, title, status, visibility, slug.
Input schema
{ "type": "object", "properties": {} }get_bookbooks:readFetch a single book with its full chapter list (titles, summaries, content, word counts, audio URLs).
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." } }, "required": [ "bookId" ] }create_bookbooks:writeCreate a draft book from a one-line premise. Returns the book id, which subsequent generation tools accept. After creating, call `generate_outline`.
Input schema
{ "type": "object", "properties": { "premise": { "type": "string", "minLength": 10, "description": "One-paragraph book idea (10–4000 chars)." }, "title": { "type": "string", "maxLength": 200 }, "genre": { "type": "string", "maxLength": 120 }, "modelTier": { "type": "string", "enum": [ "haiku", "sonnet", "opus" ], "description": "Writer model tier: haiku=fast draft, sonnet=default, opus=editorial." } }, "required": [ "premise" ] }update_bookbooks:writePatch a book's metadata (title, subtitle, description, author, cover color, genre, tone). Does not touch chapters.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "title": { "type": "string" }, "subtitle": { "type": "string" }, "author": { "type": "string" }, "description": { "type": "string" }, "coverColor": { "type": "string", "pattern": "^#[0-9a-fA-F]{6}$" }, "genre": { "type": "string" }, "audience": { "type": "string" }, "toneStyle": { "type": "string" } }, "required": [ "bookId" ] }delete_bookbooks:writeSoft-delete a book. Recoverable within 30 days, after which the cron worker hard-deletes it.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }undo_delete_bookbooks:writeRestore a recently soft-deleted book. Works within 30 days of deletion (after that the cleanup cron hard-deletes the row). Clears the archived flag too so the book returns to the active library.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }
Planning surface
Theme statement, reader promise, comp authors, beat sheets, POV/tense locks, premise interview & pitches, genre detect, era research, outline grader, outline variants, mood references, and outline snapshots.
generate_outlinegeneration:runRun the outliner: replaces any existing chapters with a fresh outline, sets title/subtitle/description/coverColor on the book, and advances status to `writing`. Synchronous — may take 10–60s.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "research": { "type": "boolean", "description": "Force-enable the Perplexity research pass before outlining. Defaults to the account-wide flag." } }, "required": [ "bookId" ] }get_planbooks:readRead the book's planning surface — theme statement, reader promise, comp authors, selected beat sheet, POV/tense locks, auto-detected genre + audience confidences, and era-research citations.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }set_planbooks:writeWrite the planning surface fields. Any omitted field is left alone; pass null to clear. Fields: themeStatement, readerPromise, compAuthors, beatSheetTemplate (id like 'save-the-cat'), povLock, tenseLock ('past'|'present'), povDepth (0-100).
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "themeStatement": { "type": [ "string", "null" ] }, "readerPromise": { "type": [ "string", "null" ] }, "compAuthors": { "type": [ "string", "null" ] }, "beatSheetTemplate": { "type": [ "string", "null" ] }, "povLock": { "type": [ "string", "null" ] }, "tenseLock": { "type": [ "string", "null" ], "enum": [ "past", "present", null ] }, "povDepth": { "type": [ "integer", "null" ], "minimum": 0, "maximum": 100 } }, "required": [ "bookId" ] }list_beat_sheetsbooks:readList every beat-sheet template (Save the Cat, Three-Act, Hero's Journey, Freytag, Kishotenketsu, Tell/Promise/Mean) with each beat's label, intent, and position.
Input schema
{ "type": "object", "properties": {} }premise_interviewgeneration:runPremise-sharpening interview. action='read' returns saved state; 'generate' produces 3-5 questions; 'save' merges answers (q1, q2, …); 'apply' rewrites book.premise from answers.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "action": { "type": "string", "enum": [ "read", "generate", "save", "apply" ] }, "answers": { "type": "object" } }, "required": [ "bookId", "action" ] }generate_premise_pitchesgeneration:runThree competing premise pitches (A/B/C angles for the same idea). Use select_premise_pitch to lock one.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }list_premise_pitchesbooks:readList the most recent round of premise pitches.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }select_premise_pitchbooks:writeLock one premise pitch (writes book.premise).
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "angle": { "type": "string", "enum": [ "A", "B", "C" ] } }, "required": [ "bookId", "angle" ] }detect_genregeneration:runAuto-detect genre + audience from the current premise. apply:true writes the result to the book.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "apply": { "type": "boolean" } }, "required": [ "bookId" ] }research_erageneration:runEra / period research with citation links. Writes a Markdown brief into the era_research writer's-bible document and saves the citations to book.researchCitations.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "eraHint": { "type": [ "string", "null" ] } }, "required": [ "bookId" ] }grade_outlinegeneration:runScore the current outline 0-100 across arc / pacing / stakes / characters / ending, with a paragraph-level critique and 2-8 fix suggestions. force:true regrades even if cached.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "force": { "type": "boolean" } }, "required": [ "bookId" ] }list_outline_variantsbooks:readList the most recent round of outline variants (#14).
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }generate_outline_variantsgeneration:runThree competing outline variants (each with a one-line angle + a full chapter list). Costs three outline-LLM calls.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }apply_outline_variantbooks:writeApply one outline variant to the chapter table (snapshots first, skips locked chapters).
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "variantId": { "type": "string" } }, "required": [ "bookId", "variantId" ] }list_outline_snapshotsbooks:readList every captured outline mutation (#22) — pair with restore_outline_snapshot.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }restore_outline_snapshotbooks:writeRevert the outline to a saved snapshot in place.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "snapshotId": { "type": "string" } }, "required": [ "bookId", "snapshotId" ] }list_mood_referencesbooks:readList tone / mood reference photos (#12) for this book.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }generate_chapter_imagegeneration:runGenerate an illustration for one chapter via the AI Gateway image pipeline, store it in Vercel Blob, and set it as the chapter's lead image. PAID — charges one illustration credit; refunds on failure.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" }, "styleHint": { "type": "string", "description": "Art-direction hint (e.g. \"muted watercolor\")." }, "prompt": { "type": "string", "description": "Override the distilled prompt." } }, "required": [ "bookId", "chapterId" ] }generate_cover_artgeneration:runGenerate one or more cover-art variants via the AI Gateway image pipeline, store in Vercel Blob, and set the first as the book's active cover. PAID — charges per variant (1-3); refunds the unspent portion on partial failure.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "styleHint": { "type": "string", "description": "Art-direction (e.g. \"moody oil painting\")." }, "prompt": { "type": "string", "description": "Hand-crafted prompt override." }, "variants": { "type": "integer", "minimum": 1, "maximum": 3 } }, "required": [ "bookId" ] }generate_back_covergeneration:runGenerate a back-cover panel via the AI Gateway image pipeline. Uses the marketing blurb when present, otherwise the premise. PAID — one illustration credit.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "prompt": { "type": "string" }, "styleHint": { "type": "string" } }, "required": [ "bookId" ] }generate_spinegeneration:runGenerate a spine panel via the AI Gateway image pipeline. Narrow aspect ratio sized for paperback spines. PAID — one illustration credit.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "prompt": { "type": "string" }, "styleHint": { "type": "string" } }, "required": [ "bookId" ] }cancel_generationbooks:writeCancel the active book-generation workflow run for one book (the long-running outline-and-write pipeline). Idempotent — succeeds with ok:true even when no run is active. Reverts book status to `draft`.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }update_mood_reference_captionbooks:writeEdit the caption on a mood reference image (#12). The caption is what actually feeds the writer prompt (register, palette, weather, light); the image is for the author.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "imageId": { "type": "string" }, "caption": { "type": "string" } }, "required": [ "bookId", "imageId", "caption" ] }remove_mood_referencebooks:writeDelete a mood reference image (#12) from this book.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "imageId": { "type": "string" } }, "required": [ "bookId", "imageId" ] }plan_deadlinegeneration:runPlan remaining writing against a target date. Returns weekly + daily word targets, a feasibility verdict, suggested cuts, and ramps. Uses outline target words + currently written words.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." }, "targetDate": { "type": "string", "description": "ISO date string, e.g. \"2026-09-01\"." }, "targetTotalWords": { "type": "number", "description": "Target total word count. If omitted, sums the outline's per-chapter targetWords (or 3000/chapter when missing)." }, "recentWordsPerWeek": { "type": "number", "description": "If known, the author's recent pace in words/week." }, "constraints": { "type": "string" } }, "required": [ "bookId", "targetDate" ] }genre_expert_lookupgeneration:runGenre expert lookup. Ask a question about genre conventions, comp-title moves, or reader expectations — the Genre Expert returns canonical prescriptions an author can apply tomorrow.
Input schema
{ "type": "object", "properties": { "question": { "type": "string", "description": "The question, e.g. 'what's the cozy-mystery midpoint move?'." }, "genre": { "type": "string", "description": "Override genre. Defaults to the book's genre if bookId is provided." }, "bookId": { "type": "string", "description": "Book UUID." } }, "required": [ "question" ] }generate_invented_calendargeneration:runGenerate a complete invented calendar for the book — months, day length, day-of-week names, festivals (#45). Does NOT save the result. Pass the returned shape to set_invented_calendar to persist. Costs LLM tokens.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "styleHint": { "type": "string" } }, "required": [ "bookId" ] }regenerate_relationship_graphgeneration:runRe-derive the character relationship graph (#95) from the full prose. Replaces book_character_conflict with model-extracted directed edges (kind + one-line description). Costs LLM tokens proportional to manuscript size.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "replace": { "type": "boolean", "description": "When true, wipes existing conflicts before insert. Defaults to false (additive, dedup'd by from+to+kind)." } }, "required": [ "bookId" ] }voice_transplant_paragraphgeneration:runRewrite one paragraph of a chapter to MATCH the voice of another paragraph, or a hand-supplied source passage. Saves a paragraph-scoped chapter_suggestion for review.
Input schema
{ "type": "object", "properties": { "targetChapterId": { "type": "string", "description": "Chapter UUID." }, "targetParagraphIndex": { "type": "integer", "minimum": 0, "description": "0-based paragraph index in the target chapter." }, "sourceChapterId": { "type": "string", "description": "Chapter holding the source paragraph (omit when using sourceText)." }, "sourceParagraphIndex": { "type": "integer", "minimum": 0 }, "sourceText": { "type": "string", "minLength": 20, "description": "Raw source paragraph — overrides sourceChapterId/index." }, "hint": { "type": "string", "maxLength": 300 } }, "required": [ "targetChapterId", "targetParagraphIndex" ] }voice_transplant_passagegeneration:runRewrite a passage in another POV character's voice. The passage is raw text (passageText) or a paragraph range in a chapter (chapterId + fromParagraphIndex + toParagraphIndex). Voice comes from targetCharacterId. Chapter-range mode saves a chapter_suggestion; raw-text mode returns the rewrite unpersisted.
Input schema
{ "type": "object", "properties": { "targetCharacterId": { "type": "string", "description": "book_character id whose voiceProfile to transplant." }, "chapterId": { "type": "string", "description": "Chapter UUID." }, "fromParagraphIndex": { "type": "integer", "minimum": 0 }, "toParagraphIndex": { "type": "integer", "minimum": 0 }, "passageText": { "type": "string", "minLength": 20, "maxLength": 8000 }, "hint": { "type": "string", "maxLength": 300 } }, "required": [ "targetCharacterId" ] }regenerate_outline_sectiongeneration:runRe-plan only a contiguous range of chapters (inclusive) — replaces titles + summaries in that range, leaves the rest alone. Refuses to overwrite written or locked chapters unless force: true.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." }, "fromOrder": { "type": "integer", "minimum": 1 }, "toOrder": { "type": "integer", "minimum": 1 }, "directive": { "type": "string", "description": "Optional editorial direction for the new section." }, "force": { "type": "boolean", "description": "Required true if any chapter in range has written prose." } }, "required": [ "bookId", "fromOrder", "toOrder" ] }splice_outline_variantsgeneration:runBuild a composite outline by splicing chapter ranges from the existing outline-variants round. Each pick is {variantId, fromOrder, toOrder}; ranges are stitched in order. Snapshots the prior outline, then replaces UNLOCKED chapters (locked chapters keep their order). DESTRUCTIVE.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." }, "picks": { "type": "array", "minItems": 1, "maxItems": 8, "items": { "type": "object", "properties": { "variantId": { "type": "string" }, "fromOrder": { "type": "integer", "minimum": 1 }, "toOrder": { "type": "integer", "minimum": 1 } }, "required": [ "variantId", "fromOrder", "toOrder" ] } } }, "required": [ "bookId", "picks" ] }generate_scene_cardsgeneration:runDecompose ONE chapter into ordered scene cards (Dwight Swain shape: POV, goal, conflict, disaster, value-shift). Persists into chapters.scenes. Use BEFORE writing the chapter. Refuses to overwrite existing scenes unless overwrite: true.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." }, "chapterId": { "type": "string", "description": "Chapter UUID." }, "order": { "type": "integer", "minimum": 1 }, "overwrite": { "type": "boolean", "description": "Replace existing scene cards. Defaults false." } }, "required": [ "bookId" ] }generate_synopsisgeneration:runGenerate a 1-page (~500–800 word) synopsis of the FULL arc — present tense, third person, ending shown — and store it on the book's synopsis document. Lives separately from the chapter outline. Refuses to overwrite an existing synopsis unless overwrite: true. Needs ≥3 chapters.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." }, "overwrite": { "type": "boolean", "description": "Allow replacing an existing synopsis. Defaults false." } }, "required": [ "bookId" ] }run_premise_stress_testgeneration:runStress-test a premise against four dimensions BEFORE outlining: hook strength, why-now, comp-title resonance, genre fit. Returns 0–100 per dimension plus a hook rewrite, comp titles with scores, suggested genre, and concrete premise revisions.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." } }, "required": [ "bookId" ] }generate_marketing_copygeneration:runGenerate launch marketing copy from a finished book: an Amazon-style back-cover blurb, three sample social posts, and a launch announcement email. Pass `kinds` to limit which pieces are generated. Returns the structured payload.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "kinds": { "type": "array", "items": { "type": "string", "enum": [ "blurb", "social", "email" ] }, "description": "Which pieces to produce. Defaults to all three." } }, "required": [ "bookId" ] }
Outline & chapter authoring
Generate outlines, write & rewrite chapters, revise ranges, and restructure (split / merge / reorder) with full revision history.
write_chaptergeneration:runGenerate prose for one chapter and persist it. Returns the new content. Streaming is not exposed over MCP — this call resolves when the chapter is fully written and saved. Call chapters in `order` so the writer has continuity.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" } }, "required": [ "bookId", "chapterId" ] }rewrite_chaptergeneration:runApply a directive to revise one chapter (e.g., "punch up the dialogue", "shorten by 30%"). Snapshots the prior text so the change is recoverable, then overwrites the chapter and invalidates audio.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" }, "directive": { "type": "string", "minLength": 3, "description": "Editorial instructions for the rewrite." } }, "required": [ "bookId", "chapterId", "directive" ] }set_chapter_metabooks:writeUpdate a chapter's title, summary, or target word count without touching the prose.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" }, "title": { "type": "string" }, "summary": { "type": [ "string", "null" ] }, "targetWords": { "type": [ "integer", "null" ], "minimum": 0 } }, "required": [ "bookId", "chapterId" ] }reorder_chaptersbooks:writeAtomically reorder chapters. orderedIds must list every chapter id in the new order.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "orderedIds": { "type": "array", "items": { "type": "string" } } }, "required": [ "bookId", "orderedIds" ] }list_chapter_revisionsbooks:readList saved snapshots of a chapter (newest first).
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" } }, "required": [ "bookId", "chapterId" ] }restore_chapter_revisionbooks:writeRoll a chapter back to a saved snapshot. The current content is snapshotted first.
Input schema
{ "type": "object", "properties": { "revisionId": { "type": "string" } }, "required": [ "revisionId" ] }list_chaptersbooks:readList every chapter on a book (id, order, title, summary, word count, audio status, image URL). Dedicated chapter list — pair with `get_chapter` to fetch full prose.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }update_chapterbooks:writeOverwrite a chapter's prose (and optionally its title/summary/notes). Snapshots the prior content so the change is recoverable, resets audio status if the content changed.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" }, "title": { "type": "string", "maxLength": 300 }, "summary": { "type": [ "string", "null" ], "maxLength": 1000 }, "content": { "type": "string", "maxLength": 100000 }, "notes": { "type": [ "string", "null" ], "maxLength": 4000 } }, "required": [ "bookId", "chapterId" ] }split_chapterbooks:writeSplit a chapter into two. Inserts a new (empty) chapter immediately after the original; later chapters' order numbers shift up by 1.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" }, "newTitle": { "type": "string", "minLength": 1 }, "newSummary": { "type": [ "string", "null" ] } }, "required": [ "bookId", "chapterId", "newTitle" ] }merge_chaptersbooks:writeMerge two adjacent chapters into one. The second chapter is removed; its content is appended to the first with a blank line separator. Snapshots both halves first so it's reversible.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "firstChapterId": { "type": "string" }, "secondChapterId": { "type": "string" } }, "required": [ "bookId", "firstChapterId", "secondChapterId" ] }revise_chapter_rangegeneration:runApply one editorial directive consistently across an inclusive range of chapters (e.g. chapters 3–7: tighten pacing, switch to first person). Runs the rewrites in parallel by default — each chapter sees the same pre-rewrite snapshot of its neighbors. Pass parallel: false for one-at-a-time on cost-sensitive runs. Snapshots each chapter before overwriting.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "fromOrder": { "type": "integer", "minimum": 1 }, "toOrder": { "type": "integer", "minimum": 1 }, "directive": { "type": "string", "minLength": 3 }, "parallel": { "type": "boolean", "description": "Fan out chapter rewrites concurrently (default true). Each rewrite reads the original pre-rewrite prose of its neighbors." } }, "required": [ "bookId", "fromOrder", "toOrder", "directive" ] }explain_chapter_revisiongeneration:runExplain in plain English why a chapter_revision differs from the chapter's current content. Returns a short TTS-ready narration plus itemized what/why pairs.
Input schema
{ "type": "object", "properties": { "revisionId": { "type": "string", "description": "Chapter revision UUID." } }, "required": [ "revisionId" ] }rewrite_chapter_preservinggeneration:runRewrite a chapter under a directive while keeping specified spans VERBATIM. Pass `preserves` (exact strings) and/or `preserveDialogue: true` to auto-collect quoted dialogue. Saves a chapter_suggestion plus a verification report flagging any preserved span that drifted.
Input schema
{ "type": "object", "properties": { "chapterId": { "type": "string", "description": "Chapter UUID." }, "directive": { "type": "string", "minLength": 3, "maxLength": 800 }, "preserves": { "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 2000 }, "maxItems": 50 }, "preserveDialogue": { "type": "boolean" } }, "required": [ "chapterId", "directive" ] }reverse_outlinegeneration:runDerive the outline a book ACTUALLY has from its written prose and diff it against the planned outline. Per written chapter: derived summary, beats, POV, setting, plus an alignment verdict (aligned / drifted / off-plan). Pure read. Pass chapterId for a single chapter.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." }, "chapterId": { "type": "string", "description": "Chapter UUID." } }, "required": [ "bookId" ] }check_outline_driftgeneration:runRe-grade the outline and compare to the previously-stored grade so you can see whether the arc on paper has drifted as chapters were drafted. Only re-runs when ≥3 chapters were written since the last grade unless force: true. Run grade_outline once first.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." }, "force": { "type": "boolean", "description": "Re-grade even if fewer than 3 new chapters were written." } }, "required": [ "bookId" ] }find_outline_plot_holesgeneration:runScan the FULL outline (every chapter title + summary, plus synopsis if present) for plot holes a structural editor would flag: unresolved setups, unmotivated actions, timeline issues, missing bridges, ability-pops, stake resets. Works on the OUTLINE — fix holes before drafting. Needs ≥5 chapters.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." } }, "required": [ "bookId" ] }
Prose analysis
Read-only craft analyzers: filter words, adverb density, sensory balance, concrete nouns, POV slippage, tense consistency, sentence rhythm, dialogue tags, body language, clichés, telegraphing, repetition, style drift, and spoken readability.
lint_prosebooks:readStatic prose linter across one or all chapters — zero LLM cost. Flags adverbs, passive voice, cliches, AI fingerprints, forbidden-word hits, etc. Returns per-chapter severity (green/yellow/red).
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" } }, "required": [ "bookId" ] }find_repetitionbooks:readDetect overused phrases within a chapter, or repeated sentence openers across the book.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" }, "scope": { "type": "string", "enum": [ "chapter", "openers" ] } }, "required": [ "bookId" ] }suggest_cliche_replacementsgeneration:runFind clichés in one chapter and propose specific replacements via the LLM.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" } }, "required": [ "bookId", "chapterId" ] }spoken_readabilitybooks:readScore narration difficulty per chapter (consonant clusters, sibilants, breath length, proper nouns).
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" } }, "required": [ "bookId" ] }style_driftbooks:readMeasure each written chapter's voice fingerprint against the book-wide average. High drift = a chapter is out of voice.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }set_forbidden_wordsbooks:writeSet or clear the per-book forbidden-word list. The linter flags hits and the writer prompt avoids them.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "words": { "type": "array", "items": { "type": "string" } } }, "required": [ "bookId", "words" ] }list_forbidden_wordsbooks:readRead the per-book forbidden-word list.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }set_style_rulesbooks:writeSet or clear the per-book declarative style rules (#67). Each rule is one hard constraint honored across every chapter — 'no semicolons', 'never open a chapter with weather'. Provide `pattern` (a regex source, no slashes/flags, case-insensitive) when the rule is mechanically checkable so the prose-lint pass flags violations; omit it for soft rules. Replaces the existing list — pass the merged set when adding incrementally, or `rules: []` to clear.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "rules": { "type": "array", "maxItems": 50, "description": "Replaces the existing list. Pass [] to clear.", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable id for the rule. Omit on new rules and one will be generated." }, "rule": { "type": "string", "description": "Natural-language constraint shown verbatim to the writer." }, "pattern": { "type": [ "string", "null" ], "description": "Optional regex source (no flags) used by the linter to flag violations. Omit for soft rules." }, "scope": { "type": "string", "enum": [ "all", "chapter_open", "chapter_close" ], "description": "'chapter_open' narrows the linter check to the chapter's opening paragraph; 'chapter_close' to the closing. Defaults to 'all'." }, "enabled": { "type": "boolean", "description": "Defaults to true." } }, "required": [ "rule" ] } } }, "required": [ "bookId", "rules" ] }list_style_rulesbooks:readRead the per-book declarative style rules (#67). Returns the rule list and, for any rule carrying a regex pattern, the chapters that currently violate it so targeted rewrites can be proposed. Zero LLM cost.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }analyze_sentence_rhythmbooks:readSentence-rhythm analyzer (#23). Measures sentence-length variance and opener-bucket histograms across a chapter (or every chapter) and flags runs of 4+ similar-length or similar-opener sentences — the AI-prose tell. Zero LLM cost. Returns severity (green/yellow/red) plus the run list.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" } }, "required": [ "bookId" ] }find_filter_wordsbooks:readFilter-word stripper (#26). Lists every "she saw / he heard / she noticed" span in a chapter — verbs that filter the reader through the POV character's senses instead of putting them inside the experience. Returns spans with surrounding context. Zero LLM cost.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" } }, "required": [ "bookId", "chapterId" ] }analyze_sensory_balancebooks:readSensory-balance audit (#27). Counts cue words per sense (sight, sound, smell, taste, touch, kinesthetic) in a chapter (or every chapter) and flags scenes that are visual-only or missing whole senses. Zero LLM cost. Returns ratios + per-paragraph dominant sense count.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" } }, "required": [ "bookId" ] }analyze_adverb_densitybooks:readAdverb-density meter (#28). Reports -ly adverbs per 100 words per chapter, with the genre target band (1–3/100 for tight prose). Lists the actual adverbs sorted by frequency. Zero LLM cost.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" } }, "required": [ "bookId" ] }analyze_dialogue_tagsbooks:readDialogue-tag diversifier (#29). Counts "said"/"asked" runs and flags inflated alternatives ("exclaimed", "opined"). Surfaces tag density so rewrites toward beats can be recommended. Zero LLM cost.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" } }, "required": [ "bookId" ] }analyze_body_languagebooks:readBody-language vocabulary audit (#30). Counts nod/sigh/shrug/smile/frown/etc. gestures per 1000 words and flags overuse. Zero LLM cost. Helps break the nod-sigh-shrug loop.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" } }, "required": [ "bookId" ] }analyze_concrete_nounsbooks:readConcrete-noun ratio (#31). Scores prose 0–100 for concreteness by counting abstract-suffix nouns (-tion, -ity, -ness) and bare-article placeholders against the rest. Zero LLM cost. Flags scenes that float in summary instead of standing on named, physical things.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" } }, "required": [ "bookId" ] }check_pov_slippagebooks:readPOV-slippage linter (#34) for strict 1st-person or 3rd-limited. Per-sentence detection — flags any sentence whose dominant pronouns disagree with the chapter's declared POV (or book-level povLock). Zero LLM cost. Returns drift indices the editor can highlight.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" }, "povLock": { "type": "string", "enum": [ "first", "second", "third" ], "description": "Override the book-level povLock for this scan. Useful when one chapter is intentionally a different POV." } }, "required": [ "bookId" ] }check_tense_consistencybooks:readTense-consistency linter (#35). Per-sentence detection of past vs present drift across a chapter (or every chapter). Uses the book-level tenseLock when set, otherwise the chapter's dominant tense. Zero LLM cost. Returns drift indices.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" }, "tenseLock": { "type": "string", "enum": [ "past", "present" ], "description": "Override the book-level tenseLock for this scan." } }, "required": [ "bookId" ] }suggest_cadence_variationsgeneration:runCadence variation suggester (#24). Reads a chapter, finds runs of similar-length sentences, and asks the model for a short+long rewrite that breaks the cadence. Returns the original run and the proposed rewrite. LLM-backed.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" } }, "required": [ "bookId", "chapterId" ] }suggest_showing_rewritesgeneration:runShow, don't tell (#25). Reads a chapter, finds abstract emotion words ("she was sad"), and proposes 2–3 embodied rewrites per span — gesture, body-sensation, thought, environmental-cue, or dialogue-beat. LLM-backed.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" } }, "required": [ "bookId", "chapterId" ] }detect_semantic_clichesgeneration:runSemantic cliché detector (#32). Asks the model to find paraphrased clichés, dead metaphors, and genre-tired physical reactions in a chapter. Returns verbatim excerpts, a category, why-tired explanation, and a replacement hint. LLM-backed; catches clichés a regex misses.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" } }, "required": [ "bookId", "chapterId" ] }detect_telegraphinggeneration:runTelegraphing detector (#33). Reads the whole manuscript and flags foreshadowing heavy enough to give twists away — "little did she know" prose. Each hit names the future beat being leaked, rates severity (soft/medium/heavy), and proposes a softer rewrite. LLM-backed.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }suggest_verb_upgradesgeneration:runVerb-strength upgrader (#36). Reads a chapter, finds weak verb+adverb pairs ("walked quickly") and "to-be + adjective" constructions, and proposes 2–3 strong single-verb replacements per span with connotation labels. LLM-backed.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" } }, "required": [ "bookId", "chapterId" ] }
Specialist & critique panel
The round-table: call a specialist, run a critique round-table, skeptic-verify a claim, synthesize as Editor-in-Chief, run a draft tournament, the long-horizon plot doctor, genre-expert lookups, and the debut-reader read.
critique_chaptergeneration:runLLM editorial pass on one written chapter — pacing, voice, continuity, line-level diagnostics. Read-only.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" } }, "required": [ "bookId", "chapterId" ] }critique_all_chaptersgeneration:runRun a read-only developmental edit pass on EVERY written chapter (optionally a fromOrder/toOrder range) in parallel. Returns one critique per chapter (pacing, voice drift, continuity). Pure read — no chapter is modified. Pair with revise_chapter_range to act on the findings.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "fromOrder": { "type": "integer", "minimum": 1, "description": "Optional: limit to chapters with order >= fromOrder." }, "toOrder": { "type": "integer", "minimum": 1, "description": "Optional: limit to chapters with order <= toOrder." } }, "required": [ "bookId" ] }list_specialistsbooks:readList the specialist sub-agents available — Dialogue Critic, Pacing Editor, Continuity Hawk, Voice Coach, Plot Doctor, Sensitivity Reader, Line Editor, Marketing Strategist, plus Genre Expert, Debut Reader, Skeptic, and Editor-in-Chief. Returns each key, name, scope, and one-line description.
Input schema
{ "type": "object", "properties": {} }call_specialistgeneration:runRun ONE specialist sub-agent against a chapter (or arbitrary excerpt). Returns a focused critique within that specialist's remit. Use list_specialists to discover keys. Pure read. Pair with editor_in_chief_synthesize when you've collected multiple specialists' findings.
Input schema
{ "type": "object", "properties": { "specialist": { "type": "string", "description": "Specialist key, e.g. 'dialogue-critic', 'pacing-editor', 'continuity-hawk', 'voice-coach', 'plot-doctor', 'sensitivity-reader', 'line-editor', 'marketing-strategist'." }, "bookId": { "type": "string", "description": "Book UUID." }, "chapterId": { "type": "string", "description": "Run against this chapter. Either chapterId or excerpt." }, "excerpt": { "type": "string", "description": "Free-form passage to critique instead of a whole chapter. Provide chapterId OR excerpt." }, "directive": { "type": "string", "description": "Extra instruction to focus the specialist on a specific concern." } }, "required": [ "specialist", "bookId" ] }round_table_critiquegeneration:runFan out N specialist sub-agents in parallel against one chapter and return all their findings. Default panel is the 8 core specialists; override with the specialists array. Pair with editor_in_chief_synthesize to consolidate.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." }, "chapterId": { "type": "string", "description": "Chapter UUID." }, "specialists": { "type": "array", "items": { "type": "string" }, "description": "Optional override: which specialist keys to include. Defaults to the 8 core specialists." }, "directive": { "type": "string", "description": "Extra instruction passed to every specialist." } }, "required": [ "bookId", "chapterId" ] }skeptic_verifygeneration:runAdversarial verify. Take a prior critique and run a skeptic pass that tries to REFUTE every claim. Each finding is labeled STANDS, OVERREACH, or WRONG with a rebuttal. Use to filter out plausible-but-wrong findings before acting.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." }, "chapterId": { "type": "string", "description": "The chapter the critique was about. Either chapterId or excerpt." }, "excerpt": { "type": "string" }, "priorCritique": { "type": "string", "description": "The critique to refute — verbatim Markdown body." }, "priorCritiqueAuthor": { "type": "string", "description": "Who produced the critique, e.g. 'Pacing Editor'." } }, "required": [ "bookId", "priorCritique" ] }editor_in_chief_synthesizegeneration:runEditor-in-Chief synthesizer. Take N specialist critiques of the same chapter and consolidate them into ONE prioritized punch list — deduplicating, resolving conflicts, ranking by leverage. Returns the one change that matters most, a numbered punch list, defer items, and resolved disagreements.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." }, "chapterId": { "type": "string", "description": "The chapter the critiques refer to. Optional for book-level synthesis." }, "critiques": { "type": "array", "minItems": 2, "description": "At least two specialist critiques to synthesize.", "items": { "type": "object", "properties": { "specialistKey": { "type": "string" }, "specialistName": { "type": "string" }, "findings": { "type": "string" } }, "required": [ "specialistKey", "specialistName", "findings" ] } } }, "required": [ "bookId", "critiques" ] }draft_tournamentgeneration:runN-draft tournament. Generate 2–6 distinct revisions of a passage from different angles (DRAMATIC, INTERIOR, RESTRAINED, LYRICAL, KINETIC, IRONIC), then run a judge that picks a winner with per-draft scoring. Set judgeTier:'deep' for an Opus judge. Never persists.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." }, "chapterId": { "type": "string", "description": "Chapter UUID." }, "passage": { "type": "string", "description": "The passage to revise. Plain prose, no Markdown wrappers." }, "before": { "type": "string", "description": "Optional preceding context for continuity." }, "after": { "type": "string", "description": "Optional trailing context for continuity." }, "n": { "type": "number", "description": "Number of drafts (2–6). Default 3." }, "judgeTier": { "type": "string", "enum": [ "fast", "deep" ], "description": "'fast' (Sonnet, default) or 'deep' (Opus) for the judge." }, "angles": { "type": "array", "items": { "type": "string" }, "description": "Optional angle labels (subset of DRAMATIC, INTERIOR, RESTRAINED, LYRICAL, KINETIC, IRONIC)." } }, "required": [ "bookId", "chapterId", "passage" ] }long_horizon_plot_doctorgeneration:runLong-horizon Plot Doctor. Reads the WHOLE book — outline plus every written chapter — and reports structural issues at the book level: throughline integrity, promise-and-payoff arcs, midpoint pivot, dead chapters, escalation curve, character agency, ending earn. Pure read.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." }, "focus": { "type": "string", "description": "Optional focus, e.g. 'arc of the antagonist' or 'midpoint pivot earned?'." } }, "required": [ "bookId" ] }debut_reader_readgeneration:runDebut Reader simulation. Reads a chapter (or excerpt) as a FIRST-TIME reader who has not seen the outline or any other chapter — reports exactly where a real reader would stumble. Ends with a one-line emotional read.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." }, "chapterId": { "type": "string", "description": "Read this chapter. Either chapterId or excerpt." }, "excerpt": { "type": "string" } }, "required": [ "bookId" ] }session_reviewgeneration:runEnd-of-session review. Summarises what changed during the writing window (default 24h, max 168) and proposes 3 concrete goals for the next session — based on chapter revisions, open foreshadowing, and unchecked required elements. Read-only.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "windowHours": { "type": "integer", "minimum": 1, "maximum": 168 } }, "required": [ "bookId" ] }
Reader feedback
Test-reader panel, emotional-arc mapping, and hook / ending scoring — see the book the way a first-time reader would.
run_test_reader_panelgeneration:runRun a panel of synthetic test readers (casual, genre fan, literary, skeptical newcomer, tired commuter, editor friend) on one chapter. Each persona reports engagement, confusion moments, emotional beats, and a one-line reaction. Divergence between personas is the signal.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." }, "chapterId": { "type": "string", "description": "Chapter UUID." }, "personas": { "type": "array", "items": { "type": "string", "enum": [ "casual", "literary", "genre-fan", "skeptical-newcomer", "tired-commuter", "editor-friend" ] }, "description": "Reader personas to include. Defaults to casual + genre-fan + literary + skeptical-newcomer." } }, "required": [ "bookId", "chapterId" ] }analyse_emotional_arcgeneration:runScore the emotional valence and intensity of every paragraph in a chapter and recommend tweaks to the arc shape. Optionally compare against the author's INTENDED arc to surface gaps between intended and felt.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." }, "chapterId": { "type": "string", "description": "Chapter UUID." }, "intendedArc": { "type": "string", "description": "Short prose: \"starts grief-heavy, lifts to bitter hope by the close\"." } }, "required": [ "bookId", "chapterId" ] }score_hook_strengthgeneration:runScore the opening of a chapter at four nested scopes — first sentence, first paragraph, first scene, first chapter — with a comp-aware verdict and the single highest-leverage edit. Defaults to the lowest-order chapter (the book opening) when no chapterId is given.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." }, "chapterId": { "type": "string", "description": "Chapter UUID." }, "compTitles": { "type": "string", "description": "Comma-separated comp titles to anchor the comp note." } }, "required": [ "bookId" ] }predict_ending_satisfactiongeneration:runCompare the PROMISES the first chapter makes against the DELIVERY in the last chapter and surface any gap that would leave a reader unsatisfied. Both first and last chapters must be written.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." }, "intendedClosingFeeling": { "type": "string", "description": "Optional author intent — e.g. \"exhausted but quietly hopeful\"." } }, "required": [ "bookId" ] }confused_reader_reviewgeneration:runRead one chapter cold, as a first-time reader who has not read the rest of the book, and report exactly where you got lost. Read-only — nothing is modified.
Input schema
{ "type": "object", "properties": { "chapterId": { "type": "string", "description": "Chapter UUID." }, "directive": { "type": "string", "maxLength": 400, "description": "Optional reader profile." } }, "required": [ "chapterId" ] }
Worldbuilding & continuity
World rules, timeline / geography / weather / travel-time checks, unit consistency, invented terms & calendars, the foreshadowing ledger, object & location trackers, scene consistency, and continuity diffs.
check_continuitygeneration:runRun a continuity check across the whole book. Flags cross-chapter inconsistencies (names, dates, prop placement, motivation).
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }add_world_rulebooks:writeRegister a rule of the book's world (#37). Pair with scan_world_rule_violations to flag chapters that contradict the rule.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." }, "name": { "type": "string" }, "category": { "type": "string", "enum": [ "magic", "tech", "social", "physics", "economy", "religion", "other" ], "default": "other" }, "rule": { "type": "string" }, "examples": { "type": "array", "items": { "type": "string" }, "default": [] }, "severity": { "type": "string", "enum": [ "hard", "soft" ], "default": "hard" } }, "required": [ "bookId", "name", "rule" ] }list_world_rulesbooks:readList every world rule registered for a book (#37) plus open-violation counts.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }update_world_rulebooks:writeUpdate a world rule (#37). Pass only fields you want to change.
Input schema
{ "type": "object", "properties": { "ruleId": { "type": "string", "description": "World-rule UUID." }, "name": { "type": "string" }, "category": { "type": "string", "enum": [ "magic", "tech", "social", "physics", "economy", "religion", "other" ] }, "rule": { "type": "string" }, "examples": { "type": "array", "items": { "type": "string" } }, "severity": { "type": "string", "enum": [ "hard", "soft" ] } }, "required": [ "ruleId" ] }delete_world_rulebooks:writeDelete a world rule (#37) and cascade its violation rows.
Input schema
{ "type": "object", "properties": { "ruleId": { "type": "string" } }, "required": [ "ruleId" ] }scan_world_rule_violationsgeneration:runScan one chapter (or every written chapter) for places the prose violates a registered world rule (#37). Wipes prior violation rows for the touched chapters before re-inserting. Costs LLM tokens.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string", "description": "Limit to one chapter (optional)." } }, "required": [ "bookId" ] }list_world_rule_violationsbooks:readList currently-open world-rule violations across a book (#37).
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "includeDismissed": { "type": "boolean", "default": false } }, "required": [ "bookId" ] }dismiss_world_rule_violationbooks:writeDismiss a world-rule violation flag (#37) — marks it intentional.
Input schema
{ "type": "object", "properties": { "violationId": { "type": "string" } }, "required": [ "violationId" ] }refresh_timeline_calendargeneration:runAuto-extract dated/sequenced events with calendar metadata — day-of-week, time-of-day, story-day counter, optional date label — for one chapter or every written chapter (#38). Wipes prior events for the touched chapters before re-inserting. Costs LLM tokens per chapter.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" } }, "required": [ "bookId" ] }get_story_calendarbooks:readReturn the book's timeline grouped as a calendar (#38) — story days, day-of-week, time-of-day buckets — under the invented calendar config when one exists, otherwise Gregorian. Read-only.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }refresh_geography_graphgeneration:runRe-derive the geography graph (#39) from the book's registered places + the prose. Inserts rows in book_geography_edge with distances and travel times the prose anchors. Costs LLM tokens.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "replace": { "type": "boolean", "default": false } }, "required": [ "bookId" ] }list_geography_edgesbooks:readList every registered geography edge for a book (#39). Read-only.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }refresh_weathergeneration:runAuto-extract season / weather / temperature / precipitation / time-of-day for one chapter (or every written chapter) and upsert into book_chapter_weather (#41). Costs LLM tokens per chapter.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" } }, "required": [ "bookId" ] }check_weather_continuitybooks:readWalk book_chapter_weather chapter-by-chapter (#41) and surface season jumps that don't fit the day-of-story gap plus same-day weather contradictions. Zero LLM cost.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }check_travel_sanitybooks:readWalk the geography graph + the timeline (#42) and surface chapters where a character covers a registered route faster than its travel time should allow. refresh_geography_graph and refresh_timeline_calendar must be up-to-date. Zero LLM cost.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "tolerancePct": { "type": "number", "minimum": 0, "maximum": 100, "default": 20 } }, "required": [ "bookId" ] }register_unitbooks:writeRegister a canonical unit / currency / language for the book (#43). Multiple canonicals per kind ARE allowed. Re-registering the same canonical for the same kind updates its aliases instead of inserting a duplicate. Use remove_unit to drop a canonical the prose no longer needs.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "kind": { "type": "string", "enum": [ "currency", "distance", "time", "temperature", "weight", "volume", "language", "other" ] }, "canonical": { "type": "string" }, "aliases": { "type": "array", "items": { "type": "string" }, "default": [] }, "note": { "type": "string" } }, "required": [ "bookId", "kind", "canonical" ] }list_unitsbooks:readList every registered unit / currency / language for a book (#43).
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }remove_unitbooks:writeDelete a registered unit (#43).
Input schema
{ "type": "object", "properties": { "unitId": { "type": "string" } }, "required": [ "unitId" ] }scan_unit_driftgeneration:runScan the manuscript for places the prose uses a unit / currency / language that conflicts with the registry (#43). Read-only. Costs LLM tokens proportional to manuscript size.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }add_invented_termbooks:writeRegister an invented term (custom / holiday / slang / general world-term) (#44). Adds a row to book_world_term so it shares the existing glossary surface.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "name": { "type": "string" }, "category": { "type": "string", "enum": [ "custom", "holiday", "slang", "term" ], "default": "term" }, "definition": { "type": "string" }, "aliases": { "type": "array", "items": { "type": "string" }, "default": [] } }, "required": [ "bookId", "name", "definition" ] }list_invented_termsbooks:readList invented terms registered for a book — customs, holidays, slang, general world terms (#44). Returns each term plus its in-prose mention count.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "kind": { "type": "string", "enum": [ "custom", "holiday", "slang", "term" ] } }, "required": [ "bookId" ] }refresh_invented_termsgeneration:runAuto-extract invented terms (customs, holidays, slang) from one chapter (or every written chapter) and log each usage to book_world_term_mention (#44). Terms not yet in book_world_term get inserted. Costs LLM tokens per chapter.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" } }, "required": [ "bookId" ] }scan_invented_term_contradictionsgeneration:runDiff per-chapter mentions of an invented term and surface places the prose's definition contradicts the canonical or itself across chapters (#44). Pass termId to focus one; omit to scan every invented term. Costs LLM tokens per term.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "termId": { "type": "string" } }, "required": [ "bookId" ] }get_invented_calendarbooks:readRead the saved invented calendar for a book (#45). Null if none saved.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }set_invented_calendarbooks:writeSave a complete invented calendar config for the book (#45). Replaces any existing config. `yearLengthDays` is recomputed from `months[].days` server-side.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "name": { "type": "string", "default": "Invented calendar" }, "eraName": { "type": [ "string", "null" ] }, "hoursPerDay": { "type": "integer", "minimum": 1, "maximum": 72, "default": 24 }, "daysPerWeek": { "type": "integer", "minimum": 1, "maximum": 20, "default": 7 }, "dayNames": { "type": "array", "items": { "type": "string" } }, "months": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string" }, "days": { "type": "integer", "minimum": 1, "maximum": 60 }, "season": { "type": [ "string", "null" ] } }, "required": [ "name", "days" ] } }, "festivals": { "type": "array", "default": [], "items": { "type": "object", "properties": { "name": { "type": "string" }, "month": { "type": "integer", "minimum": 1 }, "day": { "type": "integer", "minimum": 1 }, "description": { "type": [ "string", "null" ] } }, "required": [ "name", "month", "day" ] } } }, "required": [ "bookId", "dayNames", "months" ] }continuity_diffgeneration:runWhen a chapter was rewritten, check whether later chapters now reference facts the new version removed (#46). Compares the latest chapter_revisions snapshot to the current prose, computes which canonical facts are gone, then scans later chapters for references to them. Costs LLM tokens.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" } }, "required": [ "bookId", "chapterId" ] }register_foreshadowingbooks:writeRegister a foreshadowing setup (#86). The author flags a planted moment; the tracker stays 'open' until mark_foreshadowing_paid is called. Optional thread tag groups related setups.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "setupChapterId": { "type": "string", "description": "Chapter where the setup is planted." }, "setup": { "type": "string", "description": "Short description of what was set up (3-280 chars)." }, "thread": { "type": "string", "description": "Optional thread tag (max 60 chars)." }, "importance": { "type": "string", "enum": [ "critical", "important", "cosmetic" ], "description": "Defaults to \"important\"." } }, "required": [ "bookId", "setupChapterId", "setup" ] }mark_foreshadowing_paidbooks:writeMark a registered foreshadowing setup as paid off (#86). Provide the payoff chapter id and a one-line payoff description. Use status='dropped' instead when the author has decided not to pay it off.
Input schema
{ "type": "object", "properties": { "foreshadowingId": { "type": "string" }, "paidOffChapterId": { "type": "string" }, "payoff": { "type": "string", "description": "One-line payoff description (max 280 chars)." }, "status": { "type": "string", "enum": [ "paid", "dropped" ], "description": "Defaults to \"paid\"." } }, "required": [ "foreshadowingId" ] }list_unpaid_foreshadowingbooks:readList every open (unpaid) foreshadowing setup for a book (#86). Each row includes the setup chapter order and how many chapters have passed since. Read-only.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "importanceMin": { "type": "string", "enum": [ "critical", "important", "cosmetic" ], "description": "Filter by minimum importance. Defaults to all." } }, "required": [ "bookId" ] }did_anyone_say_this_earliergeneration:runSemantic search across the whole book (#97): did anyone — narrator or character — say something like this earlier? Returns near-quotes, paraphrases, and thematic echoes with chapter + paragraph anchors. Two-stage: a free token-overlap shortlist then an LLM refinement, so a query with no candidates costs zero LLM tokens.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "query": { "type": "string", "description": "The line, phrase, or idea to look for (3-600 chars)." }, "beforeChapterId": { "type": "string", "description": "Optional: only search chapters that come before this one." } }, "required": [ "bookId", "query" ] }check_scene_consistencygeneration:runFocused continuity check on three high-value axes only — time-of-day flips, weather contradictions, and travel times that don't fit (#96). Returns structured, per-chapter flags. Costs LLM tokens proportional to manuscript size.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }check_pronoun_continuitygeneration:runScan one chapter or all chapters for pronoun drift, roster mismatch, or unresolved pronouns (#22). Uses each character's declared pronouns as the source of truth. Costs LLM tokens proportional to prose scanned.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" } }, "required": [ "bookId" ] }refresh_object_trackergeneration:runAuto-extract tracked objects / MacGuffins from one chapter (or every written chapter) and write to book_object + book_object_state (#94). Each object's per-chapter state is rebuilt for the touched chapters so the trail stays in sync with the prose. Costs LLM tokens per chapter.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" } }, "required": [ "bookId" ] }list_object_trailbooks:readReturn every tracked object's per-chapter state trail (#94) — where it is, who holds it, what happened — sorted by chapter order. Read-only.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "objectName": { "type": "string", "description": "Optional: filter to a single named object (matches name or alias)." } }, "required": [ "bookId" ] }refresh_timelinegeneration:runAuto-extract dated / sequenced story events from one chapter (or every written chapter) and rebuild book_timeline_event (#93). Wipes the chapter's prior events before re-inserting. Costs LLM tokens per chapter.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" } }, "required": [ "bookId" ] }refresh_location_dbgeneration:runAuto-extract places from one chapter (or every written chapter) and merge them into book_world_term with kind='place' (#92). Captures lat/lng when the prose grounds the place to a real-world coordinate, and an ASCII floor plan when the interior is described in enough detail. Costs LLM tokens per chapter.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" } }, "required": [ "bookId" ] }set_chapter_checklistbooks:writeSet the per-chapter required-element checklist. Each item is a named beat the chapter must hit (callback / setup / payoff / beat / other). Replaces the existing list. Pass done: true for satisfied items, or an empty array to clear.
Input schema
{ "type": "object", "properties": { "chapterId": { "type": "string", "description": "Chapter UUID." }, "items": { "type": "array", "maxItems": 20, "items": { "type": "object", "properties": { "kind": { "type": "string", "enum": [ "callback", "setup", "payoff", "beat", "other" ] }, "text": { "type": "string", "minLength": 2, "maxLength": 280 }, "done": { "type": "boolean" } }, "required": [ "kind", "text" ] } } }, "required": [ "chapterId", "items" ] }auto_check_checklistgeneration:runVerify each item on a chapter's required-element checklist against the current prose using the model. Marks done=true with a one-line note when present; leaves unconfirmed items untouched. Read-only on the prose; mutates only the checklist column.
Input schema
{ "type": "object", "properties": { "chapterId": { "type": "string", "description": "Chapter UUID." } }, "required": [ "chapterId" ] }
Character craft
Character roster (want / fear / lie), inter-character conflicts, dialogue fingerprints, per-character voice consistency, and character arcs.
list_charactersbooks:readList the book's characters with the Truby-style want/fear/lie axes, POV flag, voice profile, and aliases.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }create_characterbooks:writeCreate a character row with name + optional want/fear/lie planning axes, voice profile, bio, role, aliases, and POV flag.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "name": { "type": "string" }, "aliases": { "type": "array", "items": { "type": "string" } }, "role": { "type": [ "string", "null" ] }, "bio": { "type": [ "string", "null" ] }, "voiceProfile": { "type": [ "string", "null" ] }, "want": { "type": [ "string", "null" ] }, "fear": { "type": [ "string", "null" ] }, "lie": { "type": [ "string", "null" ] }, "isPov": { "type": "boolean" } }, "required": [ "bookId", "name" ] }update_characterbooks:writePatch a character. Pass any subset of fields. Set want/fear/lie to null to clear those axes.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "characterId": { "type": "string" }, "name": { "type": "string" }, "aliases": { "type": "array", "items": { "type": "string" } }, "role": { "type": [ "string", "null" ] }, "bio": { "type": [ "string", "null" ] }, "voiceProfile": { "type": [ "string", "null" ] }, "want": { "type": [ "string", "null" ] }, "fear": { "type": [ "string", "null" ] }, "lie": { "type": [ "string", "null" ] }, "isPov": { "type": "boolean" } }, "required": [ "bookId", "characterId" ] }delete_characterbooks:writeRemove a character row. Conflict edges cascade.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "characterId": { "type": "string" } }, "required": [ "bookId", "characterId" ] }list_character_conflictsbooks:readList the inter-character conflict matrix. Each row is 'from <kind> to' — e.g. 'Marin blocks Alex'.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }add_character_conflictbooks:writeAdd a conflict edge. Kind: blocks, rivals, loves, fears, manipulates, protects, betrays, other.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "fromCharacterId": { "type": "string" }, "toCharacterId": { "type": "string" }, "kind": { "type": "string", "enum": [ "blocks", "rivals", "loves", "fears", "manipulates", "protects", "betrays", "other" ] }, "description": { "type": [ "string", "null" ] } }, "required": [ "bookId", "fromCharacterId", "toCharacterId", "kind" ] }remove_character_conflictbooks:writeRemove one conflict edge.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "conflictId": { "type": "string" } }, "required": [ "bookId", "conflictId" ] }refresh_character_dbgeneration:runRe-run the structured character extractor against one written chapter (or every written chapter) and MERGE the findings into the book's character DB (#91). Existing rows pick up newly-revealed details (voiceProfile, bio); new names become new rows; aliases are unioned. Updates lastSeenChapterOrder. Costs LLM tokens per chapter.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." }, "chapterId": { "type": "string", "description": "Optional: process just this chapter. Otherwise every written chapter." } }, "required": [ "bookId" ] }extract_dialogue_fingerprintsgeneration:runAuto-extract a per-character dialogue fingerprint (#11) — lexicon, average sentence length, hedges, contraction rate, signature phrases — and persist to book_character.dialogueFingerprint. Pass characterId to scope to one character; full-roster runs are capped at 12 per call (call again with characterId for any skipped). Costs LLM tokens per character.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "characterId": { "type": "string" } }, "required": [ "bookId" ] }check_dialogue_voice_consistencygeneration:runScan one chapter's dialogue for lines that sound like the wrong character (#12), using each cast member's stored dialogue fingerprint. Run extract_dialogue_fingerprints first so fingerprints exist. Costs LLM tokens proportional to chapter size.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" } }, "required": [ "bookId", "chapterId" ] }track_character_arcsgeneration:runAnalyse one or all characters' four-axis arc — want / need / lie / truth — and per-chapter movement, then persist need/truth + arcMovements (#13). Pass characterId to scope; full-roster runs are capped at 12 per call. Costs LLM tokens proportional to manuscript size × characters analysed.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "characterId": { "type": "string" } }, "required": [ "bookId" ] }detect_minor_character_bloatbooks:readFind named roster characters who appear ≤ maxAppearances times in written chapters (#18) — default threshold 1 (one-off mentions). Counts case-insensitive occurrences of each character's name + aliases. Pure heuristic — no LLM cost.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "maxAppearances": { "type": "number", "description": "Default 1 (1-10)." } }, "required": [ "bookId" ] }check_character_registergeneration:runFlag dialogue lines where a character drifts out of their declared class / cultural / regional register (#21). Requires bookCharacters.register to be set on the targeted characters; full-roster runs are capped at 12 per call. Costs LLM tokens proportional to prose scanned × characters checked.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "characterId": { "type": "string" } }, "required": [ "bookId" ] }
Persona & structural editing
Track-changes edits, editor personas, sentence variants, tense / POV flips, voice transplant, cut-by-percent, expand, reverse-outline, scene cards, synopsis, and the reviewable suggestion queue.
edit_chapter_with_personageneration:runRun one editor persona over a chapter and save the result as a REVIEWABLE pending chapter_suggestion — never an overwrite. Returns the new suggestionId plus a plain-English summary. Apply with accept_chapter_suggestion or dismiss with reject_chapter_suggestion.
Input schema
{ "type": "object", "properties": { "chapterId": { "type": "string", "description": "Chapter UUID." }, "personaKey": { "type": "string", "description": "Built-in key (developmental / line / copy / structural-only / wording-only …) or a user-saved persona key." }, "directive": { "type": "string", "maxLength": 800, "description": "Optional one-line editorial note layered on top of the persona's remit." } }, "required": [ "chapterId", "personaKey" ] }edit_book_with_personageneration:runApply one editor persona across a range of chapters (default whole book), producing one REVIEWABLE pending chapter_suggestion per chapter. Returns per-chapter suggestionIds + summaries. Accept or reject each independently.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." }, "personaKey": { "type": "string" }, "directive": { "type": "string", "maxLength": 800 }, "fromOrder": { "type": "integer", "minimum": 1 }, "toOrder": { "type": "integer", "minimum": 1 } }, "required": [ "bookId", "personaKey" ] }list_chapter_suggestionsbooks:readList pending (and optionally decided) chapter_suggestion rows for a book or a single chapter. Returns persona key, summary, and metadata — not the full proposed prose.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." }, "chapterId": { "type": "string", "description": "Chapter UUID." }, "includeDecided": { "type": "boolean" } }, "required": [ "bookId" ] }get_chapter_suggestionbooks:readRead the full proposed content of one chapter_suggestion (plus persona, summary, current content, metadata). Use to inspect the diff before accepting.
Input schema
{ "type": "object", "properties": { "suggestionId": { "type": "string", "description": "Suggestion UUID." } }, "required": [ "suggestionId" ] }accept_chapter_suggestionbooks:writeApply a pending chapter_suggestion — atomically snapshots current content (undoable via restore_chapter_revision) and overwrites with proposedContent. Re-accepting a decided suggestion is a no-op error.
Input schema
{ "type": "object", "properties": { "suggestionId": { "type": "string", "description": "Suggestion UUID." } }, "required": [ "suggestionId" ] }reject_chapter_suggestionbooks:writeReject a pending chapter_suggestion without applying it. Re-rejecting a decided suggestion is a no-op error.
Input schema
{ "type": "object", "properties": { "suggestionId": { "type": "string", "description": "Suggestion UUID." } }, "required": [ "suggestionId" ] }narrate_chapter_diffgeneration:runRead the CHANGES (not the new prose) of a chapter_revision aloud — synthesizes audio of a plain-English diff walkthrough, stores it in blob, and returns the audio URL plus the spoken text. Costs paid TTS credits.
Input schema
{ "type": "object", "properties": { "revisionId": { "type": "string", "description": "Chapter revision UUID." } }, "required": [ "revisionId" ] }comment_chaptergeneration:runLeave paragraph-anchored margin notes on a chapter — praise / note / concern / question — without touching the prose. Read-only; nothing is persisted.
Input schema
{ "type": "object", "properties": { "chapterId": { "type": "string", "description": "Chapter UUID." }, "focus": { "type": "string", "maxLength": 400, "description": "Optional focus area." } }, "required": [ "chapterId" ] }append_paragraph_to_chapterbooks:writeAppend a paragraph to a chapter's prose (Markdown). Snapshots existing content first (undoable via restore_chapter_revision) and keeps word-count / reading-time in sync.
Input schema
{ "type": "object", "properties": { "chapterId": { "type": "string", "description": "Chapter UUID." }, "paragraph": { "type": "string", "minLength": 1 } }, "required": [ "chapterId", "paragraph" ] }track_changes_editgeneration:runRun an editorial directive over a chapter and return the result as accept/reject HUNKS. Persists a chapter_suggestion with the full proposed prose; the response includes a paragraph diff with per-hunk indices for accept_suggestion_hunks.
Input schema
{ "type": "object", "properties": { "chapterId": { "type": "string", "description": "Chapter UUID." }, "directive": { "type": "string", "minLength": 3, "maxLength": 800 }, "personaKey": { "type": "string", "description": "Optional persona to drive the edit. Defaults to a line-edit pass." } }, "required": [ "chapterId", "directive" ] }accept_suggestion_hunksbooks:writeApply only chosen hunks from a track-changes chapter_suggestion. Diffs the suggestion against the chapter CURRENT content, rebuilds using original paragraphs for un-chosen hunks and proposed paragraphs for chosen ones. Snapshots first (undoable). Marks the suggestion accepted.
Input schema
{ "type": "object", "properties": { "suggestionId": { "type": "string", "description": "Suggestion UUID." }, "hunkIndices": { "type": "array", "items": { "type": "integer", "minimum": 0 }, "minItems": 1, "description": "0-based indices into the hunks array from track_changes_edit." } }, "required": [ "suggestionId", "hunkIndices" ] }sentence_variantsgeneration:runGenerate N labeled variants of a single sentence with named tradeoffs (tighter / lyrical / clipped / warmer / colder by default). Read-only — nothing is saved. Anchor with chapterId + paragraphIndex, or pass contextText.
Input schema
{ "type": "object", "properties": { "sentence": { "type": "string", "minLength": 3, "maxLength": 800 }, "chapterId": { "type": "string", "description": "Chapter UUID." }, "paragraphIndex": { "type": "integer", "minimum": 0 }, "contextText": { "type": "string", "maxLength": 2000 }, "voiceHint": { "type": "string", "maxLength": 280 }, "variantStyles": { "type": "array", "items": { "type": "string", "minLength": 2, "maxLength": 40 }, "minItems": 1, "maxItems": 8 } }, "required": [ "sentence" ] }cut_chapter_by_percentgeneration:runTighten a chapter by ~N% — every fact, beat, and dialogue line is preserved; only fat is removed. Saves a chapter_suggestion plus a paragraph diff preview. Default cut is 15%.
Input schema
{ "type": "object", "properties": { "chapterId": { "type": "string", "description": "Chapter UUID." }, "cutPercent": { "type": "integer", "minimum": 1, "maximum": 60, "description": "Percent of word count to cut. Defaults to 15." } }, "required": [ "chapterId" ] }expand_sentencegeneration:runExpand a sentence (or short seed) into a paragraph in the established voice. Read-only — nothing is persisted. Pass chapterId to pick up book voice + style bible; paragraphIndex to inject surrounding context.
Input schema
{ "type": "object", "properties": { "sentence": { "type": "string", "minLength": 3, "maxLength": 2000 }, "chapterId": { "type": "string", "description": "Chapter UUID." }, "paragraphIndex": { "type": "integer", "minimum": 0 }, "voiceHint": { "type": "string", "maxLength": 400 } }, "required": [ "sentence" ] }flip_chapter_tensegeneration:runFlip a chapter's narration past↔present. Dialogue is left untouched. Returns a chapter_suggestion plus a change log.
Input schema
{ "type": "object", "properties": { "chapterId": { "type": "string", "description": "Chapter UUID." }, "targetTense": { "type": "string", "enum": [ "past", "present" ] } }, "required": [ "chapterId", "targetTense" ] }shift_chapter_povgeneration:runShift a chapter's POV (typically third-limited ↔ first-person). Pass fromPov, toPov, optionally povCharacterId. Returns a chapter_suggestion plus the list of required changes the shift forced.
Input schema
{ "type": "object", "properties": { "chapterId": { "type": "string", "description": "Chapter UUID." }, "fromPov": { "type": "string", "minLength": 3, "maxLength": 80 }, "toPov": { "type": "string", "minLength": 3, "maxLength": 80 }, "povCharacterId": { "type": "string" } }, "required": [ "chapterId", "fromPov", "toPov" ] }
Scorecards, eval & ideation
Quality scorecards, eval exemplars, and the ideas inbox (capture / organise / triage).
list_chapter_scorecardsbooks:readList historical scorecards for a chapter (newest first) so the author can see how rewrites moved the grade.
Input schema
{ "type": "object", "properties": { "chapterId": { "type": "string", "description": "Chapter UUID." } }, "required": [ "chapterId" ] }list_book_scorecardsbooks:readList the latest scorecard per chapter for a book so the author can scan grade variance across the manuscript.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." } }, "required": [ "bookId" ] }list_eval_exemplarsbooks:readList the author's registered voice exemplars. Optional bookId narrows to exemplars tied to that book; catalog-wide exemplars (bookId=null) always appear.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." } } }add_eval_exemplarbooks:writeRegister a passage as 'this is what good looks like in MY voice'. The eval pass silently scores new drafts against these. Pass bookId to scope to one book; omit to make it catalog-wide.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." }, "label": { "type": "string", "description": "Short label (1–200 chars)." }, "content": { "type": "string", "description": "Exemplar prose (80–8000 chars)." }, "notes": { "type": "string" } }, "required": [ "label", "content" ] }remove_eval_exemplarbooks:writeDelete one of the author's voice exemplars.
Input schema
{ "type": "object", "properties": { "id": { "type": "string", "description": "Exemplar UUID." } }, "required": [ "id" ] }evaluate_against_exemplarsgeneration:runScore a draft against the author's registered exemplars and return the closest match plus per-exemplar voice / prose-quality scores. Use after a rewrite or before publishing to confirm voice hasn't drifted.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." }, "chapterId": { "type": "string", "description": "If supplied, the chapter's content is used as the draft." }, "draft": { "type": "string", "description": "Free-form draft to score; required when chapterId is omitted." }, "maxExemplars": { "type": "number", "description": "Max exemplars to compare (1–12). Default 6." } } }capture_ideabooks:writeDrop a fragment into the book's idea inbox — a line of dialogue, a stray image, a reminder. Files it without writing prose. Optionally tag it or assign it to a chapter; otherwise it sits in the inbox until organise_ideas runs.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "body": { "type": "string", "minLength": 2, "maxLength": 2000 }, "source": { "type": "string", "maxLength": 40 }, "targetChapterId": { "type": "string" }, "tags": { "type": "array", "items": { "type": "string" }, "maxItems": 8 } }, "required": [ "bookId", "body" ] }list_ideasbooks:readList captured ideas for a book. Defaults to the live (inbox + assigned) ideas; pass `status` to filter, or `chapterId` to scope to one chapter.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "status": { "type": "string", "enum": [ "inbox", "assigned", "applied", "archived", "all" ] }, "chapterId": { "type": "string" } }, "required": [ "bookId" ] }organise_ideasgeneration:runRead every inbox idea and assign each to the chapter it best fits, using the outline + chapter summaries. Sets targetChapterId and status='assigned' — does NOT write prose into chapters. The author still applies the lines by hand.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }update_idea_statusbooks:writeMove an idea to a new status — 'applied' when the line landed in a chapter, 'archived' when the author cuts it.
Input schema
{ "type": "object", "properties": { "ideaId": { "type": "string" }, "status": { "type": "string", "enum": [ "inbox", "assigned", "applied", "archived" ] } }, "required": [ "ideaId", "status" ] }
Cover, illustration & production
Choose a cover color, generate cover / back-cover / spine / chapter art, compose the print-ready wraparound, render EPUB / DOCX / PDF, export Markdown, and estimate print cost.
get_production_job_statusanalytics:readPoll a production (PDF/audiobook) job by id.
Input schema
{ "type": "object", "properties": { "jobId": { "type": "string" } }, "required": [ "jobId" ] }choose_cover_colorgeneration:runPick a tasteful cover background color (6-digit hex) for a book based on its mood, genre, and tone, and save it. Cheap LLM call.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "mood": { "type": "string", "description": "Optional mood hint (e.g. \"stormy\", \"warm and hopeful\")." } }, "required": [ "bookId" ] }compose_cover_spreadgeneration:runCompose the existing front cover, spine, and back cover into one print-ready wraparound spread (PNG). Uploads to Vercel Blob and records as a `cover_spread` image. Requires all three panels to exist already (run `generate_cover_art`, `generate_back_cover`, `generate_spine` first).
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }export_book_markdownbooks:readExport a fully written book as a single Markdown file, uploaded to Vercel Blob; returns a public download URL.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }produce_bookgeneration:runRender a fully written book to EPUB / DOCX (synchronous — bytes returned via blob URL) or PDF (async — dispatches a workflow job, returns jobId; poll with `get_production_job_status`).
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "format": { "type": "string", "enum": [ "epub", "docx", "pdf" ] } }, "required": [ "bookId", "format" ] }list_print_productsbooks:readList every Lulu print-on-demand product available on this instance (key, label, trim, cover finish, page-count bounds). Use the key with `get_print_estimate`.
Input schema
{ "type": "object", "properties": {} }get_print_estimateanalytics:readGet a retail print-on-demand quote from Lulu for the book with the chosen product, quantity, shipping option, and destination address. Read-only — no order is placed. Page count is estimated from word count; the real value may shift by a few pages after `produce_book` runs the PDF render.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "productKey": { "type": "string", "description": "A key from `list_print_products` (e.g. \"paperback-6x9-bw\")." }, "quantity": { "type": "integer", "minimum": 1, "maximum": 500 }, "shippingLevel": { "type": "string", "enum": [ "MAIL", "PRIORITY_MAIL", "GROUND", "EXPEDITED", "EXPRESS" ] }, "shippingAddress": { "type": "object", "description": "Lulu-style address (name, street1, city, state_code, postcode, country_code, …)." } }, "required": [ "bookId", "productKey", "quantity", "shippingLevel", "shippingAddress" ] }render_print_pdfgeneration:runKick off a print-ready PDF render for a book using its manuscript config (KDP / IngramSpark / Lulu / custom). Heavy (headless Chromium + Paged.js) — runs in a Vercel Workflow and returns a jobId; poll with `get_production_job_status`. Re-using an in-flight render for the same book returns the existing jobId (dedup).
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }
Narration & audiobook
List voices, preview a sample, narrate a chapter or the whole book, and build the M4B audiobook.
narrate_chaptergeneration:runSynthesize ElevenLabs narration for a chapter and upload the MP3 to Vercel Blob. Returns the audio URL. Requires ELEVENLABS_API_KEY + BLOB_READ_WRITE_TOKEN on the server.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" } }, "required": [ "bookId", "chapterId" ] }list_voicesbooks:readList the available ElevenLabs narration voices (id, name, accent, gender, age, preview URL). Use the voice id when configuring narration. Requires ELEVENLABS_API_KEY on the server.
Input schema
{ "type": "object", "properties": {} }narrate_bookgeneration:runSynthesize narration for every written, un-narrated chapter on a book. Runs serially per chapter (long — minutes per chapter). PAID — ElevenLabs charges per chapter.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "overwriteExisting": { "type": "boolean", "description": "Re-narrate chapters that already have audio (default false)." } }, "required": [ "bookId" ] }preview_voice_samplegeneration:runSynthesize a short (~30s) ElevenLabs sample using the opening paragraph of chapter 1 so the caller can hear the voice before committing to whole-book narration. PAID but cheap.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }export_audiobookgeneration:runConcatenate every ready-state chapter MP3 into a single M4B audiobook with embedded chapter markers, ambience, and intro/outro stings (if configured on the book). Requires every chapter to be narrated first. Uploads to Vercel Blob and returns the URL.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }extract_internal_monologue_voicegeneration:runProfile a POV character's internal-monologue voice (#15) — rumination cadence, attention pattern, somatic vocabulary, sample lines — and persist to book_character.monologueVoice. Only runs over chapters where the character is the POV. Costs LLM tokens proportional to their POV-chapter wordcount.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "characterId": { "type": "string" } }, "required": [ "bookId", "characterId" ] }
Translation
Clone the whole book into another language.
translate_bookgeneration:runCreate a new book that is a translation of an existing one into the target language (BCP-47 like "fr", "es", "pt-BR"). Clones metadata, seeds chapter shells, then translates each written chapter. EXPENSIVE — N LLM calls. Returns the new bookId.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "targetLanguage": { "type": "string", "minLength": 2 }, "sourceLanguage": { "type": "string" }, "glossary": { "type": "string", "description": "Optional Markdown list of canonical translations for proper names / specialty terms." } }, "required": [ "bookId", "targetLanguage" ] }
Sensitivity & QA
Run a sensitivity scan, list flags, and dismiss them.
run_sensitivity_scangeneration:runScan one or all written chapters for sensitive content (race, gender, religion, disability, violence, …) and persist flags.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" } }, "required": [ "bookId" ] }list_sensitivity_flagsanalytics:readList sensitivity flags for a book.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }dismiss_sensitivity_flagbooks:writeMark one sensitivity flag as dismissed.
Input schema
{ "type": "object", "properties": { "flagId": { "type": "string" } }, "required": [ "flagId" ] }
Collaboration
Collaborators, chapter assignments, and the activity feed — coordinate a multi-author book.
list_collaboratorsbooks:readList collaborators on a book.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }invite_collaboratorbooks:writeInvite a collaborator by email. Role: 'reader' (comments only) or 'editor' (edit access).
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "email": { "type": "string" }, "role": { "type": "string", "enum": [ "reader", "editor" ] } }, "required": [ "bookId", "email", "role" ] }remove_collaboratorbooks:writeRemove a collaborator from a book.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "email": { "type": "string" } }, "required": [ "bookId", "email" ] }list_chapter_assignmentsbooks:readList per-chapter assignments for a book (#89): assignee, review status, and note.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }assign_chapterbooks:writeAssign a chapter to an editor collaborator (#89), identified by assigneeEmail or assigneeUserId. Re-assigning resets status to 'assigned'. The assignee must already be an editor on the book.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" }, "assigneeEmail": { "type": "string" }, "assigneeUserId": { "type": "string" }, "status": { "type": "string", "enum": [ "assigned", "in_review", "changes_requested", "approved" ] }, "note": { "type": "string" } }, "required": [ "bookId", "chapterId" ] }update_assignment_statusbooks:writeUpdate a chapter assignment's review status (#89). Identify the row by chapterId; pass assigneeEmail when the chapter has more than one assignee.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" }, "assigneeEmail": { "type": "string" }, "status": { "type": "string", "enum": [ "assigned", "in_review", "changes_requested", "approved" ] }, "note": { "type": "string" } }, "required": [ "bookId", "chapterId", "status" ] }list_activitybooks:readRead the collaboration activity / audit feed for a book (#90): invites, joins, approvals, and suggestion decisions, newest first.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "limit": { "type": "integer", "minimum": 1, "maximum": 60 } }, "required": [ "bookId" ] }
Publishing
Publish / unpublish and run the end-to-end agentic publish pipeline.
publish_bookpublish:writePublish a book at /read/{slug}. Every chapter must have content. Returns the public reader URL.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "visibility": { "type": "string", "enum": [ "private", "unlisted", "public" ], "description": "Defaults to the book's current visibility." } }, "required": [ "bookId" ] }unpublish_bookpublish:writeRevert a published book to status `ready`. Reader page stops resolving.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }agentic_publishpublish:writeOne-shot publishing pipeline: outline (if needed) → write every empty chapter → optionally narrate → pick a cover color → publish to a public URL. Runs as a background job and returns a jobId immediately; poll it with `get_job_status`. Re-running while a job is active returns the existing jobId.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "narrate": { "type": "boolean", "description": "Include whole-book ElevenLabs narration in the pipeline (paid)." } }, "required": [ "bookId" ] }
Account, jobs & analytics
Usage & spend, background-job status, reader analytics, and author preferences.
get_usageaccount:readLifetime + 30-day rollups of LLM token usage across this account, grouped by call kind (outline, chapter, rewrite, …).
Input schema
{ "type": "object", "properties": {} }get_reader_analyticsanalytics:readPer-chapter reader stats for a published book (views, audio starts, completions, drop-off).
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }list_jobsanalytics:readList background jobs (outline / write / narrate / pdf). status: 'all' | 'active' | 'finished'.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "status": { "type": "string", "enum": [ "all", "active", "finished" ] }, "limit": { "type": "integer", "minimum": 1, "maximum": 50 } } }get_job_statusanalytics:readLook up one background job.
Input schema
{ "type": "object", "properties": { "jobId": { "type": "string" } }, "required": [ "jobId" ] }list_author_preferencesaccount:readRead the author's saved preferences (POV, em-dash usage, voice prefs, etc.) — applied across every book.
Input schema
{ "type": "object", "properties": {} }set_author_preferencebooks:writeSave a durable author preference (applied across every book).
Input schema
{ "type": "object", "properties": { "key": { "type": "string" }, "value": { "type": "string" } }, "required": [ "key", "value" ] }pause_jobbooks:writeRequest that a long-running job pause at its next batch boundary. The in-flight batch finishes; subsequent batches are skipped and the job exits cleanly. Returns the job's prior status.
Input schema
{ "type": "object", "properties": { "jobId": { "type": "string", "description": "Job UUID." } }, "required": [ "jobId" ] }forget_author_preferencebooks:writeDelete one saved author preference by key.
Input schema
{ "type": "object", "properties": { "key": { "type": "string" } }, "required": [ "key" ] }get_reader_statsanalytics:readAggregate reader-side telemetry for a published book — total views plus per-chapter views, audio starts, audio completions, and completion rate. Returns zeros until the reader UI starts emitting events.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }
Everything else
Tools that don't fall into a named domain above — still fully callable, still scope-gated.
get_chapterbooks:readFetch a single chapter (full prose content included).
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" } }, "required": [ "bookId", "chapterId" ] }list_book_documentsbooks:readList writer's-bible documents (characters, plot_outline, theme_outline, style_guide, style_references, worldbuilding, research_notes, glossary, synopsis, lore, setting_bible, era_research).
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }read_book_documentbooks:readRead the full content of one writer's-bible document.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "kind": { "type": "string", "enum": [ "characters", "plot_outline", "theme_outline", "style_guide", "style_references", "worldbuilding", "research_notes", "glossary", "synopsis", "lore", "setting_bible", "era_research" ] } }, "required": [ "bookId", "kind" ] }write_book_documentbooks:writeCreate or overwrite one writer's-bible document. The current revision is snapshotted first so the change is recoverable.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "kind": { "type": "string", "enum": [ "characters", "plot_outline", "theme_outline", "style_guide", "style_references", "worldbuilding", "research_notes", "glossary", "synopsis", "lore", "setting_bible", "era_research" ] }, "title": { "type": "string" }, "content": { "type": "string" } }, "required": [ "bookId", "kind", "content" ] }draft_book_documentgeneration:runAuto-draft one writer's-bible document from the premise + chapters. If a document already exists for that kind, pass confirm:true to overwrite it.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "kind": { "type": "string", "enum": [ "characters", "plot_outline", "theme_outline", "style_guide", "style_references", "worldbuilding", "research_notes", "glossary", "synopsis", "lore", "setting_bible", "era_research" ] }, "confirm": { "type": "boolean" }, "hint": { "type": [ "string", "null" ] } }, "required": [ "bookId", "kind" ] }list_book_document_revisionsbooks:readList saved snapshots of one writer's-bible document (newest first).
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "kind": { "type": "string", "enum": [ "characters", "plot_outline", "theme_outline", "style_guide", "style_references", "worldbuilding", "research_notes", "glossary", "synopsis", "lore", "setting_bible", "era_research" ] } }, "required": [ "bookId", "kind" ] }restore_book_document_revisionbooks:writeRoll a writer's-bible document back to a saved snapshot. The current content is snapshotted first so the restore is itself undoable.
Input schema
{ "type": "object", "properties": { "revisionId": { "type": "string" } }, "required": [ "revisionId" ] }get_credit_balanceaccount:readRead the account's current credit balance (number of generation credits remaining). One illustration is one credit; chapter writes and narration draw multiple credits depending on size.
Input schema
{ "type": "object", "properties": {} }detect_confusiongeneration:runFlag any paragraph a first-time reader would need to re-read — unclear pronouns, untagged characters, settings they cannot picture, jargon, time jumps, beats arriving without setup. Returns a structured per-paragraph list.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." }, "chapterId": { "type": "string", "description": "Chapter UUID." } }, "required": [ "bookId", "chapterId" ] }refresh_comp_titlesgeneration:runRank the closest comparable published books for the manuscript so far, replacing the prior list. Anchors on training memory of published titles (no live web fetch). If statedComps is supplied, the note calls out drift between intended and actual positioning.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." }, "statedComps": { "type": "string", "description": "Author-named comps to compare drift against — comma-separated." } }, "required": [ "bookId" ] }list_book_comp_titlesbooks:readList the saved comp titles for a book, ordered by rank.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." } }, "required": [ "bookId" ] }list_writing_sessionsbooks:readList the user's recent writing sessions, newest first.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." }, "limit": { "type": "number", "description": "Max sessions (1–50). Default 10." } } }session_changelogbooks:readBuild a structured changelog from a writing session — counts by event kind, accumulated notes, words added, and the auto-summary.
Input schema
{ "type": "object", "properties": { "sessionId": { "type": "string", "description": "Writing session UUID." } }, "required": [ "sessionId" ] }stuck_modegeneration:runThe author said they're stuck. Diagnose the kind of stuck, ask 3 targeted questions, and propose 3 distinct paths forward each with a concrete first step. Pass the author's verbatim message. If bookId is supplied, the last-chapter tail is attached for grounding.
Input schema
{ "type": "object", "properties": { "userMessage": { "type": "string", "description": "The author's verbatim message." }, "bookId": { "type": "string", "description": "Book UUID." } }, "required": [ "userMessage" ] }daily_rereadgeneration:runPick the 1–3 paragraphs from the author's recent writing most worth rereading before today's session. Uses chapters updated in the last lookbackHours (default 26).
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." }, "lookbackHours": { "type": "number", "description": "Window in hours (1–168). Default 26." } }, "required": [ "bookId" ] }score_chapter_cardgeneration:runScore a chapter on five axes — voice, prose, continuity, pacing, hook — with an overall score and short notes per axis. Persists the result so regression checks can compare across rewrites.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." }, "chapterId": { "type": "string", "description": "Chapter UUID." } }, "required": [ "bookId", "chapterId" ] }check_chapter_regressionbooks:readCompare the newest scorecard for a chapter against the previous one. Returns per-axis deltas and warns when any axis dropped by more than threshold (default 5).
Input schema
{ "type": "object", "properties": { "chapterId": { "type": "string", "description": "Chapter UUID." }, "threshold": { "type": "number", "description": "Drop threshold (1–50). Default 5." } }, "required": [ "chapterId" ] }chekhov_reportbooks:readChekhov's-gun report (#40): every introduced object that the prose never escalates past 'mentioned'. Reads chekhovStatus on book_object_state (populated by refreshObjectTracker). Zero LLM cost.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "maxLatencyChapters": { "type": "integer", "minimum": 0, "default": 3 } }, "required": [ "bookId" ] }in_scene_nowbooks:readReturn the objects 'in scene right now' for a given chapter (#40), grouped by chekhovStatus. Zero LLM cost.
Input schema
{ "type": "object", "properties": { "chapterId": { "type": "string" } }, "required": [ "chapterId" ] }check_off_page_durationbooks:readReturn characters who've been off-page for too long (#16). Compares each character's lastSeenChapterOrder against the most recently written chapter; flags absences ≥ maxAbsenceChapters (default 4). Also surfaces never-seen characters and stale trackers. Pure heuristic — no LLM cost.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "maxAbsenceChapters": { "type": "number", "description": "Default 4 (1-50)." } }, "required": [ "bookId" ] }check_antagonist_escalationgeneration:runAnalyse an antagonist character's tactics, motivations, and on-page intensity across the manuscript (#17). Persists the per-chapter escalation ladder to book_character.escalationLadder and returns coherence flags (drop, whiplash, motiveShift, plateau). Costs LLM tokens proportional to manuscript size.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "characterId": { "type": "string" } }, "required": [ "bookId", "characterId" ] }lint_name_collisionsbooks:readDetect roster name pairs readers may confuse (#19) — Jon/Jonah, Mark/Marcus, etc. — by shared prefix and Levenshtein edit distance across canonical names + aliases. Pure heuristic — no LLM cost.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" } }, "required": [ "bookId" ] }check_age_appropriate_behaviorgeneration:runFlag lines where a character thinks or speaks well outside their declared age (#20). Skips characters with no age set. Pass characterId / chapterId to scope; full-roster runs are capped at 12 per call. Costs LLM tokens proportional to prose scanned × characters checked.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "characterId": { "type": "string" }, "chapterId": { "type": "string" } }, "required": [ "bookId" ] }analyze_setups_and_payoffsgeneration:runExtract the complete setup → payoff graph across the outline (and drafted prose where available). Persists pairs into bookForeshadowing, REPLACING prior agent-generated rows (author rows untouched). Returns orphan setups and orphan payoffs. Pass persist: false for a dry-run. Needs ≥3 chapters.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." }, "persist": { "type": "boolean", "description": "Default true — write extracted pairs to bookForeshadowing." } }, "required": [ "bookId" ] }map_subplotsgeneration:runIdentify the book's A (main plot), B (secondary thread), and optional C threads, then map each chapter to which threads it carries. Returns threads, a per-chapter carry matrix, gap spans (thread out ≥3 chapters), and edit recommendations. Needs ≥4 chapters.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." } }, "required": [ "bookId" ] }analyze_tension_curvegeneration:runScore every chapter's tension 0–100, detect mid/late sags (≥3 consecutive low-tension chapters in a climbing section), and propose reorder/insert/compress moves. Optionally persists scores into chapters.tensionTarget; by default preserves author-set targets unless overwriteAuthorTargets: true. Needs ≥4 chapters.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." }, "persist": { "type": "boolean", "description": "Write analyzed scores into chapters.tensionTarget. Defaults false." }, "overwriteAuthorTargets": { "type": "boolean", "description": "When persisting, also overwrite author-set targets. Defaults false." } }, "required": [ "bookId" ] }get_chapter_beat_mapbooks:readFor the book's chosen beat-sheet (Save the Cat / Hero's Journey / Three-Act / etc.), return the per-chapter mapping of order → structural beat (label + intent + nominal position 0..1). Pick a framework first with set_plan({ beatSheetTemplate }).
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string", "description": "Book UUID." } }, "required": [ "bookId" ] }write_all_chaptersgeneration:runWrite every remaining (empty) chapter of a book in one call. Writes chapter 1 first to seed the style bible, then fans out chapters 2..N in parallel. Pass `parallel: false` to write strictly in order when each chapter must read the previous chapter's prose. `rewriteAll: true` overwrites existing prose. Returns per-chapter words plus a failures list. Long-running — for big books prefer `enqueue_write_all_chapters`.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "rewriteAll": { "type": "boolean", "description": "Rewrite ALL chapters (overwriting prose). Defaults false — fills empties only." }, "selfCritique": { "type": "boolean", "description": "Run the cheap consistency pass on every chapter (slower, catches drift)." }, "parallel": { "type": "boolean", "description": "Fan out chapters 2..N in parallel after chapter 1 (default true)." } }, "required": [ "bookId" ] }enqueue_write_all_chaptersgeneration:runStart write_all_chapters as a background job and return a jobId immediately, so the caller doesn't block on minutes of generation. Poll status with `get_job_status`. Refuses if another writeAllChapters job for this book is already queued or running. (In serverless deployments without a durable worker the background loop may be killed when the function exits.)
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "rewriteAll": { "type": "boolean" }, "selfCritique": { "type": "boolean" } }, "required": [ "bookId" ] }preview_chaptergeneration:runGenerate one chapter's prose WITHOUT saving it. Returns the draft text so the caller can approve it before persisting with `update_chapter` / `write_chapter`. Identify the chapter by chapterId OR order.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" }, "order": { "type": "integer", "minimum": 1 } }, "required": [ "bookId" ] }research_chaptergeneration:runRun focused web research (Perplexity) for ONE chapter — its title plus summary become the query. For non-fiction where each chapter needs current, sourced facts. Persists the brief inline at the END of the chapter's summary so the writer picks it up.
Input schema
{ "type": "object", "properties": { "bookId": { "type": "string" }, "chapterId": { "type": "string" } }, "required": [ "bookId", "chapterId" ] }research_topicgeneration:runRun web-grounded research (Perplexity) on a premise and return a sourced brief. If `bookId` is provided, the brief is saved onto that book for writing (and a cached existing brief is returned without a new call).
Input schema
{ "type": "object", "properties": { "premise": { "type": "string" }, "genreHint": { "type": "string" }, "bookId": { "type": "string", "description": "If set, the brief is saved onto this book." } }, "required": [ "premise" ] }