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_books books:read

    List every book in this account (newest first). Returns id, title, status, visibility, slug.

    Input schema
    {
      "type": "object",
      "properties": {}
    }
  • get_book books:read

    Fetch 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_book books:write

    Create 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_book books:write

    Patch 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_book books:write

    Soft-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_book books:write

    Restore 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_outline generation:run

    Run 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_plan books:read

    Read 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_plan books:write

    Write 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_sheets books:read

    List 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_interview generation:run

    Premise-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_pitches generation:run

    Three 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_pitches books:read

    List the most recent round of premise pitches.

    Input schema
    {
      "type": "object",
      "properties": {
        "bookId": {
          "type": "string"
        }
      },
      "required": [
        "bookId"
      ]
    }
  • select_premise_pitch books:write

    Lock 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_genre generation:run

    Auto-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_era generation:run

    Era / 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_outline generation:run

    Score 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_variants books:read

    List the most recent round of outline variants (#14).

    Input schema
    {
      "type": "object",
      "properties": {
        "bookId": {
          "type": "string"
        }
      },
      "required": [
        "bookId"
      ]
    }
  • generate_outline_variants generation:run

    Three 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_variant books:write

    Apply 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_snapshots books:read

    List every captured outline mutation (#22) — pair with restore_outline_snapshot.

    Input schema
    {
      "type": "object",
      "properties": {
        "bookId": {
          "type": "string"
        }
      },
      "required": [
        "bookId"
      ]
    }
  • restore_outline_snapshot books:write

    Revert the outline to a saved snapshot in place.

    Input schema
    {
      "type": "object",
      "properties": {
        "bookId": {
          "type": "string"
        },
        "snapshotId": {
          "type": "string"
        }
      },
      "required": [
        "bookId",
        "snapshotId"
      ]
    }
  • list_mood_references books:read

    List tone / mood reference photos (#12) for this book.

    Input schema
    {
      "type": "object",
      "properties": {
        "bookId": {
          "type": "string"
        }
      },
      "required": [
        "bookId"
      ]
    }
  • generate_chapter_image generation:run

    Generate 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_art generation:run

    Generate 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_cover generation:run

    Generate 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_spine generation:run

    Generate 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_generation books:write

    Cancel 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_caption books:write

    Edit 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_reference books:write

    Delete a mood reference image (#12) from this book.

    Input schema
    {
      "type": "object",
      "properties": {
        "bookId": {
          "type": "string"
        },
        "imageId": {
          "type": "string"
        }
      },
      "required": [
        "bookId",
        "imageId"
      ]
    }
  • plan_deadline generation:run

    Plan 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_lookup generation:run

    Genre 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_calendar generation:run

    Generate 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_graph generation:run

    Re-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_paragraph generation:run

    Rewrite 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_passage generation:run

    Rewrite 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_section generation:run

    Re-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_variants generation:run

    Build 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_cards generation:run

    Decompose 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_synopsis generation:run

    Generate 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_test generation:run

    Stress-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_copy generation:run

    Generate 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_chapter generation:run

    Generate 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_chapter generation:run

    Apply 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_meta books:write

    Update 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_chapters books:write

    Atomically 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_revisions books:read

    List saved snapshots of a chapter (newest first).

    Input schema
    {
      "type": "object",
      "properties": {
        "bookId": {
          "type": "string"
        },
        "chapterId": {
          "type": "string"
        }
      },
      "required": [
        "bookId",
        "chapterId"
      ]
    }
  • restore_chapter_revision books:write

    Roll a chapter back to a saved snapshot. The current content is snapshotted first.

    Input schema
    {
      "type": "object",
      "properties": {
        "revisionId": {
          "type": "string"
        }
      },
      "required": [
        "revisionId"
      ]
    }
  • list_chapters books:read

    List 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_chapter books:write

    Overwrite 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_chapter books:write

    Split 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_chapters books:write

    Merge 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_range generation:run

    Apply 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_revision generation:run

    Explain 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_preserving generation:run

    Rewrite 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_outline generation:run

    Derive 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_drift generation:run

    Re-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_holes generation:run

    Scan 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_prose books:read

    Static 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_repetition books:read

    Detect 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_replacements generation:run

    Find 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_readability books:read

    Score 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_drift books:read

    Measure 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_words books:write

    Set 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_words books:read

    Read the per-book forbidden-word list.

    Input schema
    {
      "type": "object",
      "properties": {
        "bookId": {
          "type": "string"
        }
      },
      "required": [
        "bookId"
      ]
    }
  • set_style_rules books:write

    Set 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_rules books:read

    Read 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_rhythm books:read

    Sentence-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_words books:read

    Filter-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_balance books:read

    Sensory-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_density books:read

    Adverb-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_tags books:read

    Dialogue-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_language books:read

    Body-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_nouns books:read

    Concrete-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_slippage books:read

    POV-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_consistency books:read

    Tense-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_variations generation:run

    Cadence 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_rewrites generation:run

    Show, 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_cliches generation:run

    Semantic 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_telegraphing generation:run

    Telegraphing 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_upgrades generation:run

    Verb-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_chapter generation:run

    LLM 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_chapters generation:run

    Run 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_specialists books:read

    List 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_specialist generation:run

    Run 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_critique generation:run

    Fan 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_verify generation:run

    Adversarial 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_synthesize generation:run

    Editor-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_tournament generation:run

    N-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_doctor generation:run

    Long-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_read generation:run

    Debut 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_review generation:run

    End-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_panel generation:run

    Run 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_arc generation:run

    Score 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_strength generation:run

    Score 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_satisfaction generation:run

    Compare 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_review generation:run

    Read 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_continuity generation:run

    Run 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_rule books:write

    Register 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_rules books:read

    List every world rule registered for a book (#37) plus open-violation counts.

    Input schema
    {
      "type": "object",
      "properties": {
        "bookId": {
          "type": "string"
        }
      },
      "required": [
        "bookId"
      ]
    }
  • update_world_rule books:write

    Update 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_rule books:write

    Delete a world rule (#37) and cascade its violation rows.

    Input schema
    {
      "type": "object",
      "properties": {
        "ruleId": {
          "type": "string"
        }
      },
      "required": [
        "ruleId"
      ]
    }
  • scan_world_rule_violations generation:run

    Scan 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_violations books:read

    List 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_violation books:write

    Dismiss a world-rule violation flag (#37) — marks it intentional.

    Input schema
    {
      "type": "object",
      "properties": {
        "violationId": {
          "type": "string"
        }
      },
      "required": [
        "violationId"
      ]
    }
  • refresh_timeline_calendar generation:run

    Auto-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_calendar books:read

    Return 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_graph generation:run

    Re-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_edges books:read

    List every registered geography edge for a book (#39). Read-only.

    Input schema
    {
      "type": "object",
      "properties": {
        "bookId": {
          "type": "string"
        }
      },
      "required": [
        "bookId"
      ]
    }
  • refresh_weather generation:run

    Auto-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_continuity books:read

    Walk 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_sanity books:read

    Walk 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_unit books:write

    Register 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_units books:read

    List every registered unit / currency / language for a book (#43).

    Input schema
    {
      "type": "object",
      "properties": {
        "bookId": {
          "type": "string"
        }
      },
      "required": [
        "bookId"
      ]
    }
  • remove_unit books:write

    Delete a registered unit (#43).

    Input schema
    {
      "type": "object",
      "properties": {
        "unitId": {
          "type": "string"
        }
      },
      "required": [
        "unitId"
      ]
    }
  • scan_unit_drift generation:run

    Scan 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_term books:write

    Register 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_terms books:read

    List 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_terms generation:run

    Auto-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_contradictions generation:run

    Diff 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_calendar books:read

    Read the saved invented calendar for a book (#45). Null if none saved.

    Input schema
    {
      "type": "object",
      "properties": {
        "bookId": {
          "type": "string"
        }
      },
      "required": [
        "bookId"
      ]
    }
  • set_invented_calendar books:write

    Save 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_diff generation:run

    When 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_foreshadowing books:write

    Register 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_paid books:write

    Mark 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_foreshadowing books:read

    List 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_earlier generation:run

    Semantic 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_consistency generation:run

    Focused 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_continuity generation:run

    Scan 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_tracker generation:run

    Auto-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_trail books:read

    Return 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_timeline generation:run

    Auto-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_db generation:run

    Auto-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_checklist books:write

    Set 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_checklist generation:run

    Verify 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_characters books:read

    List 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_character books:write

    Create 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_character books:write

    Patch 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_character books:write

    Remove a character row. Conflict edges cascade.

    Input schema
    {
      "type": "object",
      "properties": {
        "bookId": {
          "type": "string"
        },
        "characterId": {
          "type": "string"
        }
      },
      "required": [
        "bookId",
        "characterId"
      ]
    }
  • list_character_conflicts books:read

    List 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_conflict books:write

    Add 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_conflict books:write

    Remove one conflict edge.

    Input schema
    {
      "type": "object",
      "properties": {
        "bookId": {
          "type": "string"
        },
        "conflictId": {
          "type": "string"
        }
      },
      "required": [
        "bookId",
        "conflictId"
      ]
    }
  • refresh_character_db generation:run

    Re-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_fingerprints generation:run

    Auto-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_consistency generation:run

    Scan 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_arcs generation:run

    Analyse 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_bloat books:read

    Find 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_register generation:run

    Flag 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_persona generation:run

    Run 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_persona generation:run

    Apply 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_suggestions books:read

    List 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_suggestion books:read

    Read 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_suggestion books:write

    Apply 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_suggestion books:write

    Reject 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_diff generation:run

    Read 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_chapter generation:run

    Leave 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_chapter books:write

    Append 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_edit generation:run

    Run 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_hunks books:write

    Apply 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_variants generation:run

    Generate 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_percent generation:run

    Tighten 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_sentence generation:run

    Expand 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_tense generation:run

    Flip 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_pov generation:run

    Shift 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_scorecards books:read

    List 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_scorecards books:read

    List 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_exemplars books:read

    List 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_exemplar books:write

    Register 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_exemplar books:write

    Delete one of the author's voice exemplars.

    Input schema
    {
      "type": "object",
      "properties": {
        "id": {
          "type": "string",
          "description": "Exemplar UUID."
        }
      },
      "required": [
        "id"
      ]
    }
  • evaluate_against_exemplars generation:run

    Score 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_idea books:write

    Drop 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_ideas books:read

    List 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_ideas generation:run

    Read 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_status books:write

    Move 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_status analytics:read

    Poll a production (PDF/audiobook) job by id.

    Input schema
    {
      "type": "object",
      "properties": {
        "jobId": {
          "type": "string"
        }
      },
      "required": [
        "jobId"
      ]
    }
  • choose_cover_color generation:run

    Pick 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_spread generation:run

    Compose 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_markdown books:read

    Export 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_book generation:run

    Render 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_products books:read

    List 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_estimate analytics:read

    Get 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_pdf generation:run

    Kick 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_chapter generation:run

    Synthesize 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_voices books:read

    List 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_book generation:run

    Synthesize 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_sample generation:run

    Synthesize 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_audiobook generation:run

    Concatenate 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_voice generation:run

    Profile 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_book generation:run

    Create 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_scan generation:run

    Scan 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_flags analytics:read

    List sensitivity flags for a book.

    Input schema
    {
      "type": "object",
      "properties": {
        "bookId": {
          "type": "string"
        }
      },
      "required": [
        "bookId"
      ]
    }
  • dismiss_sensitivity_flag books:write

    Mark 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_collaborators books:read

    List collaborators on a book.

    Input schema
    {
      "type": "object",
      "properties": {
        "bookId": {
          "type": "string"
        }
      },
      "required": [
        "bookId"
      ]
    }
  • invite_collaborator books:write

    Invite 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_collaborator books:write

    Remove a collaborator from a book.

    Input schema
    {
      "type": "object",
      "properties": {
        "bookId": {
          "type": "string"
        },
        "email": {
          "type": "string"
        }
      },
      "required": [
        "bookId",
        "email"
      ]
    }
  • list_chapter_assignments books:read

    List per-chapter assignments for a book (#89): assignee, review status, and note.

    Input schema
    {
      "type": "object",
      "properties": {
        "bookId": {
          "type": "string"
        }
      },
      "required": [
        "bookId"
      ]
    }
  • assign_chapter books:write

    Assign 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_status books:write

    Update 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_activity books:read

    Read 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_book publish:write

    Publish 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_book publish:write

    Revert a published book to status `ready`. Reader page stops resolving.

    Input schema
    {
      "type": "object",
      "properties": {
        "bookId": {
          "type": "string"
        }
      },
      "required": [
        "bookId"
      ]
    }
  • agentic_publish publish:write

    One-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_usage account:read

    Lifetime + 30-day rollups of LLM token usage across this account, grouped by call kind (outline, chapter, rewrite, …).

    Input schema
    {
      "type": "object",
      "properties": {}
    }
  • get_reader_analytics analytics:read

    Per-chapter reader stats for a published book (views, audio starts, completions, drop-off).

    Input schema
    {
      "type": "object",
      "properties": {
        "bookId": {
          "type": "string"
        }
      },
      "required": [
        "bookId"
      ]
    }
  • list_jobs analytics:read

    List 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_status analytics:read

    Look up one background job.

    Input schema
    {
      "type": "object",
      "properties": {
        "jobId": {
          "type": "string"
        }
      },
      "required": [
        "jobId"
      ]
    }
  • list_author_preferences account:read

    Read the author's saved preferences (POV, em-dash usage, voice prefs, etc.) — applied across every book.

    Input schema
    {
      "type": "object",
      "properties": {}
    }
  • set_author_preference books:write

    Save a durable author preference (applied across every book).

    Input schema
    {
      "type": "object",
      "properties": {
        "key": {
          "type": "string"
        },
        "value": {
          "type": "string"
        }
      },
      "required": [
        "key",
        "value"
      ]
    }
  • pause_job books:write

    Request 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_preference books:write

    Delete one saved author preference by key.

    Input schema
    {
      "type": "object",
      "properties": {
        "key": {
          "type": "string"
        }
      },
      "required": [
        "key"
      ]
    }
  • get_reader_stats analytics:read

    Aggregate 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_chapter books:read

    Fetch a single chapter (full prose content included).

    Input schema
    {
      "type": "object",
      "properties": {
        "bookId": {
          "type": "string"
        },
        "chapterId": {
          "type": "string"
        }
      },
      "required": [
        "bookId",
        "chapterId"
      ]
    }
  • list_book_documents books:read

    List 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_document books:read

    Read 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_document books:write

    Create 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_document generation:run

    Auto-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_revisions books:read

    List 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_revision books:write

    Roll 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_balance account:read

    Read 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_confusion generation:run

    Flag 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_titles generation:run

    Rank 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_titles books:read

    List 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_sessions books:read

    List 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_changelog books:read

    Build 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_mode generation:run

    The 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_reread generation:run

    Pick 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_card generation:run

    Score 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_regression books:read

    Compare 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_report books:read

    Chekhov'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_now books:read

    Return 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_duration books:read

    Return 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_escalation generation:run

    Analyse 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_collisions books:read

    Detect 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_behavior generation:run

    Flag 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_payoffs generation:run

    Extract 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_subplots generation:run

    Identify 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_curve generation:run

    Score 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_map books:read

    For 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_chapters generation:run

    Write 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_chapters generation:run

    Start 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_chapter generation:run

    Generate 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_chapter generation:run

    Run 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_topic generation:run

    Run 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"
      ]
    }