Table of Contents

Prose MCP Tools

GENERATED — do not hand-edit. Produced by ToolDocGenerator from the [McpServerTool] + [Description] attributes in src/Prose.Mcp/Tools*.cs, the same source the MCP host registers via WithToolsFromAssembly(). To refresh:

dotnet run --project src/Prose.Mcp -- --export-tools docs/MCP_TOOLS.md

All tools are MCP-prefixed mcp__prose__<name> by the client. Most return a JSON string; the canon is the SQL database, scoped to the active Universe.

293 tools across 53 tool families.

Families

Family Tools
Archetype 1
Barks Export 1
Beat Archive 1
Bible 3
Book Health 1
Book Logic 3
Canon 9
Canon Doc 5
Character Gear 3
Combat 1
Config 13
Context 5
Contribution 4
Core Entity Crud 5
Craft Instrument 3
Data Integrity 2
Edit Session 4
Encyclopedia 35
Entity Context 7
Entity Tag 3
Factory 12
Findings 5
Gear Entity Crud 8
Glossary 4
Graph Query 4
Hub 3
Ledger 4
Lore Triple 4
Node 31
Noun Consistency 2
Obligation 11
One Shot Generation 1
Operator Key 5
Planning 2
Plant Payoff 6
Quality 5
Reading 4
Repository 3
Ruling 6
Scene 4
Species 2
Spelling 3
Story 4
Survey 7
Universe 5
Universe Interchange 4
Verification 2
Voice 6
Workflow Monitor 3
World 4
World Entity Crud 6
World Modelling 11
Writing 3

Archetype

ArchetypeTools

create_archetype

Create or update an archetype: an occupational or social role in the world (street roles such as Stitcher, Channeler, Read, Psyker, Ghost, Street Samurai and Splicer; or a behavioural type). An existing name updates that record. Omitted scalar fields are LEFT UNCHANGED. willAlways, willNever and unless split on ';' (their items contain commas); tags split on ','. A list given replaces the old one; '[]' clears it. Returns the record as read back.

  • name (string, required) — Archetype name. Required.
  • category (string, optional) — Category, e.g. 'street role', 'combat', 'social'.
  • description (string, optional) — What the role is.
  • behavioralSignature (string, optional) — How it shows in behaviour.
  • underStress (string, optional) — Under stress.
  • atRest (string, optional) — At rest.
  • willAlways (string, optional) — ';'-separated things it will always do.
  • willNever (string, optional) — ';'-separated things it will never do.
  • unless (string, optional) — ';'-separated exceptions.
  • tags (string, optional) — ','-separated tags.

Barks Export

BarksExportTools

export_barks

Walk a universe's (or one book/chapter's) beats and return every beat with a single recorded POV speaker as {barkId, speakerEntitySlug, text, context}. Beats with no recorded POV are skipped and counted, never silently dropped.

  • universe (string, required) — Universe slug, e.g. 'eve'.
  • node (string, optional) — Optional slug/NodeCode/GUID of one book or chapter to scope the walk to. Omit for the whole universe.

Beat Archive

BeatArchiveTools

get_beat_archive

Get the Beat Context Archive for one beat — everything that fed it, resolved as of that beat's own trace timestamp: prose, per-service coverage trace, the full LLM system/user prompt and response, the entity roster resolved to that moment's canon (including psychology/speech fields), and the DCM doc list resolved to that moment's content. Use this to audit exactly what the prose engine saw and did for a specific beat, after the fact.

  • beatId (string, required) — The beat's Guid id.

Bible

BibleTools

get_character_profile

Load the Character Profile — the protagonist's core contradiction, signature behavior, voice anchors. Often Kyle's profile in this project.

  • (no parameters)

get_story_bible

Load the Story Bible — structural rules for narrative shape: act structure, beat anatomy, motif planting, dialogue cadence.

  • (no parameters)

get_tone_bible

Load the Tone Bible — voice, register, sensory palette, what to do and what not to do for prose. Inject this into the system prompt when drafting prose.

  • (no parameters)

Book Health

BookHealthTools

publish_readiness

docs/LOGIC.md §9's six-check publish-readiness convergence gate, computed as one answer: (1) zero open BLOCKER/MODERATE logic-sweep findings, (2) zero open CONTRADICTED fact-ledger claims, (3) two consecutive dry logic-sweep rounds against the book's current text, (4) blast-radius recheck clean on every beat, (5) zero open High/BLOCKER Reader-Proxy QA findings, (6) the narrative obligation ledger balanced (RFC 0013). Each check answers Pass, Fail, or CouldNotLook — the last meaning its instrument never ran on this book, read nothing, read only part, or read prose that has since changed. CouldNotLook blocks like a failure; a zero from an instrument that did not look is not evidence of anything. Read-only — makes no LLM calls and runs no new checks, only reads what earlier sweep/audit/ledger runs already filed or persisted.

  • nodeIdOrSlug (string, required) — Node id (GUID) or slug — a book or a lone chapter.

Book Logic

BookLogicTools

logic_sweep

Run docs/LOGIC.md's logic sweep on a node: causality chain, knowledge states, timeline, plant/payoff (two-way), orphan references, inserted-beat drift. This is a single LLM call per dimension over the whole node's prose — a coarse, automatable gate, NOT a replacement for the full /logic-sweep Claude Code skill on a large book (that skill splits the book across range-scoped subagents, verifies quotes, and does a separate fix + re-verify pass). Findings persist to the Findings table and auto-heal on re-run. Accepts node id (GUID) or slug.

  • nodeIdOrSlug (string, required) — Node id (GUID) or slug.

logic_sweep_until_dry

Run ONE round of a loop-until-dry logic-sweep convergence campaign (2026-08-14) — replaces 'run the sweep N times regardless of what it found' with an actual convergence criterion: stops after 2 consecutive rounds that found nothing new, persisted across sessions in NodeConvergenceStates. Call this again after each fix pass. Returns skipped=true (already converged, nothing changed, no LLM call made) or converged=true (2 consecutive clean rounds reached) or hit_safety_cap=true (8 rounds without converging — filed as its own finding; the book likely needs a structural rewrite, not another fix pass). Accepts node id (GUID) or slug.

  • nodeIdOrSlug (string, required) — Node id (GUID) or slug.
  • requiredDryRounds (int, optional) — Consecutive clean rounds required to call it converged. Default 2.
  • maxTotalRounds (int, optional) — Safety cap on total rounds before escalating 'not converging' as its own finding. Default 8.

write_synopsis

Generate a beat-by-beat narrative synopsis (act-grouped) of a node's written prose. Returned only — nothing is stored. For a real logic check (causality/knowledge-states/timeline/plant-payoff/orphan-refs/inserted-beat drift), call logic_sweep instead. Accepts node id (GUID) or slug.

  • nodeIdOrSlug (string, required) — Node id (GUID) or slug.

Canon

CanonTools

get_character

Load a character's full canon record by name: identity, psychology (core_fears, core_desires, coping_mechanisms, blind_spots, secret), behavioral (decision_rules, escalation_ladder, contradictions, habits, breaking_points, stress_responses), speech_patterns (vocabulary, cadence, verbal_tics, example_lines), augmentations, story_hooks. This is the primary source for voice when writing a POV chapter.

  • name (string, required) — Exact name of the character (e.g. 'Kyle Ellen Corbin' or 'Sasha Võ').

get_corponation

Load a CorpoNation by name: sector, hierarchy, holdings, public-facing brand, dirty laundry.

  • name (string, required) — Exact CorpoNation name.

get_faction

Load a faction by name: leadership, structure, territory, motives, alliances, rivalries.

  • name (string, required) — Exact faction name.

get_literary_rules

Load the world's literary rules: prohibitions, paragraph requirements, POV voice differentiation rules, register permissions, paragraph economy, interior_monologue source. Inject this near the top of any prose-generation prompt.

  • (no parameters)

get_place

Load a place / district by name. Returns description, sensory_details, parent territory, geography.

  • name (string, required) — Exact name of the place.

list_characters

List every character in canon. Returns name + role + status for each. Cheap — call this first when you need to know who exists.

  • (no parameters)

list_corponations

List every CorpoNation (corporate sovereign entity).

  • (no parameters)

list_factions

List every faction in canon: street gangs, syndicates, cells, advocacy groups, etc.

  • (no parameters)

list_places

List every place / district in canon. Use this to find a location for a scene.

  • (no parameters)

Canon Doc

CanonDocTools

generate_canon_md

Regenerate a world-canon .md file from its DB sections. Writes the assembled content to disk and updates the LastChecksum so codex doctor validates the file as current. set_canon_section already does this as part of its own call; use this to regenerate on demand.

  • documentType (string, required) — Document type — call list_canon_document_types for the current valid values.
  • universeSlug (string, optional) — Universe slug: glmz, scry/caul/fantasy, or universe GUID. Defaults to glmz.

get_canon_document

Get a full world-canon document assembled from its DB sections. Call list_canon_document_types for the current valid documentType values. universeSlug: glmz | scry/fantasy/caul (or a universe GUID). Returns the complete assembled markdown — same content that generate_canon_md would write to disk.

  • documentType (string, required) — Document type — call list_canon_document_types for the current valid values.
  • universeSlug (string, optional) — Universe slug: glmz, scry/caul/fantasy, or universe GUID. Defaults to glmz.

list_canon_document_types

List every registered canon DocumentType (e.g. WorldBible, CraftGuide) — the current valid values for the documentType parameter on every other tool in this file. Data-driven (CanonDocumentTypes table), so this grows as new document types are migrated; don't rely on a hardcoded list from memory.

  • (no parameters)

list_canon_sections

List all sections in a world-canon document with their keys, titles, sort order, and last-updated times. Use this to find the sectionKey you need before calling set_canon_section.

  • documentType (string, required) — Document type — call list_canon_document_types for the current valid values.
  • universeSlug (string, optional) — Universe slug: glmz, scry/caul/fantasy, or universe GUID. Defaults to glmz.

set_canon_section

Update or create a section in a world-canon document. This is the ONLY way to edit world canon — do NOT hand-edit the generated .md files under docs/ (BIBLE.md, WORLD.md, FRANCHISE.md, CRAFT.md, DELIGHT.md, docs/universes/*.md). The .md artifact and the MarkdownFiles sync (what DocContextService reads at generation time) are regenerated automatically as part of this call — no follow-up call needed. To find available sectionKeys, call list_canon_sections first.

  • documentType (string, required) — Document type — call list_canon_document_types for the current valid values.
  • sectionKey (string, required) — Stable section key — e.g. 'SS-LAW-1', 'SS-§3', 'preamble'. Use list_canon_sections to find existing keys.
  • content (string, required) — Full section content (markdown). Replaces the existing content for this key.
  • universeSlug (string, optional) — Universe slug: glmz, scry/caul/fantasy, or universe GUID. Defaults to glmz.
  • sectionTitle (string, optional) — Optional: human-readable section title (the ## heading text). Leave blank to keep the existing title.

Character Gear

CharacterGearTools

list_character_gear

List a character's gear entries (signature_gear / pharmaceuticals buckets) with their row ids. Row ids are what remove_character_gear takes. Pass a character name or GUID.

  • character (string, required) — Character name (exact) or GUID.
  • bucket (string, optional) — Optional bucket filter, e.g. 'signature_gear' or 'pharmaceuticals'.

remove_character_gear

Remove ONE gear entry from a character by its row id (get ids from list_character_gear). Surgical: the rest of the character record is never round-tripped, so nothing else can be lost. The table is system-versioned, so the row stays recoverable from CharacterBelongingsGear_History.

  • character (string, required) — Character name (exact) or GUID — the row's owner.
  • rowId (long, required) — Numeric gear row id from list_character_gear.

search_character_gear

Corpus-wide search for a gear name across every character — answers 'does anyone still carry X?'. Use before declaring an invented item purged: a per-character-only read is how invented canon survives.

  • text (string, required) — Substring to look for in gear names (case-insensitive).

Combat

CombatTools

draft_combat_scene

Generate an action sequence using the Prose combat writer. Respects participants' canon loadouts, current injuries/stress, and tracks ammo/grenade counts across beats. Tone shapes word choice and pacing — pick deliberately. Always pass preceding_context (last 1–3 paragraphs leading into the fight) so the prose transitions cleanly. sides_json must be a JSON array of side objects; see parameter description for shape. Returns the generated beats plus the full stitched text. Run validate_canon_text on the result before staging it into a chapter.

  • battlefieldLocation (string, required) — Place name or district where the fight occurs (used to pull terrain/cover).
  • sidesJson (string, required) — JSON array of combat sides. Each entry: { "label": str, "combatants": [canon character names], "unnamed_combatants": ["three drones", ...], "initial_position": str, "goal": str, "shared_loadout": str }. Label is required; everything else is optional. Usually 2 sides; up to 3 for a three-way.
  • environment (string, optional) — Environmental specifics shaping the action — 'rain on rusted steel', 'flickering neon'.
  • objective (string, optional) — What the scene is building toward — 'extract the courier', 'kill the target', 'buy time'.
  • openingBeat (string, optional) — Inciting action that opens the fight — 'Kyle draws Silence and steps through the strop', 'the door blows in'.
  • precedingContext (string, optional) — Last 1–3 paragraphs of narration before the fight, for tonal continuity.
  • numExchanges (int, optional) — Number of attack/react cycles to generate. 3–6 is normal.
  • tone (string, optional) — Tonal register: Brutal | Cinematic | Desperate | Clinical | Chaotic. Brutal = work; Cinematic = choreography; Desperate = losing-side POV; Clinical = mercenary detachment; Chaotic = broken perception.
  • initialResourcesJson (string, optional) — Optional JSON object: { "": { "ammo_by_weapon": { "Cacophony": 4, "XB-7 Silence": 0 }, "bio_battery_percent": 80, "meal_context": "full meal 2h ago" } }. When present, the writer enforces ammo/charge limits across beats. Leave empty to skip resource tracking for this scene.

Config

ConfigTools

add_context_doc

Pin a canon .md doc so it is always included in every beat prompt, regardless of LRU tier. Identify the doc by relative path fragment (e.g. 'ICFI', 'BIBLE', 'wound') or its GUID. The override lasts 24 h or until remove_context_doc / clear_context is called. Optionally scope to a single book with nodeSlug so only that book's beats include it.

  • doc (string, required) — Relative path fragment or GUID of the markdown doc to pin.
  • nodeSlug (string, optional) — Optional book slug to scope the pin (e.g. 'icfi'). Omit for session-global.

clear_context

Clear ALL active context overrides for this session (both pins and excludes). Pass nodeSlug to clear only overrides scoped to that book; omit for session-wide clear.

  • nodeSlug (string, optional) — Optional book slug to clear only overrides for that node. Omit for full session clear.

doc_context_prepare

Prepare the Doc Context Stack — the rotating cast of pertinent canon .md docs for a topic/scene. Returns one budgeted block plus the resident docs (tier + why each loaded). Pass nodeCode (e.g. 'BCODA') to include that book's register and book-scoped docs; pass text (scene/goal/conversation) to trigger topic docs by keyword and semantic embedding. This is how you load only the few docs that matter now instead of dumping hundreds.

  • text (string, required) — Scene/goal/conversation text to trigger topic docs against.
  • nodeCode (string, optional) — Optional node CODE (e.g. 'BCODA') to also load that book's register and book-scoped docs.
  • budget (int, optional) — Token budget for the assembled block. Default 2000.

doc_context_status

Inspect the current Doc Context Stack working set (the docs resident in the rotating cast) for a node context, without changing it. Returns each doc's tier, why it loaded, and its score.

  • nodeCode (string, optional) — Optional node CODE whose working set to inspect.

exclude_context_doc

Exclude a canon .md doc from the DocContextStack so it is never injected even if it would normally match. Identify the doc by relative path fragment or GUID. The override lasts 24 h or until remove_context_doc / clear_context is called.

  • doc (string, required) — Relative path fragment or GUID of the markdown doc to exclude.
  • nodeSlug (string, optional) — Optional book slug to scope the exclusion. Omit for session-global.

get_context_status

Show all active context overrides (pins and excludes) for this session. Includes the doc path, action, scope (global or node), and expiry time.

  • (no parameters)

get_cost_report

Show the running token cost tally for the current MCP server session. Returns call count, input/output token estimates, and USD cost broken down by model. Token counts are estimated from text length (chars / 4) since the Legion transport does not expose Anthropic usage objects. Pass reset=true to clear the ledger.

  • reset (bool, optional) — If true, clear the ledger after reporting. Default false.

get_markdown_file

Get the content of a tracked markdown file from the database. Pass asOf (ISO 8601 UTC) to retrieve a historical version from the temporal table. relativePath examples: 'CLAUDE.md', 'docs/BIBLE.md', 'feedback_sequential_node_writing.md'

  • relativePath (string, required) — Relative path key, e.g. 'CLAUDE.md' or 'docs/AMENDMENTS.md'.
  • asOf (string, optional) — Optional ISO 8601 UTC datetime to retrieve the version current at that moment.

list_markdown_files

List all markdown files tracked in the database (project rules, Codex docs, Claude Code memory). Returns category, relativePath, contentHash, and lastSyncedAt for each file.

  • (no parameters)

recall_markdown_files

Recall (call up) the select few tracked markdown files relevant to a keyword, straight from the database — instead of materializing hundreds of tiny .md files on disk. Substring-matches the keyword (case-insensitive) against relativePath, fileName, and category; set includeContent=true to also search inside file bodies. Returns each match's full content so the caller can read only what it needs. Examples: 'steppin', 'wound ledger', 'schism'.

  • keyword (string, required) — Keyword to match against path/name/category (and body when includeContent=true).
  • includeContent (bool, optional) — Also search inside file bodies, not just names. Default false.

remove_context_doc

Remove a specific pin or exclude override for a canon doc. Pass the same doc path/GUID and optional nodeSlug used when the override was created.

  • doc (string, required) — Relative path fragment or GUID of the markdown doc whose override to remove.
  • nodeSlug (string, optional) — Optional book slug the override was scoped to.

restore_markdown_file

Restore markdown files from the database back to disk. Pass relativePath to restore a single file; omit to restore all tracked files. Pass asOf (ISO 8601 UTC) to recover a historical version from the temporal table. Pass dryRun=true to preview without writing to disk.

  • relativePath (string, optional) — Relative path of the file to restore, e.g. 'CLAUDE.md'. Omit to restore all.
  • asOf (string, optional) — Optional ISO 8601 UTC datetime for point-in-time recovery.
  • dryRun (bool, optional) — If true, report what would be written without touching the filesystem.

sync_markdown_files

Sync all discovered markdown files from disk into the database. Only files whose content hash changed produce a new history row. Pass dryRun=true to preview without writing.

  • dryRun (bool, optional) — If true, report what would be synced without writing to the database.

Context

ContextTools

get_motifs

List the registered motifs for a book — recurring objects, phrases, gestures, sensory threads. Mention these in the chapter you're writing where natural; the review pipeline flags chapters that drop the whole inventory.

  • bookId (string, required) — Book id.

get_neighbors

Get a graph node's neighbors (relationships) up to N hops. Use this to walk from a known entity to entities related by canon — alliances, rivalries, family, mentor links, location ownership.

  • nodeId (string, required) — Node id (use search_semantic or list_characters to find the id).
  • hops (int, optional) — Hops to traverse. 1 = direct neighbors. Default 1.

plant_motif

Plant a new motif in a book's inventory. Idempotent by name (re-planting with a longer description merges). The user normally accepts these from the Motifs panel in the UI; this tool exposes the same write so chat-side authoring can register them too.

  • bookId (string, required) — Book id.
  • name (string, required) — Motif name, e.g. 'brick-wall notebook' or 'the door is unlocked'.
  • description (string, required) — Short description of what this motif means and where it lands.
  • kind (string, required) — MotifKind: Object, Phrase, Gesture, Sensory, Ritual.
  • introducedInChapterId (string, required) — Chapter id where this motif is being introduced.

propose_motifs

Scan a node's actual written prose for motif candidates — italicized phrases that recur, or capitalized named objects (not already characters/places) that repeat 3+ times. Returns proposals for review; nothing is written automatically. Pass a chapter-level node for one chapter's beats, or a book-level node to aggregate every chapter's beats. Plant any you want to keep via plant_motif.

  • nodeIdOrSlug (string, required) — Node id (GUID) or slug/code to scan.

search_semantic

Search the world graph by theme, not by name. TF-IDF cosine similarity across every entity description. Use this to surface entities that are thematically relevant to what you're about to write — e.g. searching 'corporate betrayal under-table contract' might return Sable's backstory, the Lotus Syndicate, the Ferrogate enforcement arm. Returns ranked id+name+type+score.

  • query (string, required) — Free-text query — describe the theme/scene/concept.
  • topK (int, optional) — Number of top hits to return. Default 8.

Contribution

ContributionTools

character_history

A character's history, read from the beats: every beat that tags them (by name or pronoun), in reading order, cited as book code, chapter and beat number, with the line saying what they did there. A beat with no line reads missing; a line written against other text reads stale. CLI parity: prose --character-history.

  • entity (string, required) — Character id or slug.
  • book (string, optional) — Optional book code to limit to (e.g. VATD).

get_beat_contributions

A beat's contribution lines and where they stand against its prose: characters tagged with no line, lines for characters it does not tag, stale lines, pronouns with no tag, and bare mentions of an ambiguous name sitting untagged (e.g. a 'Sable' the universe has five of, mentioned by name but never pinned with an explicit tag — tag one occurrence to resolve it). CLI parity: prose --beat contributions --id .

  • beatId (string, required) — Beat Guid.

set_beat_contributions

Replace one beat's contribution lines: one per character the beat tags (by name or pronoun), saying what they do in the beat and what it changes, with optional typed edges (e.g. relation was_killed_by, target the killer's guid). Refused unless the lines name EXACTLY the beat's tagged characters. Each line is stamped with the beat's text hash and goes stale on any edit. CLI parity: prose --beat contributions --id --file .

  • beatId (string, required) — Beat Guid.
  • linesJson (string, required) — JSON object: {"": "line"} or {"": {"text": "line", "edges": [{"relation": "was_killed_by", "target": ""}]}}.

story_edges

Relations the story establishes from or to an entity (e.g. who killed Bram Osei: relation was_killed_by), each with the beat that establishes it and its line. Answers a question about the story without reading the book. CLI parity: prose --story-edges.

  • entity (string, required) — Entity id or slug.
  • relation (string, optional) — Optional relation to filter by, e.g. was_killed_by.

Core Entity Crud

CoreEntityCrudTools

create_character

Create or update a character in canon. Pass empty id to create new; pass an existing id to update. List fields (tags, story_hooks, aliases) are comma-delimited strings. Complex fields (psychology_json, speech_patterns_json, physical_description_json) accept optional JSON — omit to keep defaults.

  • name (string, required) — Character's full name. Required.
  • role (string, optional) — Role or function in the world (e.g. 'street samurai', 'fixer', 'cleanup contractor').
  • description (string, optional) — Prose description of who this character is.
  • species (string, optional) — Species: human, ai, android, robot, cyborg, synthetic, hybrid, unknown. Omit to keep the current value (a new character defaults to human).
  • gender (string, optional) — Gender identity.
  • pronouns (string, optional) — Pronouns (e.g. 'he/him', 'she/her', 'they/them').
  • age (int, optional) — Age in years.
  • status (string, optional) — Status: alive, deceased, unknown, missing. Omit to keep the current value (a new character defaults to alive).
  • location (string, optional) — Refused if given: location is not stored on the character (see set_character_fields).
  • affiliation (string, optional) — Faction, corp, or freelancer network affiliation.
  • augmentations (string, optional) — Augmentation summary — cyberware, genemods, neural enhancements.
  • narrativeFunction (string, optional) — Narrative function: what role this character plays in stories.
  • tags (string, optional) — Comma-separated tags (e.g. 'freelancer,enforcer,Tier 3').
  • storyHooks (string, optional) — Comma-separated story hooks — unresolved threads this character carries.
  • aliases (string, optional) — Comma-separated aliases/handles this character is also known by (e.g. 'Rook,The Read'). ADDITIVE — merged into any aliases already on file, never replacing them; an alias equal to the character's own name is dropped (a self-alias is rejected by the write gate). Remove one with prose --delete-alias.
  • psychologyJson (string, optional) — Optional JSON for the psychology block: {core_fears, core_desires, coping_mechanisms, blind_spots, secret}.
  • speechPatternsJson (string, optional) — Optional JSON for speech_patterns: {vocabulary, cadence, verbal_tics, example_lines, subtext}.
  • physicalDescriptionJson (string, optional) — Optional JSON for physical_description: {heritage, height_cm, weight_kg, build, hair_color, eye_color, distinguishing_marks}.
  • id (string, optional) — Optional existing character id (32-char hex or full UUID) to update.
  • originNodeSlug (string, optional) — Optional book/series node slug this character belongs to (Entity.OriginNodeId). Pass this when seeding a book's cast — it lets a genuinely different character elsewhere reuse a common name (e.g. two unrelated books each with a 'Marcus') instead of being refused as a duplicate.
  • relationshipsJson (string, optional) — Optional JSON array of relationships: [{name (target, required), type, description, emotional_core, story_tension, status, since_chapter, until_chapter}]. REPLACES the whole list (the mapper rewrites the bridge table on every save) — pass '[]' to CLEAR all relationships, omit to leave unchanged. An entry with an empty 'name' is rejected.

create_corponation

Create or update a CorpoNation (corporate sovereign entity) in canon. Pass empty id to create new; pass an existing id to update.

  • name (string, required) — CorpoNation name. Required.
  • fullLegalName (string, optional) — Full legal corporate name.
  • sector (string, optional) — Industry sector.
  • sovereignTerritory (string, optional) — Territory the corp controls or dominates.
  • stockDesignation (string, optional) — Stock ticker or designation.
  • foundingStory (string, optional) — Founding story or origin.
  • securityForce (string, optional) — Security force name and description.
  • keyDetail (string, optional) — Key distinguishing detail about this corp.
  • fullText (string, optional) — Full prose text describing the CorpoNation.
  • tags (string, optional) — Comma-separated tags.
  • id (string, optional) — Optional existing CorpoNation id to update.

create_faction

Create or update a faction (street gang, syndicate, cell, advocacy group, etc.) in canon. Pass empty id to create new; pass an existing id to update. List fields are comma-delimited strings.

  • name (string, required) — Faction name. Required.
  • motto (string, optional) — Faction motto or slogan.
  • description (string, optional) — Prose description.
  • ideology (string, optional) — Core ideology.
  • territory (string, optional) — Territory the faction controls.
  • leadership (string, optional) — Leadership structure and named leaders.
  • narrativeFunction (string, optional) — Narrative function — what role this faction plays in stories.
  • methods (string, optional) — Comma-separated operational methods.
  • goals (string, optional) — Comma-separated goals.
  • storyHooks (string, optional) — Comma-separated story hooks.
  • tags (string, optional) — Comma-separated tags.
  • id (string, optional) — Optional existing faction id to update.

create_place

Create or update a place / district in canon. Pass empty id to create new; pass an existing id to update. List fields are comma-delimited strings.

  • name (string, required) — Place name. Required.
  • type (string, optional) — Type of place (e.g. 'district', 'building', 'landmark', 'corridor', 'station'). Omit to keep the current value (a new place defaults to 'place').
  • description (string, optional) — Prose description of the place.
  • demographics (string, optional) — Demographic makeup.
  • economy (string, optional) — Economic profile.
  • powerStructure (string, optional) — Who holds power here and how.
  • dangers (string, optional) — Comma-separated dangers present in this place.
  • storyHooks (string, optional) — Comma-separated story hooks.
  • tags (string, optional) — Comma-separated tags.
  • id (string, optional) — Optional existing place id to update.

set_entity_origin

Set which book/series node an existing entity belongs to (Entity.OriginNodeId), so a same-named entity in a different book is recognized as genuinely different rather than blocked as a duplicate. Pass empty originNodeSlug to clear back to universe-wide.

  • id (string, required) — Existing entity id (32-char hex or full UUID).
  • originNodeSlug (string, optional) — Book/series node slug to scope this entity to. Empty clears it (universe-wide/shared).

Craft Instrument

CraftInstrumentTools

compute_metrics

Computes and upserts per-beat prose quality metrics (sentence stats, type-token ratio, Flesch-Kincaid, dialogue proportion) for one book or every enabled beat corpus-wide. CPU-only — no LLM or API calls. Safe to re-run; results are upserted.

  • slug (string, optional) — Node slug — omit and set all=true to compute corpus-wide instead.
  • all (bool, optional) — Compute for every enabled beat corpus-wide instead of one book.

extract_beat_locations

Backfill the per-beat scene location (Beat.PlaceName + resolved Beat.PlaceEntityId) for one book — batched Haiku extraction in reading order, hash-gated on Beat.PlaceExtractedFromHash vs TextHash so unchanged beats cost nothing on re-run. New beats get this automatically via the consolidated post-write extraction; this tool exists for backfilling the existing corpus.

  • slug (string, required) — Node slug or code.
  • force (bool, optional) — Re-extract every beat, ignoring the hash gate.
  • limit (int, optional) — Optional cap on how many beats to process this call.
  • dryRun (bool, optional) — Preview without writing.

lint_prose

Deterministic prose linter (RepetitionLintService) — echo words, crutch phrases, pet words, unattributed dialogue runs, airless-narration runs, floating-heads beats. Zero LLM cost. Findings land in the Findings table (CraftChecklist, "LINT " prefix) and loop back into future generation. Run compute_metrics first so dialogue-proportion checks have data.

  • slug (string, required) — Node slug or code.
  • dryRun (bool, optional) — Preview findings without writing them.

Data Integrity

DataIntegrityTools

audit_data_consistency

Audit SSOT drift across the SQL schema — denormalized display fields (Alias caches on bridge tables) disagreeing with the FK they cache, orphaned subtype rows, dangling edges, slug collisions, and EntityStateEvents bi-temporal hygiene. Global, cross-universe check (not scoped to one universe). No LLM calls; findings are reported, never auto-corrected.

  • (no parameters)

check_graph_health

Check the active universe's world-graph health: orphaned nodes (zero edges), weakly-connected nodes (exactly one edge), and suspicious/malformed node names (sentence fragments, junk parses from free-text fields promoted verbatim into node identities). Rebuilds the graph from live SQL before analyzing, so results always reflect current data. Zero LLM calls; pure graph traversal + string heuristics.

  • (no parameters)

Edit Session

EditSessionTools

close_edit_session

Close the open edit session for a node (or by session ID). Returns beat count and duration.

  • nodeIdOrSlug (string, optional) — Node id (GUID) or slug. Use this OR session_id.
  • sessionId (string, optional) — Session GUID. Use this OR node_id_or_slug.

list_edit_sessions

List edit sessions for a node, most recent first.

  • nodeIdOrSlug (string, required) — Node id (GUID) or slug.
  • limit (int, optional) — Max number of sessions to return (default 20).

session_beats

List the beats that were edited in a session, with timestamps and version deltas.

  • sessionId (string, required) — Session GUID.

start_edit_session

Start a named edit session for a node. A session groups all prose edits until closed. Session types: prose-pass, gripes-cleanup, logic-sweep, custom.

  • nodeIdOrSlug (string, required) — Node id (GUID) or slug.
  • label (string, required) — Human-readable label, e.g. 'prose-pass-1' or 'gripes-cleanup-2026-07-13'.
  • sessionType (string, optional) — Session type: prose-pass | gripes-cleanup | logic-sweep | custom (default).

Encyclopedia

EncyclopediaTools

get_ammunition

Load an ammunition record.

  • name (string, required) — Ammunition name.

get_apparel

Load an apparel record.

  • name (string, required) — Apparel name.

get_archetype

Load an archetype record: typical behavior, knowledge, equipment, social position.

  • name (string, required) — Archetype name.

get_automaton

Load an automaton record. Behemoths and other industrial automata: not synthetic life — these are machines.

  • name (string, required) — Automaton name.

get_consumer_good

Load a consumer good record.

  • name (string, required) — Consumer good name.

get_cyberware

Load a cyberware record: install procedure, side effects, sensory experience, dependency profile.

  • name (string, required) — Cyberware ProductName or Name.

get_document

Load a worldbuilding document by its file_name (the filename-derived identifier). Returns the full prose body.

  • fileName (string, required) — Document file_name (e.g. 'corponations_overview' or as listed by list_documents).

get_equipment

Load an equipment record. Match is by ProductName when set, else Name (case-insensitive).

  • name (string, required) — Equipment ProductName or Name.

get_genemod

Load a gene modification record.

  • name (string, required) — Genemod name.

get_lab_specimen

Load a lab specimen record.

  • name (string, required) — Specimen name.

get_material

Load a material record: properties, applications, sensory qualities.

  • name (string, required) — Material name.

get_pharmaceutical

Load a pharmaceutical record: effects, dosage, side effects, dependency profile.

  • name (string, required) — Pharmaceutical name.

get_psionic

Load a psionic record.

  • name (string, required) — Psionic name.

get_subsidiary

Load a subsidiary record.

  • name (string, required) — Subsidiary name.

get_technology

Load a technology record. Match is by ProductName when set, else Name.

  • name (string, required) — Technology ProductName or Name.

get_transportation

Load a transportation record.

  • name (string, required) — Transportation name.

get_weapon

Load a weapon's full record by name: category, manufacturer, ammunition_type, lethality, mechanics, sensory detail, story_hooks, image prompts.

  • name (string, required) — Weapon name.

list_ammunition

List every ammunition variant in canon (calibers, specialty rounds, energy cells).

  • (no parameters)

list_apparel

List every apparel item in canon: clothing, armor, accessories.

  • (no parameters)

list_archetypes

List every archetype: occupational/social roles in the world (street samurai, fixer, runner, gleaner, etc).

  • (no parameters)

list_automata

List every automaton in canon: drones, security bots, Iowan Behemoths, agricultural machines.

  • (no parameters)

list_consumer_goods

List every consumer good: food, drinks, household items, branded products.

  • (no parameters)

list_cyberware

List every cyberware product: implants, neural augmentations, prosthetic limbs.

  • (no parameters)

list_documents

List every worldbuilding document by file name + title + category. Use get_document to load the body.

  • (no parameters)

list_equipment

List every equipment item in canon: gear, tools, devices, augmentation accessories.

  • (no parameters)

list_genemods

List every gene modification: somatic edits, lineage modifications, body-spec edits.

  • (no parameters)

list_lab_specimens

List every lab specimen — anomalous biological / synthetic / hybrid samples held in research facilities.

  • (no parameters)

list_materials

List every material: alloys, composites, fabrics, biomaterials. Use this when describing physical objects with specificity.

  • (no parameters)

list_pharmaceuticals

List every pharmaceutical: drugs, stims, pain modulators, neuro-pharma.

  • (no parameters)

list_psionics

List every psionic phenomenon recorded in canon.

  • (no parameters)

list_quotes

List every quote: in-world sayings, graffiti, advertising copy, attributed quotes. Useful for chapter epigraphs and ambient flavor.

  • tag (string, optional) — Optional filter: only quotes with a tag matching this value. Empty for all.

list_subsidiaries

List every subsidiary — child/holding companies of larger CorpoNations.

  • (no parameters)

list_technology

List every technology entry: software, protocols, networks, systems.

  • (no parameters)

list_transportation

List every transportation entry: vehicles, transit systems, The Pulse stations, individual transports.

  • (no parameters)

list_weapons

List every weapon in canon. Returns name + category + manufacturer. Use this to find a weapon for an action scene.

  • (no parameters)

Entity Context

EntityContextTools

apply_entity_rename

Apply a reviewed deterministic entity rename. Requires confirmed=true and an explicit active universe. Rewrites the text of the entity's own tags that read exactly the old name in the selected book's beats (untagged words and tags that read otherwise are left alone), relabels linked Story Ledger claims, and registers the old name as deprecated.

  • entityIdOrSlug (string, required) — Canonical entity GUID7 or slug.
  • nodeIdOrSlug (string, required) — Book GUID, slug, or NodeCode that scopes the beats.
  • newName (string, required) — New canonical full name.
  • confirmed (bool, optional) — Must be true after reviewing preview_entity_rename.
  • note (string, optional) — Optional audit note.

clear_entity_context

Clear the entity context stack for a node. Use when starting a new writing session for a node to reset the LRU working memory.

  • slug (string, required) — Node slug

find_entities

Find canonical entities by a case-insensitive partial name or character alias. Returns name, GUID7 id, slug, entity type, and alias match when applicable.

  • query (string, required) — Partial canonical name or character alias.
  • entityType (string, optional) — Optional entity type, for example character or place.
  • limit (int, optional) — Maximum results, 1-200; default 40.

get_entity_beat_mentions

Find every beat in the narrative where a specific entity is mentioned. Returns a list grouped by node with beat number, beat handle, and a short excerpt. Useful for auditing entity coverage, finding canon moments, and reverse-navigating from entity to story.

  • entityId (string, required) — Entity ID (GUID) or entity slug
  • limit (int, optional) — Maximum results to return (default 50)

get_entity_context

Inspect the entity working memory currently active for a node. Shows depth-0 (directly named), depth-1 (semantic neighbors), and depth-2 (neighbors of neighbors) entities with their canon descriptions. Call after generating beats to see what was in scope.

  • slug (string, required) — Node slug (e.g. 'ATTE', 'BCODA')

preview_entity_rename

Preview a deterministic entity rename. Finds the entity's own tags (entity guid) whose text is exactly its current name in one book's descendant beats, plus linked Story Ledger claims. Untagged words are never counted. Does not write.

  • entityIdOrSlug (string, required) — Canonical entity GUID7 or slug.
  • nodeIdOrSlug (string, required) — Book GUID, slug, or NodeCode that scopes the beats.
  • newName (string, required) — New canonical full name.

scan_entity_context

Run the entity context scanner on a text snippet and return the formatted context block that would be injected into the beat prompt. Useful for testing what entities the scanner picks up from a given passage or beat goal.

  • slug (string, required) — Node slug — context is keyed per node
  • text (string, required) — Text to scan (beat goal, prose excerpt, or entity name)

Entity Tag

EntityTagTools

add_entity_tags

Add tags to an entity, creating any tag vocabulary row that does not exist yet. Comma-separated. Tags already present are skipped.

  • entity (string, required) — Entity GUID or exact name.
  • tagNames (string, required) — Comma-separated tag names to add.

list_entity_tags

List an entity's tags. Pass an entity GUID or its exact name.

  • entity (string, required) — Entity GUID or exact name.

remove_entity_tags

REMOVE tags from an entity — the only path that can take a tag off, since create_character's tags parameter merges and never deletes. Comma-separated, case-insensitive. Removing a tag the entity does not carry is a no-op, not an error. Only the entity's link is removed; the shared tag vocabulary row is left intact for every other entity using it.

  • entity (string, required) — Entity GUID or exact name.
  • tagNames (string, required) — Comma-separated tag names to remove, e.g. 'vigl,battle-rig'.

Factory

FactoryTools

factory_capture

Station F4's worklist for a book: (a) capitalized names used in 2+ beats that no entity, alias or incidental ruling accounts for, and (b) uses of a book-tagged entity's name in a beat that does not tag it. Resolve (a) with create_* / an alias / record_ruling(kind: incidental), and (b) with tags (CLI: prose --factory capture --node X --retag | --pin | --pin-name "" --entity ).

  • nodeIdOrSlug (string, required) — Book id, slug or NodeCode.
  • limit (int, optional) — Most items per list (default 100).

factory_context

The writer's working memory for one unit (RFC 0015 §3.9), rebuilt on every call and never edited. Writes two files: {slug}.world.md — the book's law and the universe's world and craft canon, the same for every unit (read it once per session) — and {slug}.context.md, within the budget: the law, the records of every entity the unit tags as they stand now, the prose before the unit (the previous unit, or with priorUnits 'all' every preceding unit that fits, oldest dropped first, never cut at a chapter boundary) and the unit itself (its prose, or its planned beats). Returns both paths and a manifest of exactly what they hold and what was left out.

  • nodeIdOrSlug (string, required) — Book id, slug or NodeCode.
  • unit (int, required) — Unit ordinal, as factory_status prints it.
  • priorUnits (string, optional) — '1' (default) = the previous unit; 'all' = every preceding unit within the budget.
  • budgetChars (int, optional) — Character budget for the whole bundle (default 400000).

factory_journal

What happened in a window, reconstructed from the records themselves, in time order: every Hub call in the command ledger (with the session that made it), every read receipt, read note, entity verification, press, ruling, work order and session written, and — on SQL Server — every stored version of a beat or an entity from the temporal history. With a book: only what touched it. Nothing here had to be remembered to be written.

  • since (string, required) — Start of the window, ISO 8601 (UTC unless it carries an offset).
  • until (string, optional) — End of the window (default now).
  • nodeIdOrSlug (string, optional) — Optional book id, slug or NodeCode.
  • limit (int, optional) — Most events to return, newest kept (default 400). Counts by kind always cover the whole window.

factory_next

The single next action, computed: the first open blocking work order (during the factory's own build), otherwise the first failing station of the earliest unit of a book an author order has put on the line — with the exact calls that clear it. Ask this instead of deciding from memory.

  • nodeIdOrSlug (string, optional) — Optional book id, slug or NodeCode to ask about one book only.

factory_status

The Novel Factory's matrix for one book: every unit (chapter, as the exporters print it) × every station (F2 Planned, F3 Written, F4 Captured, F5 Read, F6 Clean, F1 Verified) plus the book stations (F7 Pressed, A Audio). Every verdict is computed from the prose, the world and the read receipts; a station not built yet says not-built.

  • nodeIdOrSlug (string, required) — Book id, slug or NodeCode.

factory_usage

The use-or-delete check: every factory tool, the day it shipped, its real calls in the command ledger (either door, MCP or CLI) and its verdict. A tool with no real call seven days after it shipped gets one engine order, "Use or delete: ", under the RFC's approved root; that order closes only by use, or is abandoned with the commit that deleted the tool. Runs at every session start.

  • fileOrders (bool, optional) — False = report only, file nothing.

session_end

End the current factory session (what /quicksave does). summaryJson = {done:[...], decisions:[{text, rulingId|orderId}], next:"..."}. Refused while any decision is not backed by a ruling or work order recorded this session.

  • summaryJson (string, required) — The summary JSON.
  • sessionId (string, optional) — The session id the start hook printed as THIS SESSION. May be omitted only when exactly one session is open; with several open the end is refused.

work_order_abandon

Abandon an open work order. A reason is required and recorded.

  • id (string, required) — Order id.
  • reason (string, required) — Why.

work_order_add

Open a work order. kind engine = code or docs in the repo (must declare paths; must descend from an author-approved root); kind author = a request about a book (pass nodeIdOrSlug to put the book on the factory line). checksJson is an array of typed checks validated Hub-side at close: commit, tests {names[]}, ledger {handler, method?, minCalls}, factory {book, station}, deploy, author.

  • kind (string, required) — engine | author
  • title (string, required) — Short title.
  • parentId (string, optional) — Parent order id (required unless this is a root the author approved).
  • rootApprovedBy (string, optional) — Roots only: 'author' — only when the author has approved this root.
  • nodeIdOrSlug (string, optional) — Book for an author order.
  • paths (string, optional) — Semicolon-separated repo-relative globs the order may touch (engine).
  • checksJson (string, optional) — JSON array of checks.
  • blocking (bool, optional) — True = this order is the factory's next action until it closes.
  • detail (string, optional) — Longer description.

work_order_close

Close a work order. The Hub validates every check itself (commit on HEAD within declared paths, TRX tests passed, real ledger use, station passes, Hub redeployed, author confirmation relayed). Refused — and the order stays open — if any check fails.

  • id (string, required) — Order id.
  • commitHash (string, optional) — Commit hash for a commit check.
  • trxPath (string, optional) — Path to a dotnet test TRX file for a tests check.
  • authorConfirmation (string, optional) — The author's words, for an author check (trust point: relayed).
  • note (string, optional) — Optional note.

work_order_get

One work order in full, whatever its status: title, kind, status, blocking, parent, node, paths, checks, the full detail text, and (once closed) the commit and evidence.

  • id (string, required) — Order id.

work_order_list

List work orders as a tree (depth-first, in the order the factory works them).

  • status (string, optional) — open (default) | closed | abandoned | all
  • kind (string, optional) — engine | author

Findings

FindingsTools

apply_finding

Apply a finding's suggested fix to the source file. Locates the snippet in the file, replaces it with the suggested rewrite, writes a backup to engine/data/archives/findings/, and marks the finding Applied. Returns the outcome: Applied, SnippetNotFound (LLM paraphrased — edit manually), NoSuggestedFix, NoSnippet, FileMissing, or Failed.

  • id (long, required) — Finding id from list_findings.

bulk_dismiss_findings

Dismiss every open finding matching a category and/or summary-prefix filter. At least one filter is required. Use to clear a backlog of many similar findings (e.g. an old per-beat sweep) instead of dismissing them one at a time.

  • category (string, optional) — FindingCategory to match, e.g. StructuralFailure. Omit to match any category.
  • summaryPrefix (string, optional) — Summary text prefix to match, e.g. "SWAIN ". Omit to match any summary.

findings_stats

Counts of findings per status (new / triaged / applied / dismissed).

  • (no parameters)

list_findings

List findings from the autonomous quality inbox. ContinuousQualityService auto-detects contradictions and clichés on every chapter save; results land here for triage. Sorted high-severity-first.

  • status (string, optional) — Filter by status: New, Triaged, Applied, Dismissed. Omit for all.
  • limit (int, optional) — Max number of findings to return. Default 100.

set_finding_status

Mark a finding triaged / applied / dismissed without writing to source files.

  • id (long, required) — Finding id.
  • status (string, required) — Target status: Triaged, Applied, or Dismissed.

Gear Entity Crud

GearEntityCrudTools

create_ammunition

Create or update an ammunition type (calibers, specialty rounds, energy cells) in canon. Pass empty id to create new; pass an existing id to update.

  • name (string, required) — Ammunition name. Required.
  • category (string, optional) — Category (e.g. 'pistol', 'rifle', 'shotgun', 'energy', 'specialty').
  • description (string, optional) — Prose description.
  • manufacturer (string, optional) — Manufacturer name.
  • tags (string, optional) — Comma-separated tags.
  • id (string, optional) — Optional existing ammunition id to update.

create_apparel

Create or update an apparel item (clothing, armor, accessories) in canon. Pass empty id to create new; pass an existing id to update.

  • name (string, required) — Apparel name. Required.
  • category (string, optional) — Category (e.g. 'outerwear', 'armor', 'footwear', 'accessories').
  • description (string, optional) — Prose description.
  • manufacturer (string, optional) — Manufacturer name.
  • tags (string, optional) — Comma-separated tags.
  • id (string, optional) — Optional existing apparel id to update.

create_cyberware

Create or update a cyberware implant in canon. Pass empty id to create new; pass an existing id to update. List fields are comma-delimited strings.

  • name (string, required) — Cyberware name. Required.
  • brandName (string, optional) — Brand name.
  • productName (string, optional) — Product model name.
  • category (string, optional) — Category (e.g. 'neural', 'limb', 'sensory', 'combat', 'subdermal').
  • bodyLocation (string, optional) — Body location of installation.
  • description (string, optional) — Prose description.
  • manufacturer (string, optional) — Manufacturer name.
  • tierAvailability (string, optional) — Tier availability.
  • legality (string, optional) — Legal status.
  • installationRequirements (string, optional) — Installation requirements.
  • specifications (string, optional) — Technical specifications.
  • streetPrice (string, optional) — Street price (unregulated market).
  • culturalContext (string, optional) — Cultural context in the GLMZ world.
  • sideEffects (string, optional) — Comma-separated side effects.
  • storyHooks (string, optional) — Comma-separated story hooks.
  • tags (string, optional) — Comma-separated tags.
  • id (string, optional) — Optional existing cyberware id to update.

create_equipment

Create or update a piece of equipment (gear, tools, devices, accessories) in canon. Pass empty id to create new; pass an existing id to update.

  • name (string, required) — Equipment name. Required.
  • brandName (string, optional) — Brand name.
  • productName (string, optional) — Product model name.
  • category (string, optional) — Category (e.g. 'surveillance', 'medical', 'demolitions', 'comms').
  • description (string, optional) — Prose description.
  • manufacturer (string, optional) — Manufacturer name.
  • tierAvailability (string, optional) — Tier availability.
  • tags (string, optional) — Comma-separated tags.
  • id (string, optional) — Optional existing equipment id to update.

create_material

Create or update a material in canon (alloys, composites, ceramics, fabrics, biomaterials). Pass empty id to create new; pass an existing id, or just an existing name, to update. Omitted scalar fields are LEFT UNCHANGED. List fields are comma-delimited and REPLACE the existing list; pass '[]' to clear one, or appendLists:true to merge instead of replacing.

  • name (string, required) — Material name. Required. An existing name updates that record.
  • category (string, optional) — Category (e.g. 'metal', 'ceramic', 'composite', 'advanced', 'nano_material', 'exotic', 'future').
  • description (string, optional) — Prose description of the material.
  • properties (string, optional) — Comma-separated physical properties (e.g. 'extreme_hardness,electrically_insulating').
  • applications (string, optional) — Comma-separated applications.
  • developers (string, optional) — Comma-separated developers.
  • tierAvailability (string, optional) — Tier availability (e.g. 'Tier 3-5', 'black market').
  • cost (string, optional) — Cost, e.g. 'Φ 200 per kg'.
  • tags (string, optional) — Comma-separated tags.
  • aliases (string, optional) — Comma-separated aliases.
  • brandName (string, optional) — Brand name.
  • productName (string, optional) — Product model name.
  • appendLists (bool, optional) — Merge list fields into the existing lists instead of replacing them. Default false.
  • id (string, optional) — Optional existing material id to update.

create_pharmaceutical

Create or update a pharmaceutical (drug, stim, pain modulator, neuro-pharma) in canon. Pass empty id to create new; pass an existing id to update.

  • name (string, required) — Pharmaceutical name. Required.
  • category (string, optional) — Category (e.g. 'stimulant', 'analgesic', 'neuro-modulator', 'combat stim').
  • description (string, optional) — Prose description and effects.
  • manufacturer (string, optional) — Manufacturer name.
  • tags (string, optional) — Comma-separated tags.
  • id (string, optional) — Optional existing pharmaceutical id to update.

create_technology

Create or update a technology entry (software, protocols, networks, systems) in canon. Pass empty id to create new; pass an existing id to update.

  • name (string, required) — Technology name. Required.
  • brandName (string, optional) — Brand name.
  • productName (string, optional) — Product model name.
  • subcategory (string, optional) — Subcategory (e.g. 'neural interface', 'network protocol', 'AI system').
  • description (string, optional) — Prose description.
  • developers (string, optional) — Comma-separated developer names (corporations, labs, individuals).
  • tierAvailability (string, optional) — Tier availability.
  • storyHooks (string, optional) — Comma-separated story hooks.
  • tags (string, optional) — Comma-separated tags.
  • id (string, optional) — Optional existing technology id to update.

create_weapon

Create or update a weapon in canon. Pass empty id to create new; pass an existing id to update. List fields are comma-delimited strings.

  • name (string, required) — Weapon name. Required.
  • category (string, optional) — Category (e.g. 'melee', 'pistol', 'shotgun', 'rifle', 'explosive', 'launcher').
  • description (string, optional) — Prose description of the weapon.
  • manufacturer (string, optional) — Manufacturer name.
  • tierAvailability (string, optional) — Tier availability (e.g. 'Tier 2+', 'black market', 'military only').
  • legality (string, optional) — Legal status.
  • specifications (string, optional) — Technical specifications.
  • tacticalUse (string, optional) — Tactical use and combat role.
  • culturalContext (string, optional) — Cultural context in the GLMZ world.
  • ammunitionTypes (string, optional) — Comma-separated ammunition types this weapon accepts.
  • storyHooks (string, optional) — Comma-separated story hooks.
  • tags (string, optional) — Comma-separated tags.
  • id (string, optional) — Optional existing weapon id to update.
  • knownUsers (string, optional) — Comma-separated known users (character names). Pass '[]' to CLEAR the list. Omit to leave unchanged.

Glossary

GlossaryTools

generate_book_glossary

Regenerate one book's Glossary (docs/nodes/{CODE}-Glossary.htm/.json/.txt) — the subset of its universe's Master Glossary whose terms actually appear in the book's live prose, detected fresh each call (not a stored join). A term the book stops using drops out on the next regenerate; a term added to the universe glossary after the book's last edit picks up automatically.

  • idOrSlug (string, required) — Node Guid id or slug/NodeCode of the book.

generate_glossary

Regenerate the current universe's Master Glossary — Glossary.htm/.json/.txt under docs/universes/{SLUG}/ — from the GlossaryTerms table. Run after upsert_glossary_term calls.

  • (no parameters)

list_glossary_terms

List every Master Glossary entry for the current universe, grouped by category.

  • (no parameters)

upsert_glossary_term

Add or update one Master Glossary entry for the current universe. term is the word/acronym as it appears in prose (e.g. 'GLMZ'); fullForm is its expansion if it's an acronym (e.g. 'Great Lakes Metropolitan Zone'), empty for plain vocabulary; definition is the reader-facing back-matter explanation (can carry more context than an in-voice gloss would); category groups entries in the rendered glossary (e.g. 'Enforcement', 'Currency', 'Tech'). Upserts by (universe, term) — case-sensitive exact match, calling again with the same term overwrites it.

  • term (string, required) — The term/acronym as it appears in prose.
  • fullForm (string, required) — Full expansion if an acronym; empty for plain vocabulary.
  • definition (string, required) — Reader-facing definition shown in the glossary.
  • category (string, optional) — Optional grouping category (e.g. 'Enforcement', 'Currency').

Graph Query

GraphQueryTools

beat_cast

Who and what is in a beat or a whole chapter: every tagged entity (with how many beats it appears in) and every live relationship edge among them. Read-only.

  • beatOrChapter (string, required) — A beat GUID, or a chapter GUID/slug/NodeCode.

co_occurrence

Every beat where two entities are both tagged (e.g. two characters sharing a scene, or a character and a motif). With a book, results are in that book's reading order. Read-only; derived from the entity tags the prose carries.

  • a (string, required) — First entity GUID or slug.
  • b (string, required) — Second entity GUID or slug.
  • book (string, optional) — Optional book GUID, slug or NodeCode to restrict to and order by.
  • limit (int, optional) — Maximum beats (default 100).

path_between

Shortest chain of live relationship edges connecting two entities (either direction), e.g. how a minor character is tied to the antagonist. Returns null path when none exists within maxHops. Read-only.

  • a (string, required) — Start entity GUID or slug.
  • b (string, required) — End entity GUID or slug.
  • maxHops (int, optional) — Maximum hops (default 4).

shared_neighbors

Entities that have a live relationship edge to BOTH given entities (common allies, shared employer, a place both frequent), with each side's relation type. Read-only.

  • a (string, required) — First entity GUID or slug.
  • b (string, required) — Second entity GUID or slug.

Hub

HubTools

graph_snapshot

Pull a graph snapshot from the Prose Hub for one universe - either the whole graph (scope='all') or just what's currently pertinent to ProseWriter right now (scope='active', the DocContextStack-driven default). Returns {nodes, edges}. Requires the Prose Hub running on http://127.0.0.1:5900.

  • universe (string, required) — Universe slug: glmz | scry | gspl.
  • scope (string, optional) — 'active' (default, what's pertinent right now) or 'all' (whole universe).
  • nodeCode (string, optional) — Node CODE (e.g. 'BCODA') to scope the 'active' set to, if applicable.

graph_stats

Get node/edge counts for one universe's resident graph from the Prose Hub. Cheap sanity check that the Hub is up and its graph is loaded. Requires the Prose Hub running on http://127.0.0.1:5900.

  • universe (string, required) — Universe slug: glmz | scry | gspl.

Create a relationship edge between two entities via the Prose Hub - the generic edge-creation capability missing from RelationshipDiscoveryService's auto-link path (which only covers Character/CorpoNation/District/Faction/Weaponry/Equipment/Technology, not e.g. Transportation). Writes to the SQL Edges table and updates the Hub's resident graph immediately. relationType is normalized (trim/lowercase/underscore) and resolved against the RelationTypeAliases registry before writing, so a registered wording (e.g. 'has' -> 'owns') collapses onto the same canonical RelationType automatically. The response's 'possibleDuplicate' field, when present, means a live edge already exists for this (source, target) pair under a DIFFERENT RelationType wording - check it before assuming this call created a new fact: if it's the same relationship reworded, prefer reusing the existing edge (or run prose --merge-edge --keep --dedupe --register-alias afterward) rather than leaving two edges for one relationship. validFromBeatId/validUntilBeatId (2026-09-02) bound this edge's truth to a reading-order span within ONE book (e.g. 'Lyra has the Oculus starting at this beat' / 'Kyle no longer has the motorcycle from this beat on') - replaces the dead legacy DateTime story-time mechanism. Omit both for an edge that's just always true. To close/adjust the window on an edge that ALREADY exists (the common case - most facts start out unbounded, then later the story establishes when they end), use prose --set-edge-validity instead of calling this again - a repeat call with different bounds does NOT change the existing edge (see the response's 'validityNote' when that happens). Requires the Prose Hub to be running on http://127.0.0.1:5900.

  • source (string, required) — Source entity GUID.
  • target (string, required) — Target entity GUID.
  • relationType (string, required) — Relation type, e.g. 'made_by', 'owns', 'based_in'. Normalized + alias-resolved server-side.
  • sentiment (string, optional) — Optional: 'positive' | 'negative' | 'neutral' (default).
  • description (string, optional) — Optional free-text description of the relationship.
  • universe (string, optional) — Optional universe slug to scope the write (glmz|scry|gspl). Uses the Hub's default if omitted.
  • validFromBeatId (string, optional) — Optional beat GUID: this edge is valid starting at this beat (inclusive), within that beat's own book. Omit for valid-from-the-start.
  • validUntilBeatId (string, optional) — Optional beat GUID: this edge is valid up to (exclusive of) this beat, within that beat's own book. Omit for valid-to-the-end.

Ledger

LedgerTools

command_log

Read back the Command Ledger — every CLI/MCP/cost-gated call Prose.Hub has executed, with args, exit code, duration, and error (if any). The mechanical half of the durable audit trail.

  • since (string, optional) — ISO-8601 datetime; only rows at/after this time.
  • handler (string, optional) — Filter to one handler class, e.g. 'BeatCli'.
  • take (int, optional) — Max rows to return (default 50).

decision_log

Read back the Decision Ledger written by log_decision — structured, permanent decision/reasoning records. Query this at the start of a fresh session instead of relying on chat history to reconstruct what was decided and why.

  • since (string, optional) — ISO-8601 datetime; only rows at/after this time.
  • sessionId (string, optional) — Filter to one session id.
  • take (int, optional) — Max rows to return (default 50).

log_decision

Write a Decision Ledger row — a durable, structured record of a higher-level decision or piece of reasoning (not a mechanical command call; those are logged automatically). Use this to make your own reasoning survive past this conversation's memory: a fresh session can query it back via decision_log.

  • summary (string, required) — One-line summary of the decision.
  • rationale (string, optional) — The 'why' behind it.
  • category (string, optional) — e.g. 'architecture', 'bugfix', 'canon-change'.
  • sessionId (string, optional) — This assistant's session id, if known.
  • actor (string, optional) — Who's recording this, e.g. 'claude-code'. Defaults to 'claude-code'.
  • relatedCommandIds (string, optional) — CommandLedgerEntry ids this decision grew out of, comma-separated.

search_logs

Search the Hub's durable log history (Serilog daily files on disk, not the live in-memory tail) by time range, minimum severity, and/or free text. This is the already-existing LoggingService.Search, the same mechanism the old Codex Logging page used, now exposed through the Hub.

  • since (string, optional) — ISO-8601 datetime; only entries at/after this time. Defaults to 1 day ago.
  • severity (string, optional) — Minimum severity: Verbose|Debug|Information|Warning|Error|Fatal.
  • text (string, optional) — Free-text filter over message/exception.
  • take (int, optional) — Max entries to return (default 200).

Lore Triple

LoreTripleTools

apply_continuity_claim

Apply a CANONICAL or CONFIRMED claim to its entity record file. Legion's panel picks which field should hold the value (string fields are set, array fields are appended to, otherwise the claim is appended to a continuity_facts[] array). The audit trail records which field was chosen.

  • claimUid (string, required) — Claim uid to apply.

get_continuity_claims

List continuity claims. Optional filters: entity (id or name), status (NEW | CONFIRMED | CONTRADICTED | CANONICAL | REJECTED | SUPERSEDED). Returns the claims with their predicates, objects, sources, and statuses.

  • entity (string, optional) — Optional: entity name to filter to one entity.
  • status (string, optional) — Optional: status filter.

list_continuity_contradictions

List every CONTRADICTED claim awaiting resolution. Each entry is a pair (A, B) where A and B share (entity, predicate) but have different object values. Use ResolveContinuityContradiction to pick a winner.

  • (no parameters)

resolve_continuity_contradiction

Resolve a contradiction. Winner = A | B (one claim wins → CANONICAL, the other → REJECTED) or custom (both rejected, a new writer-asserted CANONICAL claim takes their place; pass customObject).

  • aUid (string, required) — Claim A uid.
  • bUid (string, required) — Claim B uid (must belong to same entity as A).
  • winner (string, required) — Winner: A | B | custom.
  • customObject (string, optional) — Required when winner=custom: the agreed value.
  • note (string, optional) — Optional resolution note (kept in audit trail).

Node

NodeTools

clear_beat_gap_after

Clear an explicit gap-after-beat override. The audio engine falls back to the auto-computed silence from SceneType + terminator punctuation.

  • beatHandle (string, required) — Beat Guid OR 'node-guid.beat-guid' handle.

clone_book

Clone a node into a fully independent copy: new Node row + new Beat rows, same prose. Audio, scores, and review history are NOT copied — clone starts fresh (not archived, not at its end). Supports nodeCode for per-experiment isolation. Use this instead of DuplicateBook when you need nodeCode or per-experiment isolation. Returns new id, slug, beat count.

  • idOrSlug (string, required) — Source node Guid id or slug.
  • title (string, optional) — Title for the clone. Defaults to 'Source Title (Clone)'.
  • nodeCode (string, optional) — Optional short reference code for the clone (e.g. 'SM1'). Rejected if already in use.

create_book

Create a BookNode — a single book arc (book / novella / standalone). The book is created EMPTY: plan it by adding chapters (create_chapter) and planned beats (insert_beat with a title and description and no text), then write the beats. There is no outline or bible — a beat is written from its own description plus the canon entities it draws on. Optional parent makes it part of a series; optional previous marks it a sequel (sequel commandments apply). Returns the new id, slug, and url.

  • title (string, required) — Book title. Required.
  • description (string, optional) — Optional back-of-book description.
  • parentNodeIdOrSlug (string, optional) — Optional parent SeriesNode Guid id (or slug). Empty = standalone.
  • code (string, optional) — Optional short author-assigned reference code (e.g. 'ATTE'). Uppercased, unique lookup key.
  • previous (string, optional) — Optional prior book this one continues (slug or GUID) — sequel commandments apply.

create_chapter

Create a ChapterNode under a book. Chapters hold beats and never carry a reference code. parentNodeIdOrSlug is REQUIRED. Returns the new id, slug, and url.

  • title (string, required) — Chapter title. Required.
  • parentNodeIdOrSlug (string, required) — Parent BookNode Guid id or slug. Required.
  • description (string, optional) — Optional back-of-book description.

create_series

Create a SeriesNode — the top-level grouping (saga / anthology) that BookNodes hang under. Never holds beats. Returns the new id, slug, and URL.

  • title (string, required) — Series title. Required.
  • code (string, optional) — Optional short reference code (e.g. 'BCODA'). Upper-cased; rejected if already in use.
  • description (string, optional) — Optional one-line description (back-of-book text).

delete_beat

Remove a beat from a node. If the beat is not referenced by any other node, the beat row + audio file are deleted entirely.

  • nodeIdOrSlug (string, required) — Node Guid id or slug.
  • beatId (string, required) — Beat Guid id to delete.

duplicate_book

Deep-duplicate a node (and its sub-node tree) into a fresh, independent copy. Every beat is cloned into a new row — prose and narration metadata are preserved, but audio, review scores, and the stale flag are reset. Editing the copy never affects the original. Accepts a Guid id OR a slug. Returns the new node's id, slug, and writer URL.

  • idOrSlug (string, required) — Source node Guid id or slug.
  • newTitle (string, required) — Title for the new duplicate. Required.

export_audiobook

Render the whole node as one continuous narration (no per-beat voice drift) and write the MP3 to the configured export directory (defaults to Desktop). TTS engine: 'elevenlabs' (default, paid, highest fidelity), 'piper' (free/local, fastest), 'kokoro' (free/local, recommended), 'chatterbox' (free/local, most expressive). Returns the path of the written file, or null if the node has no beat text. This only generates a local MP3 — it does not publish anything to Audible/ACX.

  • nodeIdOrSlug (string, required) — Node id (GUID) or slug.
  • ttsEngine (string, optional) — TTS engine: elevenlabs (default) | piper | kokoro | chatterbox.
  • robust (bool, optional) — Set to true to retune this node's frozen voice snapshot to Robust stability (1.0) before recording.

export_node

Render a node to .docx + .epub + .pdf + .txt, plus description.txt (from Node.Description), and keywords.txt (from seeded NodeKeywords), all written to the configured export directory. Same full pipeline as the CLI's prose --export-node --slug <slug>. Refuses while any beat is unread as it stands (never read, text changed, moved, or a mentioned entity changed) and returns which ones — read them with read_beats(markRead:true) first. There is no override. Local files only; nothing is published to Amazon/KDP.

  • nodeIdOrSlug (string, required) — Node id (GUID) or slug.
  • author (string, optional) — Author name to embed in the document properties. Optional.

get_beat

Get a single beat with every authoring field — prose, kind, IsChapterStart, BeatTitle, gap-after, tone/pace/facet metadata, position within node, and the previous/next beat ids for relative insertion. Accepts a plain Beat Guid or the 'node-guid.beat-guid' dotted handle the writer UI shows on the LLM bottom sheet.

  • beatHandle (string, required) — Beat Guid OR the dotted 'node-guid.beat-guid' handle.

get_book

Get a single node with its beats in reading order. Accepts a Guid id OR a slug. Returns node metadata + ordered beats (id, text, stale, has_audio, title, description).

  • idOrSlug (string, required) — Node Guid id or slug.

get_score_history

Return the score history for a node as a time-series — every review run that produced a summary, with its mean score, SD, review count, and date. Use to track whether an edit moved the needle, or to compare pre/post-edit trajectories. Accepts node id (GUID) or slug.

  • idOrSlug (string, required) — Node id (GUID) or slug.
  • limit (int, optional) — Maximum history points to return (most recent first). Default 20.

insert_beat

Insert a new beat into a node. Pass an empty afterBeatId to insert at the top. Returns the new beat's id. To PLAN a beat (the only planning there is — no outline exists), leave text empty and give it a title and a description of what happens; the writer later writes the beat from that description plus the canon entities it names. A beat with neither title nor description cannot be written.

  • nodeIdOrSlug (string, required) — Node Guid id or slug.
  • afterBeatId (string, optional) — Beat Guid id to insert after, or empty for top-of-node.
  • text (string, optional) — Initial prose text for the new beat. Leave empty for a planned beat.
  • title (string, optional) — Optional beat title (for a planned beat: a short name for what it is).
  • description (string, optional) — Optional description — what happens in this beat. This is what the writer writes the beat FROM.

join_beat

Merge one beat into the previous one in the node. Audio on the survivor is invalidated.

  • nodeIdOrSlug (string, required) — Node Guid id or slug.
  • beatId (string, required) — Beat Guid id to merge upward.

list_books

List nodes. Use kind='book' to list all root narratives; kind='chapter' for all sub-nodes (contain beats). Returns a flat list of id, slug, title, kind, is_archived, timeline, beat-count, stale-count.

  • kind (string, optional) — Optional Kind filter — 'book' (root nodes) or 'chapter' (sub-nodes with beats). Case-insensitive equality match.
  • limit (int, optional) — Maximum rows to return. Default 100.

list_scores

List nodes with their latest review score, word count, and estimated page count (250 words/page). Optionally filter by kind ('book', 'chapter', 'episode', etc.). Returns code, title, kind, is_archived, timeline, score (null if unreviewed), words, pages, scored_on. Sorted by score descending (unscored nodes last). Use this for a quick quality dashboard without running new reviews.

  • kind (string, optional) — Optional kind filter (case-insensitive). E.g. 'book', 'chapter', 'novella'. Empty = all kinds.
  • includeArchived (bool, optional) — Include archived nodes. Default false.
  • limit (int, optional) — Maximum rows to return. Default 200.

move_node_after_sibling

Reposition an existing node (typically a chapter) to sit immediately after a named sibling under the same parent — a fractional SortKey midpoint is computed automatically, so callers never need to know or guess raw SortKey values. Use this to insert a newly created chapter into the middle of a book's reading order instead of it landing at the end (create_chapter always appends). Accepts GUID id or slug for both nodeIdOrSlug and afterSiblingIdOrSlug.

  • nodeIdOrSlug (string, required) — Node Guid id or slug to reposition.
  • afterSiblingIdOrSlug (string, required) — Guid id or slug of the sibling this node should immediately follow. Must share the same parent as nodeIdOrSlug's new position (the node is moved under that same parent).

narrate_book

Kick off TTS narration for every un-narrated beat in this node (and its child nodes recursively). Returns immediately — narration runs in the background; poll get_node to observe progress. Returns an error response (without spawning anything) if TTS is not configured.

  • nodeIdOrSlug (string, required) — Node Guid id or slug.

prepare_audible

Build an Audible AI-narration hand-off package for a node. Produces three files in {publishDir}/{Title}/Audible/: (1) a narration-clean manuscript (.audible.txt) with markdown artifacts stripped and Φ expanded to 'QUANTA'; (2) a pronunciation guide (.pronunciation.md) listing entity names with plain-English respellings; (3) AUDIBLE_README.md with submission instructions. No API is called on Audible's side — the author uploads the .audible.txt via ACX/Audible publisher portal. Returns paths + word/term counts.

  • nodeIdOrSlug (string, required) — Node id (GUID) or slug.
  • withPhonetics (bool, optional) — Run the optional LLM phonetics pass to fill in 'Say it as' respellings. Default true. Set false to skip and leave the column blank for manual completion.

Print all beats of a node as continuous prose — each beat's Text joined by a blank line. No headers, no beat numbers, no metadata. Accepts node id (GUID) or slug. Use this to read the full prose of a node in one call.

  • idOrSlug (string, required) — Node Guid id or slug.

read_beats

Read a book's beats directly, in reading order, with ids/titles/text - no --publish-md export round-trip required. The 'Writer' capability: browse prose without exporting first. Unlike print_book (plain joined text only), this returns structured per-beat rows and supports a from/to range, or direct lookup of specific beats by their global Beat.Number (the id logic-sweep findings quote, e.g. 'Beat #14664') via numbersCsv, which takes precedence over from/to when both are given. Pass groupByChapter:true for the chapter-altitude view: the same beats nested under their chapter nodes, so a large book can be read chapter by chapter instead of as one flat list.

  • idOrSlug (string, required) — Node Guid id or slug.
  • from (int, optional) — 1-based position to start at (default 1).
  • to (int, optional) — 1-based position to end at, inclusive (default: last beat).
  • numbersCsv (string, optional) — Optional comma-separated Beat.Number values to look up directly, ignoring from/to.
  • groupByChapter (bool, optional) — When true, nest the returned beats under their chapter nodes instead of returning one flat list. Positions are identical either way.
  • markRead (bool, optional) — When true, record a read receipt for exactly the beats returned, at the hash of the text returned — only pass it when the text is actually being read. Export refuses while any beat is unread (see read_status). Requires readBy.
  • readBy (string, optional) — Who is reading (required with markRead).

rebeat_book

Re-segment a node's beats to the codified beat doctrine via LLM re-segmentation. Dry-run by default (safe to call freely). Set apply=true to export a Markdown backup then replace the beats — only committed if the word-retention guard passes (prevents silent content loss). Returns old/new beat counts, retention %, guard result, and a note if it was blocked.

  • nodeIdOrSlug (string, required) — Node id (GUID) or slug.
  • apply (bool, optional) — Set to true to commit the new segmentation. Default false = dry run.

reflow_book

Copy-edit a node's prose in-place: adds missing '?' on questions, swaps 'says/said' → 'asks/asked' on question dialogue lines, and normalises paragraph/dialogue spacing. Dry-run by default — set apply=true to commit. Beats the model modified beyond those specific edits are rejected and left untouched. Returns changed/unchanged/rejected/errors counts plus per-beat diff previews.

  • nodeIdOrSlug (string, required) — Node id (GUID) or slug.
  • apply (bool, optional) — Set to true to write the edits to the DB. Default false = dry run.

rename_node

Rename a node (series, book, chapter or scene): set its Title and, optionally, its Slug. A new slug goes through the same path as prose --set-node-slug --apply: it must be slug-shaped and free in the universe, it is pinned, and every slug-carrying reference (beat audio paths, publication paths, on-disk directories) moves with it. Both are validated before anything is written; a refusal changes nothing. Does not touch beats. CLI twin: prose --rename-node --node <id|slug> --title "…" [--slug …].

  • nodeIdOrSlug (string, required) — Node Guid id, slug or NodeCode.
  • title (string, required) — The new title. Required.
  • newSlug (string, optional) — Optional new slug (lowercase words joined by hyphens). Omit to keep the current slug.

set_beat_gap_after

Set the silence (in ms) the audio engine inserts AFTER this beat, before the next. 0 = no silence (explicit override). Use ClearBeatGapAfter to revert to the auto-computed default from SceneType + terminator punctuation.

  • beatHandle (string, required) — Beat Guid OR 'node-guid.beat-guid' handle.
  • durationMs (int, required) — Silence in milliseconds, 0..6000.

set_previous_node

Set (or clear) a book node's sequel link (Node.PreviousNodeId). Needed before deleting or reparenting a book that another book's PreviousNodeId points at — the FK is a DB-level Restrict, so delete_node's force flag alone cannot bypass it; repoint or clear the referencing node's link first. Pass clear=true to detach instead of setting a new previous node.

  • nodeIdOrSlug (string, required) — Node Guid id or slug whose PreviousNodeId to set.
  • previousNodeIdOrSlug (string, optional) — Guid id or slug of the book this node continues. Ignored when clear=true.
  • clear (bool, optional) — Set true to clear PreviousNodeId (detach) instead of setting one.

splice_beats

Apply a hand-written docket of exact-text replacements across a book — the multi-beat hand edit. Each edit names a beat by its global Beat.Number; 'old' is matched against the beat text with entity tags stripped (inline italic markers kept) and must occur exactly 'count' times (default 1), counted after the earlier edits to the same beat. ANY count mismatch aborts the whole docket with nothing written. Dry run unless apply=true. Entity tags an edit does not touch are kept; touched ones are re-derived on save. Each beat is written once as an AuthorEdit, refused if another session changed it since it was read, then re-read and checked against the promised text. CLI parity: prose --splice-beats.

  • nodeIdOrSlug (string, required) — Book (or any node) slug, NodeCode, or Guid whose beats the docket targets.
  • docketJson (string, required) — JSON array: [{"beat": 20420, "old": "exact text", "new": "replacement", "count": 1}]. Empty 'new' deletes.
  • apply (bool, optional) — false (default) = plan and guard only; true = write.
  • analyze (bool, optional) — true = run the per-save LLM analysis tails on every beat. Default false: a docket wants one analysis pass at the end.

split_beat

Split one beat into two at the nearest sentence boundary near its midpoint. Both halves lose their audio.

  • nodeIdOrSlug (string, required) — Node Guid id or slug.
  • beatId (string, required) — Beat Guid id to split.

update_beat_metadata

Update a beat's metadata: Title, Description, EmotionalTone, PaceHint, StructureRole, Act, SceneType, IsChapterStart, Kind. ONLY the fields you pass change — omit a field to leave that column exactly as it is, pass an empty string to clear it. Does NOT touch prose or audio. Use to mark a beat as a chapter start, change its kind to quote/dedication/book-title, or set the tone the next re-record uses.

  • beatHandle (string, required) — Beat Guid OR 'node-guid.beat-guid' handle.
  • title (string, optional) — Short label. When IsChapterStart=true this is the chapter heading; when Kind=quote this is the attribution. Omit to leave unchanged; "" to clear.
  • description (string, optional) — One-line description fed to LLM regenerations. Omit to leave unchanged; "" to clear.
  • subtext (string, optional) — What is happening beneath the prose — foreshadowing, unspoken motivations, dramatic irony. Visible to the prose writer LLM but never printed. Omit to leave unchanged; "" to clear.
  • emotionalTone (string, optional) — Emotional tone, e.g. 'quiet' / 'tense' / 'wry'. Omit to leave unchanged; "" to clear.
  • paceHint (string, optional) — Pace hint, e.g. 'flowing' / 'clipped' / 'staccato' / 'languorous'. Omit to leave unchanged; "" to clear.
  • structureRole (string, optional) — Structure role, e.g. 'inciting-incident' / 'rising-action' / 'climax'. Omit to leave unchanged; "" to clear.
  • act (int, optional) — Plot-act number 0–5. 0 = unassigned. Omit to leave unchanged.
  • sceneType (string, optional) — Scene type: scene | summary | transition | interstitial. Omit to leave unchanged; "" resets to 'scene'.
  • isChapterStart (bool, optional) — True = this beat begins a new chapter / section. The writer renders a divider above it with Title as the heading. OMIT to leave unchanged — passing false demotes a chapter opener, which until 2026-08-24 happened on every call that didn't set it.
  • kind (string, optional) — Beat kind: prose | book-title | dedication | quote. Free-form so new kinds add no schema cost. Omit to leave unchanged; "" resets to 'prose'.

update_beat_text

Update one beat's prose. Recomputes the hash, marks the beat stale, and invalidates its audio. Beat.Text accepts inline markdown (bold / italic / underline / strike) and ElevenLabs-style tone tags ([WHISPERING] [GASP] [LAUGHS] [PAUSES] etc.) that render as emoji in the read view. Accepts a Beat Guid OR the 'node-guid.beat-guid' handle.

  • beatHandle (string, required) — Beat Guid OR 'node-guid.beat-guid' handle.
  • text (string, required) — New prose. Replaces the entire beat text. Markdown markers + tone-tag brackets are preserved verbatim in storage.

update_book

Update a node's metadata fields. Pass only the fields you want to change — omit the rest to leave them unchanged. Editable fields: title, description, kind, status, seed, code (NodeCode), voice_id, kdp_page_count, layout. Status valid values: draft | ready | canon | archived. Code is uppercased and must be unique across non-null values — pass empty string to clear it. Does NOT touch beats or audio. Does NOT rename slugs — use the CLI prose --set-node-slug --slug <current> --to <new> --apply (SlugRepairService), which pins the slug and moves every slug-carrying reference (beat audio paths, publication paths, on-disk directories) with it.

  • idOrSlug (string, required) — Node id (GUID) or slug.
  • title (string, optional) — New title. Omit to leave unchanged.
  • subtitle (string, optional) — Subtitle (e.g. 'A GLMZ Novella'). Omit to leave unchanged; pass empty string to clear.
  • description (string, optional) — Back-of-book description. Omit to leave unchanged; pass empty string to clear.
  • kind (string, optional) — Kind label: book | chapter | episode | novella | novel | node | scene | saga | anthology. Omit to leave unchanged.
  • isArchived (bool, optional) — Archive (true) or restore (false) this node — excludes it from the progress dashboard, edit-distribution and the default obligation-reconciliation scan. Omit to leave unchanged.
  • isAtEnd (bool, optional) — Has the text reached its own end (vs. still being written)? Distinct from structural completeness. Omit to leave unchanged.
  • timeline (Decimal, optional) — Where this book sits on its universe's chronology: integer part = series/era, fractional part orders books within it (1.0 < 1.1 < 2.0). Equal values mean the prose doesn't establish an order between them. Omit to leave unchanged.
  • seed (string, optional) — Generation seed (one-line premise). Omit to leave unchanged; pass empty string to clear.
  • code (string, optional) — Short author reference code (e.g. 'ATTE'). Uppercased; pass empty string to clear. Omit to leave unchanged.
  • voiceId (string, optional) — ElevenLabs or local TTS voice id. Omit to leave unchanged; pass empty string to clear.
  • kdpPageCount (int, optional) — KDP print-page count from Word (File → Info → Properties → Pages). Used to calculate the correct inside margin on the next export. Pass 0 to clear.
  • layout (string, optional) — Export layout: prose | lyrics | screenplay. lyrics prints blank-line-separated stanzas with bracketed section labels ([Verse 1], [Chorus]) dropped; screenplay parses Fountain-style elements (INT./EXT. headings, upper-case cues over dialogue, (parentheticals), TO: transitions) onto US Letter Courier 12. Beats are never changed. Omit to leave unchanged.

Noun Consistency

NounConsistencyTools

add_deprecated_name

Register a deprecated noun rule. Any beat that contains 'deprecatedName' (whole-word, case-insensitive) in the target universe will be flagged by validate_nouns. Use when a named thing is renamed or retired. universeSlug defaults to 'glmz' when omitted.

  • deprecatedName (string, required) — The old/wrong name to flag in prose (e.g. 'VacCell', 'Rider').
  • canonicalName (string, required) — The correct name to use instead (e.g. 'Nit', 'Exo').
  • notes (string, optional) — Optional explanation (e.g. 'Renamed in SS-A38 when Rider job was retired').
  • universeSlug (string, optional) — Universe slug ('glmz' or 'fantasy'). Defaults to 'glmz'.

list_deprecated_names

List all registered deprecated noun rules. Filter by universeSlug ('glmz' or 'fantasy') or omit for all universes.

  • universeSlug (string, optional) — Optional universe slug to filter ('glmz' or 'fantasy'). Omit for all.

Obligation

ObligationTools

accept_obligation

Accept an extracted obligation as-is: locks it so no automated rescan can withdraw, re-anchor or re-state it.

  • obligationId (string, required) — Obligation id (GUID).

close_obligation

Pay an obligation: name the beat that pays it and quote the sentence verbatim. Refused with quote_not_found if the quote is not in that beat's text — closure is verified against the artifact, never asserted.

  • obligationId (string, required) — Obligation id (GUID).
  • beatId (string, required) — Closing beat GUID.
  • quote (string, required) — Verbatim quote from the closing beat (≥12 chars).
  • note (string, optional) — Optional note.

defer_obligation

Defer an obligation to a later due point — 'I'll pay this in Ch12' is defer to chapter:12; a deliberate slow burn is defer to book-end. A note is required. Deferred rows are never flagged before their new due point.

  • obligationId (string, required) — Obligation id (GUID).
  • note (string, required) — Why, in your words.
  • due (string, optional) — chapter:N | beats:N | book-end

drop_obligation

Intentionally abandon an obligation. reason: background-texture | pov-limited | genre-convention | intentional-mystery | series-deferred | false-extraction | duplicate-of:. A note in your words is required. 'false-extraction' and 'background-texture' feed the extractor's stop-list for this universe.

  • obligationId (string, required) — Obligation id (GUID).
  • reason (string, required) — Dropped reason (see description).
  • note (string, required) — Why, in your words.

get_obligation

One obligation with its full journal (every open/advance/close/drop/defer/withdraw event, who did it, and the quote that justified it).

  • obligationId (string, required) — Obligation id (GUID).

Point an obligation at the entity it is about (e.g. after naming an '(unnamed) girl behind the curtain' stub, or merging it into a canon character).

  • obligationId (string, required) — Obligation id (GUID).
  • entityId (string, required) — Entity id (GUID).

list_obligations

List the narrative obligations of a book — every promise the prose has made that the ledger tracks (RFC 0013). Each row: id, kind (promise|plant|question|wound|foreshadow|introduced-referent|unexplained-presence), description, state (Open|Advanced|Closed|Dropped|Deferred), provenance (authored|observed|inferred), origin chapter/beat and the verbatim quote that made the promise, due point, overdue flag, and whether the author has locked it. Filters: state, kind, overdueOnly, chapter (origin chapter ordinal). Accepts a book or chapter node id/slug/code — always reports the whole book.

  • nodeIdOrSlug (string, required) — Node id (GUID), slug, or NodeCode of the book (a chapter resolves to its book).
  • state (string, optional) — Optional state filter: Open, Advanced, Closed, Dropped, Deferred.
  • kind (string, optional) — Optional kind filter.
  • overdueOnly (bool, optional) — Only rows past their due point with no author decision.
  • chapter (int, optional) — Only rows whose origin is in this chapter ordinal (1-based).

obligation_trial_balance

The chapter trial balance (RFC 0013): opened − closed − dropped − deferred = carried forward, plus the rows the hard gate reads — obligations past their due point at the end of this chapter with no author decision. Also lists what this chapter opened and closed, closures whose quote is no longer on the page, and rows whose origin beat was deleted. balanced=false means the chapter cannot close until each overdue row is closed, dropped or deferred. could_not_look=true means the ledger is empty for this book — an empty ledger FAILS, it does not pass; run a rescan first. Omit chapter for the whole book.

  • nodeIdOrSlug (string, required) — Node id (GUID), slug, or NodeCode of the book.
  • chapter (int, optional) — Chapter ordinal (1-based). Omit for the whole book.

open_obligation

Declare an obligation yourself (provenance authored, locked): a promise you intend the book to keep. Optionally anchor it to a beat with the verbatim quote that makes the promise — refused if the quote is not in that beat's text. due: 'chapter:7', 'beats:12', or 'book-end' (default).

  • nodeIdOrSlug (string, required) — Book node id/slug/code.
  • kind (string, required) — promise | plant | question | wound | foreshadow | introduced-referent | unexplained-presence
  • description (string, required) — What is owed, one line.
  • beatId (string, optional) — Origin beat GUID (optional).
  • quote (string, optional) — Verbatim quote from that beat (optional; ≥12 chars).
  • trigger (string, optional) — Narrative condition under which paying this becomes natural (optional).
  • due (string, optional) — chapter:N | beats:N | book-end

reopen_obligation

Reopen a closed, dropped or deferred obligation (author decision; locks the row).

  • obligationId (string, required) — Obligation id (GUID).
  • note (string, optional) — Optional note.

set_obligation_due

Change an obligation's due point without changing its state. due: chapter:N | beats:N | book-end.

  • obligationId (string, required) — Obligation id (GUID).
  • due (string, required) — chapter:N | beats:N | book-end

One Shot Generation

OneShotGenerationTools

generate_scene

Write a scene or line of dialog without a pre-existing Book/Chapter/Beat row. Ephemeral by default: pacing, dialogue voice profiles, canon-fact grounding, consequence/gear constraints, ambient sensory grounding, and entity pre-check warnings all still apply. Pass node to borrow an existing book's canon/continuity ('attached mode') without writing a Beat row to it.

  • beatGoal (string, required) — What should happen in this scene/line — the beat goal.
  • characters (string, optional) — Comma-separated character names on screen (activates dialogue voice profiles and continuity/consequence grounding).
  • location (string, optional) — Raw location hint for ambient sensory grounding, e.g. 'The Spine, Zone 3'.
  • subtext (string, optional) — What's happening beneath the surface — foreshadowing, unspoken motivation, dramatic irony.
  • node (string, optional) — Optional slug/NodeCode/GUID of an existing Book or Chapter to borrow canon and continuity from. Omit for pure ephemeral.
  • universe (string, optional) — Optional universe slug override; defaults to the session's current universe.
  • beatIndex (int, optional) — Zero-based position in an imagined beat sequence, for pacing guidance. 0 if unknown.
  • totalBeats (int, optional) — Total beats in that imagined sequence, for pacing guidance. 0 disables positional pacing.

Operator Key

OperatorKeyTools

add_operator_byo_key

Append one key to the end of an operator provider's BYO key pool (tried last, after every key already configured). No-op if the exact key is already present.

  • provider (string, required) — 'claude' or 'openai'.
  • key (string, required) — The raw API key to add.

clear_operator_byo_keys

Clear the ENTIRE BYO key pool for one operator provider (claude or openai) — falls back to that adapter's own default credential chain (never the shared pay-per-token Vault key, for Claude).

  • provider (string, required) — 'claude' or 'openai'.

list_operator_byo_keys

List the BYO API key pool configured for the KDP operator's tool-calling loop (claude or openai) — the keys tried BEFORE that provider's own default credential chain, in priority order, failing over to the next on an auth/rate-limit/server error. Keys are returned masked (last 4 chars only). Pass no provider to list both.

  • provider (string, optional) — 'claude' or 'openai'. Omit to list both providers.

remove_operator_byo_key

Remove one key (by exact value) from an operator provider's BYO key pool. Returns removed=false if that key wasn't configured.

  • provider (string, required) — 'claude' or 'openai'.
  • key (string, required) — The exact raw API key to remove.

set_operator_byo_keys

Replace the WHOLE BYO API key pool for one operator provider (claude or openai) with the given keys, tried in that order and failing over on error. Use add_operator_byo_key / remove_operator_byo_key instead to edit the pool incrementally without retyping every key.

  • provider (string, required) — 'claude' or 'openai'.
  • keys (String[], required) — The full pool, in priority order. An empty list clears the provider (same as clear_operator_byo_keys).

Planning

PlanningTools

extract_entities

Extract named entities and relationships from arbitrary prose. Useful AFTER drafting a chapter — surfaces any new characters, places, factions, weapons, technology mentioned that aren't in canon yet (candidates for promotion). Returns the structured ExtractionResult with entities (with type + description + properties) and relationships (source → target). Calls the LLM internally — slow on long text, fast on a single beat.

  • text (string, required) — Prose text to scan.

get_neighbors_by_relation

List a node's edges filtered by relation type. Subset of get_neighbors that returns only relationships matching a specific relation_type — e.g. 'rival', 'allied', 'mentor', 'family', 'controls_territory', 'frequents'. Useful for targeted lookups: 'who are Kyle's known rivals'.

  • nodeId (string, required) — Source node id (use search_semantic / list_characters / etc. to find).
  • relationType (string, required) — Relation type to filter on. Case-insensitive substring match (e.g. 'rival' matches 'rivalry').

Plant Payoff

PlantPayoffTools

get_plant_payoffs

List all registered plant/payoff pairs for a node. A plant is a narrative detail seeded early (a behavioral tell, an object, a gloss) that resonates or resolves later — rewarding re-readers without requiring first-timers to catch it. Returns all pairs with their status (planned = not yet written, seeded = plant beat written but no payoff yet, paid-off = both beats written), is_transparent flag (must be true for the payoff to work for cold readers), and transparency_note (what the re-reader gains). Accepts node id (GUID) or slug.

  • nodeIdOrSlug (string, required) — Node id (GUID) or slug.

Link the payoff beat to a registered plant/payoff pair. Call after writing the beat where the plant pays off. plant_payoff_id = GUID from register_plant_payoff; beat_id = GUID of the payoff beat.

  • plantPayoffId (string, required) — PlantPayoff id (GUID) from register_plant_payoff.
  • beatId (string, required) — Beat GUID containing the payoff.

Link the plant beat to a registered plant/payoff pair. Call after writing the beat that seeds the plant detail. plant_payoff_id = GUID returned by register_plant_payoff; beat_id = GUID of the beat containing the plant.

  • plantPayoffId (string, required) — PlantPayoff id (GUID) from register_plant_payoff.
  • beatId (string, required) — Beat GUID containing the plant.

register_plant_payoff

Register a new plant/payoff pair for a node. Call this when you're about to write (or have just written) a detail that will pay off later. plant_description = what is seeded (the observable detail the cold reader sees but doesn't decode); payoff_description = what the re-reader gets (the deeper meaning on return). Category options: detail, echo, irony, motif, character-truth, structural. Optionally link to specific beats by their GUID ids (plant_beat_id, payoff_beat_id). Accepts node id (GUID) or slug.

  • nodeIdOrSlug (string, required) — Node id (GUID) or slug.
  • plantDescription (string, required) — What is seeded — the detail the cold reader encounters but doesn't decode. Example: 'Kyle's hand twitches when he mentions Seo.'
  • payoffDescription (string, required) — How it pays off — what the returning reader gets on re-read. Example: 'On re-read, the twitch reveals the mentor was fabricated long before Kyle admits it.'
  • category (string, optional) — Category: detail | echo | irony | motif | character-truth | structural
  • plantBeatId (string, optional) — Beat GUID where the plant is seeded (omit if not yet written).
  • payoffBeatId (string, optional) — Beat GUID where the payoff occurs (omit if not yet written).

set_plant_transparency

Record whether a payoff beat stands alone for cold readers (is_transparent) and what the re-reader gains (note). is_transparent=true means the payoff makes complete narrative sense without having read/remembered the plant. is_transparent=false is a writing bug — fix the payoff beat before marking the node gateway-ready. note should name the specific additional layer the returning reader receives.

  • plantPayoffId (string, required) — PlantPayoff id (GUID).
  • isTransparent (bool, required) — True = the payoff reads completely for a cold reader; false = it requires catching the plant (writing bug).
  • note (string, optional) — What the re-reader gains that the first-timer doesn't. Required when is_transparent=true.

update_plant_payoff

Correct a registered plant/payoff pair's descriptions in place when the register disagrees with the page (the page wins). Omit a side to leave it unchanged. The pair's plant obligation follows. Returns the row as read back.

  • plantPayoffId (string, required) — PlantPayoff id (GUID).
  • plantDescription (string, optional) — New plant description (omit to keep).
  • payoffDescription (string, optional) — New payoff description (omit to keep).

Quality

QualityTools

get_review_settings

Return the current review-voting configuration: how many score-ballots and prose upgrades a sampled run casts, the persona panel depth, default reader count, max parallel ballot slots, judge provider, the comma-separated list of allowed providers, and whether the continuous auto-review monitor is enabled. Use update_review_settings to change any value.

  • (no parameters)

get_review_summary

Return the stored review summary for a node — the synthesized aggregate of what readers liked, recurring gripes, and concrete improvement suggestions, written by the judge after the last review run. Includes average score, review count, and content hash so you can tell whether the summary is stale (node was edited after the last run). Call review_node to refresh. Accepts node id (GUID) or slug.

  • nodeIdOrSlug (string, required) — Node id (GUID) or slug.

list_book_reviews

List individual ballot reviews for a node — one row per persona reader, showing persona name, provider, score, flow score (if study mode), improvements, and content hash. Use to inspect which personas scored low and what they said, or to compare how different providers voted. Results are sorted most-recent-first. Accepts node id (GUID) or slug.

  • nodeIdOrSlug (string, required) — Node id (GUID) or slug.
  • contentHash (string, optional) — Only return reviews from this content hash (i.e. one specific review run). Leave empty for all reviews.
  • limit (int, optional) — Maximum rows to return. Default 50.

update_review_settings

Update review-voting settings. Pass only the fields you want to change — omit the rest. ballots: score-only ballot count (≥1). prose: full prose upgrades per run (≥0). panel: persona pool depth (≥1). readers: default reader count (≥1). max_concurrency: parallel ballot slots 1–50. judge_provider: provider that synthesizes the summary (claude|openai|gemini|deepseek). allowed_providers: comma-separated provider whitelist (e.g. 'claude,openai'); empty = all active providers allowed. review_auto_run_enabled: set false to disable the continuous auto-review monitor (you call reviews manually); set true to re-enable.

  • ballots (int, optional) — Score-only ballot count (≥1). Omit to leave unchanged.
  • prose (int, optional) — Full prose upgrades per run (≥0). Omit to leave unchanged.
  • panel (int, optional) — Persona pool depth (≥1). Omit to leave unchanged.
  • readers (int, optional) — Default reader count (≥1). Omit to leave unchanged.
  • maxConcurrency (int, optional) — Parallel ballot slots, 1–50. Omit to leave unchanged.
  • judgeProvider (string, optional) — Provider that synthesizes the summary. Omit to leave unchanged.
  • allowedProviders (string, optional) — Comma-separated provider whitelist (e.g. 'claude,openai'). Empty string = all active. Omit to leave unchanged.
  • reviewAutoRunEnabled (bool, optional) — False = disable the continuous auto-review monitor (call reviews manually). True = re-enable. Omit to leave unchanged.

validate_canon_text

Scan arbitrary prose against every world rule (no city police, no Behemoth-as-alive, no 'the Shelf' district, no wedding-cake tier architecture, no Ferrogate-as-railroad, no metro/city police, no phi/Greek-letter confusion). Returns the list of matched violations with the surrounding context. Call this on a chapter draft BEFORE delivering it — catches rule slips Claude might miss.

  • text (string, required) — The prose to scan. Pass an entire chapter or a single beat.

Reading

ReadingTools

add_read_note

File what a read found on one beat: kind defect | question | note. Stamped with the beat's current text hash, so list_read_notes shows when the beat has changed since. This records what a reader noticed; it is not canon.

  • nodeIdOrSlug (string, required) — Book or chapter id, slug, or NodeCode.
  • beat (int, required) — Global Beat.Number of the beat.
  • kind (string, required) — defect | question | note
  • text (string, required) — What the reader noticed.
  • readBy (string, required) — Who read it.

list_read_notes

Read notes on a book's beats in reading order. beat_changed_since = the beat's text no longer matches what the note was written against.

  • nodeIdOrSlug (string, required) — Book or chapter id, slug, or NodeCode.
  • status (string, optional) — open (default) | resolved | all
  • kind (string, optional) — Optional: defect | question | note

read_status

Which beats of a book (or chapter) are unread as they stand now, and why: never read, text changed since it was read, moved (the beat before or after it changed — a chapter move or an insert/delete beside it), or an entity it mentions was edited after it was read. Computed on demand from text hashes; nothing is stored that could drift. Export refuses while any beat is unread, with no override — read the listed beats with read_beats(markRead:true) first.

  • nodeIdOrSlug (string, required) — Book or chapter id, slug, or NodeCode.
  • limit (int, optional) — Max unread beats to list individually (default 200). Counts are always complete.

resolve_read_note

Resolve a read note: a question answered or a defect fixed. Optionally name the beat (global Beat.Number) that answered it.

  • nodeIdOrSlug (string, required) — Book or chapter id, slug, or NodeCode.
  • noteId (string, required) — Note id from list_read_notes.
  • byBeat (int, optional) — Optional Beat.Number of the beat that answered or fixed it.

Repository

RepositoryTools

browse_repository

Browse entities by repository/type (built-in - character, place, faction, weapon, corponation, ... - or a custom one from create_repository) without hand-written SQL. Omit type to list every repository type present in the current universe with counts.

  • type (string, optional) — EntityType/repository slug to browse, e.g. 'character'. Omit to list types.
  • search (string, optional) — Optional free-text filter over Name/Description.
  • page (int, optional) — 1-based page number (default 1).
  • pageSize (int, optional) — Rows per page, 1-200 (default 25).

create_repository

Create a new repository (custom entity type). The slug is derived from the name (lowercased, hyphenated) and must be unique. Category is one of Characters/Organizations/Gear/World/Culture (defaults to World). Returns the created slug + route, or an error if the slug already exists.

  • name (string, required) — Display name, e.g. 'Artifacts'. The slug is derived from this.
  • category (string, optional) — Board category: Characters, Organizations, Gear, World, or Culture. Defaults to World.
  • icon (string, optional) — Bootstrap-icon class for the tile, e.g. 'bi-box'. Optional.
  • description (string, optional) — Optional description of what this repository holds.

list_repositories

List all runtime-defined repositories (custom entity types): slug, name, category, route.

  • (no parameters)

Ruling

RulingTools

book_metrics

Book-wide tic counts against the author's metric rulings (counting, not judging). Only author-sourced metrics gate the press.

  • nodeIdOrSlug (string, required) — Book id, slug or NodeCode.

law_violations

Every place an active law's zero-tolerance pattern matches the book's prose, in reading order, with context. Each hit is either a real violation (fix the prose by splice) or a pattern that is too broad (supersede the ruling with a tighter pattern).

  • nodeIdOrSlug (string, required) — Book id, slug or NodeCode.

list_rulings

The active rulings that apply to a book (its own plus universe-wide ones).

  • nodeIdOrSlug (string, required) — Book id, slug or NodeCode.
  • kind (string, optional) — law | page-law | metric | incidental | gate

record_law_violations

Every place an active law's pattern matches the canonical record of an entity the book tags (the world must not hold what the page may not say). Page-laws are not applied to records: they name facts the record is meant to hold. Each hit is fixed on the record (set_character_fields / create_*), or the pattern is superseded if too broad.

  • nodeIdOrSlug (string, required) — Book id, slug or NodeCode.
  • entityId (string, optional) — Narrow to one entity's record.
  • searchPattern (string, optional) — Search the records for this one .NET regex instead of the laws (read-only, recorded nowhere).

record_ruling

Record one of the author's rulings the moment it is made. kind law = a constraint (pattern-less text the writer is shown, or a zero-tolerance regex neither the prose nor any record the book tags may match; case-insensitive unless the pattern starts with (?-i)); kind page-law = a fact the world holds but the page must never say (its pattern binds the prose only); kind metric = a book-wide tic ceiling (pattern + maxPer1kWords); kind incidental = a proper name that intentionally has no entity (pattern = the name); kind gate = switch a factory gate on (text = the gate's name, e.g. plan-first: F3 then needs every prose beat's Description current against its prose, F7 every plant/payoff bound). A ruling on a series node binds every book under it. Entity facts do NOT go here — write them on the entity record. Returns the stored row as the read-back.

  • kind (string, required) — law | page-law | metric | incidental | gate
  • text (string, required) — The author's words, verbatim.
  • nodeIdOrSlug (string, optional) — Book or series id, slug or NodeCode (omit only for a universe-wide ruling).
  • pattern (string, optional) — .NET regex (law/metric) or the name (incidental).
  • maxPer1kWords (Decimal, optional) — Metric only: the ceiling per 1,000 words of the whole book.
  • source (string, optional) — author (default) or session:.

supersede_ruling

Replace a ruling: the new one is recorded and the old one goes inert (history is kept).

  • id (string, required) — The ruling to replace.
  • kind (string, required) — law | page-law | metric | incidental | gate
  • text (string, required) — The author's new words, verbatim.
  • pattern (string, optional) — New pattern.
  • maxPer1kWords (Decimal, optional) — Metric only.
  • source (string, optional) — author (default) or session:.

Scene

SceneTools

assemble_scene_context

X-Ray scene assembly (RFC 0002): given a Beat guid OR raw prose text, detect which entities are on screen (name/alias scan + embedding similarity + one-hop graph expansion) and return the roster plus a budgeted context block carrying each character's voice fields (vocabulary, cadence, subtext, under-pressure, intimacy register, example lines) and each place/object's gloss — the live memory block prose prompts should receive.

  • beatIdOrText (string, required) — A Beat guid, or any prose text to assemble a scene roster for.
  • tokenBudget (int, optional) — Token budget for the context block (default 2000).

get_character_wounds

List a character's ACTIVE wounds from the WoundLedger (the literal body map): location, description, severity, source, healing status, and the residual effect prose must honor (favored limbs, reduced grip, exertion costs).

  • characterId (string, required) — Character guid (e.g. Kyle = 019d6143-a648-7876-9688-0f6d38d70075).

log_wound

Log a wound to the WoundLedger. Use when the story wounds a character so the body map stays factual: future prose prompts will carry it as an ACTIVE WOUND until its status moves to healed/scarred.

  • characterId (string, required) — Character guid.
  • bodyLocation (string, required) — Body location, side+region (e.g. 'left forearm', 'ribs, right side').
  • description (string, required) — What happened, one sentence.
  • severity (string, required) — minor | moderate | severe
  • residualEffect (string, optional) — Residual effect the prose must honor (e.g. 'grip 90 percent; two-handed work hurts').
  • sourceNodeSlug (string, optional) — Source node slug, if known.
  • expectedHealingDays (int, optional) — Expected healing days (default 14; AutoDoc shortens, never zeroes).

set_wound_status

Update a wound's status: fresh | healing | healed | scarred. Scarred wounds stop appearing in prompts (graduate permanent marks to CharacterPhysicalMarks separately).

  • woundId (long, required) — Wound id from the ledger.
  • status (string, required) — fresh | healing | healed | scarred

Species

SpeciesTools

get_species

Get the full record for one species by canonical name (e.g. 'ai', 'elf', 'synthetic'). Returns name, label, description, examples, and sentient flag. Returns {error: not_found} when the name doesn't match.

  • name (string, required) — Canonical species name, e.g. 'human' or 'elf'.

list_species

List all species in the current universe. Returns canonical name (key used on Character.Species), label, and sentient flag. The five GLMZ values are: human, ai, elf, synthetic, unknown.

  • (no parameters)

Spelling

SpellingTools

add_dictionary_word

Add a word to the author's spelling dictionary. One entry covers its inflections: adding 'CorpoNation' also accepts CorpoNations, CorpoNation's and CorpoNations'. A word with capitals must be written with them; an all-lowercase word matches any capitalisation. A possessive is stored as its bare word. Returns the stored row.

  • word (string, required) — One word (letters and apostrophes; a hyphenated word is two words).
  • addedBy (string, optional) — Who added it: author (default), or session:.

list_dictionary_words

List the author's spelling dictionary: every word the Writer's spellcheck accepts beyond English and the universe's entity names. One entry covers its plural and possessive forms.

  • (no parameters)

remove_dictionary_word

Remove a word from the author's spelling dictionary (matched without regard to case).

  • word (string, required) — The word.

Story

StoryTools

delete_book_permanently

LEGACY. Permanently delete a book from the old pre-Nodes Records/Entities book shelf only (create_legacy_book writes here) — hard-deletes its Books and Entities rows. Does NOT reach current Nodes-table books: those will report error:'not_found' here even though they exist. For a current book, use the CLI prose --delete-node --id <guid> [--force] instead (never raw sqlcmd DELETE on Nodes). This tool is DESTRUCTIVE for what it does reach — chapters/beats are not touched but the book record itself is gone from normal queries, recoverable only via Entities_History / prose --restore-entity. Requires the caller to retype the full book id as a confirmation token (matches the UI's type-the-guid modal). Returns ok:true on success or error:'confirmation_mismatch' / error:'not_found' otherwise.

  • id (string, required) — Book id (32-char hex).
  • confirmId (string, required) — Confirmation token — must equal the same full book id. Mismatched or missing values abort the deletion.

get_chapter

Load a single chapter by id: synopsis, full HTML body, persisted beats list (each with structure_role + text), participating characters. Use this to read existing prose before extending or revising.

  • id (string, required) — Chapter id (32-char hex).

get_legacy_book

LEGACY. Load a book by id from the old pre-Nodes Records/Entities book shelf only (create_legacy_book writes here). Does NOT resolve current Nodes-table books/slugs — use get_book for those. Full metadata, chapter id list (canonical order), state_at_end (open threads, character status carry-forward, canon changes).

  • id (string, required) — Legacy book id (32-char hex like 'eb91080d9c9c4f2b9b405fa5996bdea1').

list_legacy_books

LEGACY. List books in the old pre-Nodes Records/Entities book shelf only (create_legacy_book/create_legacy_chapter write here). Does NOT include current Nodes-table books — use list_books for those. Returns id, title, premise, chapter count, status, protagonists.

  • (no parameters)

Survey

SurveyTools

answer_survey_question

Record the user's answer for one survey question. selectedOption is the letter key ('a', 'b', 'c', or 'd'). Call this once per question after the user exports their answers from the artifact.

  • surveySlug (string, required) — Survey slug.
  • questionKey (string, required) — Question key, e.g. 'Q-001'.
  • selectedOption (string, required) — Selected option letter: 'a', 'b', 'c', or 'd'.

complete_survey

Mark a survey as Completed. All questions should be Applied or Skipped before calling this.

  • slug (string, required) — Survey slug.

create_survey

Create a new canon-sync or contradiction-resolution survey. questions is a JSON array of {questionKey, title, context?, questionType?, options} where options is an array of {key, label, description?}. questionType values: PlaceDescription, TechnologyDescription, WeaponRename, FactionDescription, CharacterDescription, BeatText, DocUpdate, ContradictionResolve, Custom. Returns the survey id and slug. Call get_survey_html to generate the artifact HTML.

  • slug (string, required) — URL-safe slug, e.g. 'canon-sync-2026-07-05'.
  • title (string, required) — Human-readable title.
  • questionsJson (string, required) — JSON array of question objects. Each: {questionKey, title, context?, questionType?, options:[{key,label,description?}]}
  • purpose (string, optional) — Optional purpose / scope description.
  • universeSlug (string, optional) — Universe slug ('glmz' or 'fantasy'). Omit for universe-neutral.

get_survey

Retrieve a survey with all questions and their current answer state. Returns the survey metadata, each question's key/title/type/options/selectedOption/applyStatus.

  • slug (string, required) — Survey slug.

get_survey_html

Generate the interactive artifact HTML for a survey. Returns the full HTML string ready to be published as an artifact. After calling this, publish it via the Artifact tool with the survey slug as the filename.

  • slug (string, required) — Survey slug.

list_surveys

List surveys. Filter by status ('Open' or 'Completed') or omit for all.

  • status (string, optional) — 'Open' or 'Completed'. Omit for all.

mark_survey_question_applied

Mark a survey question as applied (or skipped) after the fix has been made. applyStatus: 'Applied' (default) or 'Skipped'. applyNotes should describe what was changed (SQL table/column, MCP tool used, etc.).

  • surveySlug (string, required) — Survey slug.
  • questionKey (string, required) — Question key, e.g. 'Q-001'.
  • applyNotes (string, required) — Description of what was changed.
  • applyStatus (string, optional) — 'Applied' or 'Skipped'. Defaults to 'Applied'.

Universe

UniverseTools

current_universe

Return the universe currently active for this session (slug + name).

  • (no parameters)

get_universal_facts

Return the universal world facts for the current universe — world mechanics, vocabulary, and social rules injected into every beat generation prompt. These apply to all books in the universe. Book-specific facts live in that book's beats and its canon entities instead.

  • (no parameters)

list_universes

List every registered universe (slug, name, theme) and which one is currently active. Call this first to discover universe slugs before switch_universe.

  • (no parameters)

set_universal_facts

Set the universal world facts for the current universe. These facts are injected into every beat generation prompt for any book in this universe, so they should cover mechanics and vocabulary that apply everywhere (transport, technology, social structure, prose vocabulary). Book-specific content belongs in that book's beats and canon entities, not here.

  • facts (string, required) — The full world facts text in Markdown. Replaces any existing content. Pass empty string to clear.

switch_universe

Switch the active universe for this session by slug (e.g. 'glmz' or 'scry'). All subsequent canon/story reads are scoped to it. Returns the new current universe or an error if the slug is unknown.

  • slug (string, required) — Universe slug from list_universes, e.g. 'glmz'.

Universe Interchange

UniverseInterchangeTools

export_universe_file

Export a Prose universe to Universe Interchange JSON (RFC 0007) at the given path.

  • slug (string, required) — Universe slug, e.g. 'eve'.
  • path (string, required) — Absolute output path for the exported JSON file.

get_universe_entity

Look up one entity in a specific universe by slug. Cross-universe — does NOT switch the session's active universe (unlike the generic entity tools).

  • slug (string, required) — Universe slug, e.g. 'eve'.
  • entitySlug (string, required) — Entity slug within that universe, e.g. 'kat-weiss'.

import_universe_file

Import a Universe Interchange JSON file (RFC 0007, docs/schemas/universe.schema.json) into Prose's Entity spine. Universe slug defaults to the file's own universe.id. Idempotent — re-importing the same file is a no-op diff.

  • path (string, required) — Absolute path to the .universe.json file.
  • slug (string, optional) — Optional universe slug override; defaults to the file's own universe.id.

search_universe

Search a specific universe's entities by name substring. Cross-universe — does NOT switch the session's active universe.

  • slug (string, required) — Universe slug, e.g. 'eve'.
  • query (string, required) — Name substring to search for.

Verification

VerificationTools

verify_quote_grounding

Verify that a logic-sweep audit agent's CLAIMED QUOTE actually appears in the beat it's attributed to, before that finding is trusted for triage/fix. Use this on every quoted finding an audit agent reports — agents occasionally misattribute a quote to the wrong beat or fabricate one under time pressure; this is the mechanical guard against that. Comparison is normalized (dash variants, curly/straight quotes, whitespace), so only a genuine misattribution fails — not console-display punctuation drift. Result is persisted to BeatVerification (CheckType='QuoteGrounding', always inserted, never overwritten — a beat accumulates one row per claim checked across every sweep). A Fail means: reject the finding and re-read the actual beat before acting on it.

  • beatId (string, required) — Beat GUID the finding claims this quote came from.
  • quote (string, required) — The exact text the audit agent claims appears in this beat.
  • claimedBy (string, optional) — Optional: which agent/pass made this claim, for the audit trail.

verify_quote_grounding_batch

Batch form of VerifyQuoteGrounding: gate an ENTIRE audit report in one call before triage. Pass every (beatId, quote) claim the audit produced; get back which ones are actually grounded in their attributed beat and which must be rejected/re-verified. Run this before triaging any logic-sweep audit findings that quote beat text (SS-LOGIC-4a).

  • claimsJson (string, required) — JSON array of claims: [{"beatId":"","quote":""}, ...]
  • claimedBy (string, optional) — Optional: which agent/pass made these claims, for the audit trail.

Voice

VoiceTools

apply_voice_proposal

Apply a proposed voice rule to the live voice store (the DB-backed rules the generator reads). Pass the entry id returned by harvest_voice or list_voice_proposals. The entry status changes to 'applied'. Returns ok=true on success, or error if the entry was not found or already resolved.

  • entryId (string, required) — The voice change-log entry GUID to apply.

harvest_voice

Distill voice rules from a winning node (score ≥80) into proposed change-log entries. Nothing touches the live rule store until apply_voice_proposal is called. Pass force=true to harvest even if the node scored below 80. Returns the list of proposed entries with their ids, rule targets, descriptions, and evidence.

  • nodeIdOrSlug (string, required) — Node id (GUID) or slug to harvest from.
  • force (bool, optional) — Set to true to harvest even if the node scored below 80%.

harvest_voice_all

Distill voice rules from every node scored >=threshold (default 80). Score gates were retired project-wide (SS-A44) so almost no node has a Score anymore — this will likely return empty. Prefer harvest_voice_canon or harvest_voice_node(force:true) instead. Returns proposals grouped by node slug. Nothing is written to the live rule store until apply_voice_proposal is called.

  • threshold (double, optional) — Minimum Node.Score to include (0-100). Default 80. Only affects nodes that HAVE a Score — most nodes have none post-SS-A44.

harvest_voice_canon

Distill voice rules from every node the author has marked Canon (IsCanon=true) — the recommended harvest gate post-SS-A44, since almost no node carries a Score anymore. Returns proposals grouped by node slug. Nothing is written to the live rule store until apply_voice_proposal is called.

  • (no parameters)

list_voice_proposals

List voice change-log entries filtered by status. Use status='proposed' to see pending proposals awaiting a decision. Each entry shows its id (use for apply/reject), rule target, description, evidence, and source node.

  • status (string, optional) — Filter by status: 'proposed' | 'applied' | 'rejected' | 'observed'. Default 'proposed'.

reject_voice_proposal

Reject a proposed voice rule. The entry stays in the audit trail (status = 'rejected') so the decision is traceable. Pass the entry id returned by harvest_voice or list_voice_proposals.

  • entryId (string, required) — The voice change-log entry GUID to reject.

Workflow Monitor

WorkflowMonitorTools

workflow_beat_modes

Get the detected beat mode log for a node. Shows how each beat was classified (Narrative/Combat/EmotionalClimax/Dialogue/Transition/Revelation) and the confidence level.

  • slug (string, required) — Node slug

workflow_status

Get prose service coverage for a node. Returns, for every service the live write path logs (~30 rows per beat: Pacing, StoryMethodology, EntityContext, DocContext, SceneContextAssembler, ContinuityEnforcer, …), how often it was applicable and how often it actually contributed a non-empty prompt block, and flags gaps where applicable services went unused. For per-beat LLM-call counts by stage use prose --beat-write-trace.

  • slug (string, required) — Node slug (e.g. 'ATTE', 'BCODA')

workflow_status_global

Get global prose workflow coverage across all nodes. Returns per-service utilization rates and a list of nodes with coverage gaps.

  • (no parameters)

World

WorldTools

set_character_fields

Set any fields of a character's record, by the same snake_case keys get_character returns (behavioral, timeline, cyberware_inventory, neural_abilities, genetic_ancestry, knowledge, psychology, relationships, story_hooks, aliases, …). JSON Merge Patch (RFC 7396): a key present sets that field; null clears it; a key absent is untouched; objects merge one level down the same way (so {"behavioral":{"habits":[…]}} leaves decision_rules alone); lists replace whole and are JSON arrays, so nothing is split on commas. Refused: id, type, location, rating, vote_count. Cost-visible: if the change would un-read beats that were read, it is refused with the count unless confirmUnread is true. Returns what changed and the record as read back from the database.

  • id (string, required) — Character id (32-char hex or UUID).
  • fieldsJson (string, required) — JSON object of field → value, e.g. {"age":27,"story_hooks":["…"],"behavioral":{…}}.
  • confirmUnread (bool, optional) — Make the write even though it un-reads the listed beats (then re-read them).

set_entity_fields

Set any fields of ANY entity's record — faction, place, weapon, corponation, cyberware, and every other repository type (characters are routed to set_character_fields' rules) — by the same snake_case keys its get_* tool returns. JSON Merge Patch (RFC 7396): a key present sets it, null clears it, a key absent is untouched, objects merge, lists replace whole (JSON arrays; nothing is split on commas). Refused: id, type, rating, vote_count. Cost-visible: refused with the count if it would un-read read beats, unless confirmUnread. Returns what changed and the record as read back.

  • id (string, required) — Entity id (32-char hex or UUID).
  • fieldsJson (string, required) — JSON object of field → value.
  • confirmUnread (bool, optional) — Make the write even though it un-reads the listed beats (then re-read them).

verify_entity_begin

Station F1, step 1: deliver an entity's canonical record and the beats of a book that tag it (text up to a budget), with a nonce sealing both. Examine the record against the book as read, then verify_entity_commit(nonce). If the record is wrong, fix it instead (set_character_fields), re-read what that un-reads, and begin again.

  • entityId (string, required) — Entity id.
  • nodeIdOrSlug (string, required) — Book id, slug or NodeCode.
  • textBudgetChars (int, optional) — Characters of mention text to include (default 40000; 0 = none).

verify_entity_commit

Station F1, step 2: record that the entity's record was examined against the book. Refused if the record or any beat that mentions it changed since begin, or if any of those beats is unread.

  • nonce (string, required) — The nonce verify_entity_begin returned.
  • by (string, optional) — Who examined it.

World Entity Crud

WorldEntityCrudTools

create_automaton

Create or update an automaton (drone, security bot, Iowan Behemoth, agricultural machine) in canon. Automata are machines, NOT synthetic life. Pass empty id to create new; pass an existing id to update.

  • name (string, required) — Automaton name. Required.
  • description (string, optional) — Prose description.
  • manufacturer (string, optional) — Manufacturer name.
  • tags (string, optional) — Comma-separated tags.
  • id (string, optional) — Optional existing automaton id to update.

create_consumer_good

Create or update a consumer good (food, drinks, household items, branded products) in canon. Pass empty id to create new; pass an existing id to update.

  • name (string, required) — Consumer good name. Required.
  • productName (string, optional) — Product name if different from name.
  • category (string, optional) — Category (e.g. 'food', 'beverage', 'household', 'luxury').
  • description (string, optional) — Prose description.
  • manufacturer (string, optional) — Manufacturer or brand.
  • tags (string, optional) — Comma-separated tags.
  • id (string, optional) — Optional existing consumer good id to update.

create_document

Create or update a worldbuilding document in canon. Documents hold long-form canon text (lore articles, guides, in-world publications). Pass empty id to create new; pass an existing id to update.

  • fileName (string, required) — Document file name (slug, e.g. 'network_operators_guide'). Required.
  • title (string, required) — Document title. Required.
  • category (string, optional) — Category (e.g. 'lore', 'technical', 'in-world-publication', 'history').
  • body (string, optional) — Full prose body of the document.
  • tags (string, optional) — Comma-separated tags.
  • id (string, optional) — Optional existing document id to update.

create_subsidiary

Create or update a subsidiary (child/holding company of a larger CorpoNation) in canon. Pass empty id to create new; pass an existing id to update.

  • name (string, required) — Subsidiary name. Required.
  • parentCorponation (string, optional) — Parent CorpoNation name.
  • description (string, optional) — Prose description.
  • tags (string, optional) — Comma-separated tags.
  • id (string, optional) — Optional existing subsidiary id to update.

create_transportation

Create or update a transportation entry (vehicle, transit line, Pulse station, individual transport) in canon. Pass empty id to create new; pass an existing id to update.

  • name (string, required) — Transportation name. Required.
  • category (string, optional) — Category (e.g. 'motorcycle', 'rail', 'air', 'Pulse', 'water').
  • description (string, optional) — Prose description.
  • manufacturer (string, optional) — Manufacturer name.
  • tags (string, optional) — Comma-separated tags.
  • id (string, optional) — Optional existing transportation id to update.

create_vocabulary

Create or update a vocabulary entry in canon — slang, jargon, craft terms, street cant. This is the entity type prose tags as repo="vocabulary", so an entry here gives the word a GUID that beats can reference. Matching on an existing term updates it. Omitted fields are LEFT UNCHANGED. NOTE: this is not the reader-facing glossary — for a definition in a book's back matter, also call upsert_glossary_term; a craft term usually wants both.

  • term (string, required) — The term as it appears in prose. Required. An existing term updates that entry.
  • definition (string, optional) — What it means.
  • origin (string, optional) — Where it comes from — language, trade, subculture.
  • usage (string, optional) — How it is actually used, and by whom.
  • category (string, optional) — Grouping category (e.g. 'Swordsmithing', 'Street', 'Enforcement').
  • example (string, optional) — A short example of the term in use.
  • tier (string, optional) — Tier availability or currency of the term.
  • tags (string, optional) — Comma-separated tags. '[]' clears; appendTags merges instead of replacing.
  • appendTags (bool, optional) — Merge tags into the existing list instead of replacing. Default false.

World Modelling

WorldModellingTools

add_prose_lesson

Add an editorial prose lesson — an author ruling that reviewers must respect. Lessons are injected into every future review ballot prompt so the panel does not penalise beats the author has already decided are doing their job in the sequence. scope: 'global' applies to all nodes; 'node:' to one node; 'beat:' to one beat. kind: score-vs-function | delight | voice | pacing | continuity | other.

  • scope (string, required) — Scope: 'global', 'node:', or 'beat:'
  • kind (string, required) — Kind: score-vs-function | delight | voice | pacing | continuity | other
  • text (string, required) — The ruling text — what reviewers must respect.

clear_entity_stale

Clears the EntityStale flag on a beat after the author has reviewed it and confirmed the prose is still consistent with current entity canon.

  • beatId (string, required) — Beat GUID

get_ambient_palette

Returns the sensory detail palette for a character's carried gear. Inject the result into a beat prompt to ground sensory texture in what the character actually carries.

  • characterId (string, required) — Character entity GUID
  • asOfDate (string, optional) — Story-date filter (ISO 8601). Omit for current carry edges.

get_character_equipment

Returns a character's full equipment across all slots: primary/secondary/ranged weapons, armor, tool, signature gear, pharmaceuticals, and carried loot. Use for scene continuity, loot tracking, and loadout management.

  • characterSlug (string, required) — Character entity slug (e.g. 'kyle_ellen_corbin', 'sasha_vo').

get_character_loadout

Returns a character's weapon loadout from their signature_gear list, with ammo types for each weapon. Use for scene continuity and logistics.

  • characterId (string, required) — Character entity GUID
  • asOfDate (string, optional) — Story-date filter (ISO 8601). Omit for all-time loadout.

get_entity_tree

Returns a hierarchical relationship tree rooted at an entity, traversing the Edge graph up to maxDepth hops. Formatted as a prompt-injectable context block. Use before generation to understand who/what an entity is connected to.

  • entityId (string, required) — Entity GUID
  • maxDepth (int, optional) — Maximum hop depth (default 3)
  • relTypes (string, optional) — Comma-separated relation types to follow, e.g. 'carries,wields,member_of'. Omit for all.

get_weapon_network

Returns the ammo network for a weapon: its ammunition types + sibling weapons that share at least one chambering. Use for continuity (scavenging compatible rounds, borrowing ammo between characters) and world enrichment.

  • weaponId (string, required) — Weapon entity GUID

get_world_state_at_beat

Returns the world-state snapshot at a given beat: all entity aspect states (wounds, location, status…) + active relationships. Use to inject consistent 'what is true right now' context before writing a beat.

  • beatId (string, required) — Beat GUID
  • storyTime (string, optional) — Story-world timestamp override, ISO 8601. Inferred from beat events when omitted.

list_entity_stale_beats

Returns every beat flagged EntityStale — i.e. a canon entity mentioned in the beat was updated after the beat was written. Grouped by node. Review each beat and call clear_entity_stale when satisfied.

  • (no parameters)

list_prose_lessons

List prose lessons from the editorial memory store. When scope is omitted, returns all lessons across all scopes. When scope is provided, returns only lessons whose scope starts with that prefix (e.g. 'global' for all global lessons, 'node:my-slug' for a specific node).

  • scope (string, optional) — Optional scope filter prefix (e.g. 'global', 'node:my-slug'). Omit for all.

validate_beat

Run the full post-beat validation battery on a saved beat: prose pattern guard (clichés, pseudo-profound, on-the-nose, italicised dialogue) + gear carry check (character uses gear without a carry edge). All violations are filed as Findings and returned. Accepts an optional comma-separated list of character GUIDs; when omitted, characters are derived from the beat's indexed entity mentions.

  • beatId (string, required) — Beat GUID.
  • characterIds (string, optional) — Comma-separated character GUIDs to check gear for. Omit to auto-detect from entity mentions.
  • storyTime (string, optional) — Story-date for gear edge validation (ISO 8601). Omit for all-time carry edges.

Writing

WritingTools

add_chapter_to_book

Append an existing chapter id to a book's chapter_ids list. Use when a chapter and a book were created independently. Sets the chapter's BookId and Number to match. Idempotent — re-running with the same chapter moves it to the requested position.

  • bookId (string, required) — Book id.
  • chapterId (string, required) — Chapter id to attach.
  • number (int, optional) — Chapter position (1-indexed). 0 = append.

create_legacy_book

LEGACY Book/Chapter schema — new work should use create_series / create_book instead. Create or upsert a Book record. Pass an empty id to create a new book (a v7 GUID is assigned and returned); pass a known id to update an existing book. Returns the persisted Book including assigned id.

  • title (string, required) — Book title. Required.
  • premise (string, required) — One-paragraph premise — feeds the chapter director when extending.
  • protagonists (string, required) — Comma-separated protagonist names — first name is the lead. Resolved against character canon.
  • arcTarget (string, optional) — What this book is about and where it lands. Used as the extension target. Optional.
  • tagline (string, optional) — Optional tagline shown beneath the title on the bookshelf card.
  • status (string, optional) — Book status: drafting | preserved | published | archived. Empty keeps the current status of an existing book and means 'drafting' for a new one.
  • id (string, optional) — Optional book id to update an existing record. Empty creates a new book.

create_legacy_chapter

LEGACY Book/Chapter schema — new work should use create_chapter (node tree) instead. Create or upsert a Chapter record. Pass an empty id to create new; pass a known id to update. Returns the persisted Chapter including assigned id.

  • title (string, required) — Chapter title. Required.
  • synopsis (string, required) — One-paragraph chapter synopsis. Required.
  • html (string, required) — Full chapter prose. HTML or plain text — plain text is wrapped in

    tags on render.

  • characters (string, required) — Comma-separated character names participating in this chapter.
  • bookId (string, optional) — Parent book id. Empty leaves the chapter orphaned.
  • number (int, optional) — Chapter number within the book (1-indexed). Ignored when bookId is empty.
  • status (string, optional) — Chapter status: draft | revising | reviewed | published. Defaults to 'draft'.
  • id (string, optional) — Optional chapter id to update an existing record. Empty creates new.