update_plan
Patch the book bible JSON file and sync characters, deaths, or gags into the project to maintain continuity.
Instructions
Patch book_bible.json; may sync characters/deaths/gags into project.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| section | No | all | |
| changes | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes |
Implementation Reference
- src/storywright_mcp/planning.py:443-462 (handler)Core handler for update_plan tool: loads the book bible, applies section changes via apply_bible_section, saves, and optionally syncs characters/deaths/gags into the project via finalize_bible.
async def run_update_plan(section: str = "all", changes: dict | None = None) -> str: proj, _cont = require_project() bible = BookBible.load(proj.base_path) if changes is None: return ( f"# Update bible — section `{section}`\n\n" f"Call update_plan(section=\"{section}\", changes={{...}}) with partial bible fields.\n" f"Use get_book_bible() to review.\n" ) apply_bible_section(bible, section, changes) bible.save(proj.base_path) if section in ("all", "characters", "deaths", "gags"): finalize_bible(bible, proj, _cont) else: save_project_and_continuity() return f"Bible updated (section={section}). Sync ran for characters/deaths/gags sections." - src/storywright_mcp/app.py:144-150 (registration)Tool registration via @mcp.tool() decorator on FastMCP instance. Delegates to run_update_plan.
@mcp.tool() async def update_plan(section: str = "all", changes: dict | None = None) -> str: """Patch book_bible.json; may sync characters/deaths/gags into project.""" try: return await run_update_plan(section=section, changes=changes) except ValueError as e: return str(e) - Helper that applies partial bible field changes per section (all, identity, world, characters, structure, deaths, gags, tone). Deserializes nested models as needed.
def apply_bible_section(bible: BookBible, section: str, changes: dict) -> None: if section == "all": for key, value in changes.items(): if hasattr(bible, key): setattr(bible, key, value) return if section == "identity": if "title" in changes: bible.title = changes["title"] if "genre" in changes: bible.genre = changes["genre"] if "logline" in changes: bible.logline = changes["logline"] if "themes" in changes: from .models.bible import Theme bible.themes = [ Theme(name=t["name"], description=t.get("description", "")) if isinstance(t, dict) else t for t in changes["themes"] ] if "comparable_books" in changes: bible.comparable_books = changes["comparable_books"] elif section == "world": if "world_name" in changes: bible.world_name = changes["world_name"] if "world_description" in changes: bible.world_description = changes["world_description"] if "world_rules" in changes: bible.world_rules = changes["world_rules"] if "magic_systems" in changes: from .models.bible import MagicSystem bible.magic_systems = [ MagicSystem(**m) if isinstance(m, dict) else m for m in changes["magic_systems"] ] if "locations" in changes: from .models.bible import Location bible.locations = [Location(**loc) if isinstance(loc, dict) else loc for loc in changes["locations"]] elif section == "characters": from .models.bible import CharacterProfile if "characters" in changes: bible.characters = [ CharacterProfile(**c) if isinstance(c, dict) else c for c in changes["characters"] ] elif section == "structure": if "act_structure" in changes: bible.act_structure = changes["act_structure"] if "chapter_count" in changes: bible.chapter_count = changes["chapter_count"] if "plot_beats" in changes: from .models.bible import PlotBeat bible.plot_beats = [ PlotBeat(**b) if isinstance(b, dict) else b for b in changes["plot_beats"] ] elif section == "deaths": from .models.bible import DeathPlan if "deaths" in changes: bible.deaths = [DeathPlan(**d) if isinstance(d, dict) else d for d in changes["deaths"]] elif section == "gags": from .models.bible import RunningGagPlan if "running_gags" in changes: bible.running_gags = [ RunningGagPlan(**g) if isinstance(g, dict) else g for g in changes["running_gags"] ] elif section == "tone": if "tone_notes" in changes: bible.tone_notes = changes["tone_notes"] if "comparable_books" in changes: bible.comparable_books = changes["comparable_books"] - Helper that syncs bible characters, deaths, and gags into the project and continuity models, then saves.
def finalize_bible(bible: BookBible, project, continuity) -> None: if not project.name or project.name == "Untitled": project.name = bible.title or project.name if bible.genre and not project.genre: project.genre = bible.genre for char_profile in bible.characters: if not any(c.name == char_profile.name for c in project.characters): project.characters.append( Character( name=char_profile.name, role=char_profile.role, description=char_profile.backstory, voice_notes=char_profile.voice_notes, comedy_hook=char_profile.comedy_hook, ) ) continuity.living_characters.append( CharacterState(name=char_profile.name, status=CharacterStatus.ALIVE) ) for death_plan in bible.deaths: if not any(d.character == death_plan.character for d in project.death_schedule): project.death_schedule.append( DeathEntry( character=death_plan.character, chapter=death_plan.chapter, circumstances=death_plan.circumstances, death_style=death_plan.death_style, ) ) for gag_plan in bible.running_gags: if not any(g.name == gag_plan.name for g in project.running_gags): project.running_gags.append( RunningGag( name=gag_plan.name, owner=gag_plan.owner, setup_chapter=gag_plan.setup_chapter, description=gag_plan.description, escalation_pattern=gag_plan.escalation_pattern, ) ) if not project.chapters: for i in range(1, bible.chapter_count + 1): project.chapters.append( Chapter(num=i, title=f"Chapter {i}", target_words=5000, status=ChapterStatus.NOT_STARTED) ) project.save() continuity.save(project.base_path) - src/storywright_mcp/app.py:145-146 (schema)Type signature and docstring define the tool's input schema: section (str, default 'all') and changes (dict | None).
async def update_plan(section: str = "all", changes: dict | None = None) -> str: """Patch book_bible.json; may sync characters/deaths/gags into project."""