feat: Narrative Layer — prose generation, characters, God Mode, world state#573
Open
anadoris007 wants to merge 25 commits into
Open
feat: Narrative Layer — prose generation, characters, God Mode, world state#573anadoris007 wants to merge 25 commits into
anadoris007 wants to merge 25 commits into
Conversation
- docs/superpowers/specs/2026-03-26-narrative-layer-design.md - docs/superpowers/plans/2026-03-26-narrative-layer-foundation.md Spec extends MiroFish into a creative storytelling platform via a new narrative layer over the existing OASIS simulation engine. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New narrative package with action_mapper module that maps the 13 OASIS action types (CREATE_POST, LIKE_POST, REPOST, etc.) to narrative verbs and interpretations used when generating story prose. Tests: 4/4 passing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three JSON files per simulation under narrative/ subdir: - story_beats.json: chronological story passages - translator_state.json: per-platform file offsets - characters.json: extended character profiles Tests: 4/4 passing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Character profiles now track a six-dimension emotional state (anger, fear, joy, sadness, trust, surprise) that evolves based on actions taken. Initial deltas for all 13 OASIS actions chosen as a balanced baseline (see module docstring for tuning guidance). Tests: 5/5 passing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reads one round's worth of agent actions from the OASIS log file, tracking file offset so callers can resume across translation calls. Handles missing files, malformed JSON lines, and non-target rounds gracefully. Tests: 3/3 passing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Module-level call_llm() wrapper (patchable by tests) drives PROSE_PROMPT_TEMPLATE rendering with character summaries, actions, previous beats, and user-selected tone. Prompt tuned for punchy, cinematic, dialogue-heavy voice. Tests: 5/5 passing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
translate_round() ties together: - reading the round's actions from actions.jsonl - generating prose via the LLM - updating per-character emotional state - persisting the beat, characters, and file offset Full test suite now at 19/19 passing across action mapper, character engine, story store, and translator. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Five endpoints under /api/narrative/*: - GET /story/<sim_id> — full story so far - GET /story/<sim_id>/round/<num> — single round - POST /translate — translate a round on demand - GET /characters/<sim_id> — roster with emotional state - POST /characters/<sim_id>/init — bootstrap from OASIS profiles Blueprint registered alongside existing graph/simulation/report blueprints following the established pattern. Smoke-tested via Flask test client. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Five named exports covering narrative endpoints, following the existing pattern in frontend/src/api/simulation.js (service + requestWithRetry + named exports). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New frontend surface for reading generated stories: - StoryBeat.vue: renders a round's prose with character attribution - CharacterCard.vue: compact roster card with animated emotion bars - StoryTimelineView.vue: reading view with Init Characters, Refresh, Translate Next Round, and a tone input - Route: /story/:simulationId Recently-active characters are highlighted in the roster. Styling uses the project's cream/brass palette for consistency with existing views. Frontend builds cleanly (vite build). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Full-pipeline test: fake simulation dir → actions.jsonl → two translate_round calls → assertions on beat persistence, character evolution, and translator offset advancement. Final test suite: 20/20 passing across action mapper, character engine, story store, translator (read + prose + orchestration), and E2E. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Minimal scope: 3 God Mode interventions (inject event, modify emotion, kill character) + 3 World State primitives (locations, rules, event log). File-based only — no OASIS simulation changes for v1. Design trade-off: v1 God Mode affects the prose layer, not the simulation loop. Agents don't "see" injected events; only the narrator does. This ships faster and fits the creative-authoring use case. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Addresses 3 critical + 6 major + 7 minor issues from spec review: - §5.0 new: specifies translator loads world_state, id/name keying conventions, brace-escape for user text in prompt - §4.2/§4.3: god_mode interventions audit-log to event_log - §4.3: kill auto-appends death event for narrative visibility - §4.4: documents concurrency limitation - §6.4/§6.5: navigation on all 3 views, typed-name kill confirmation - §10: expanded non-goals (no-delete, unbounded log, global enforcement) - §8: adds explicit prompt-inclusion regression test Spec review: Approved. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
10-task TDD plan covering: - WorldStateStore (rules, locations, event log) - Character status field - 3 God Mode handlers (inject_event, modify_emotion, kill_character) - Translator prompt extension + dead filter + brace escape - E2E integration tests for injection and kill - 6 API endpoints with validation - 2 Vue views with shared nav + typed-name kill confirmation Includes 2 marked user-contribution points: - EVENT_ENFORCEMENT_STRENGTH (soft/medium/hard) - Location schema fields (minimal vs atmosphere vs time_of_day) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- PROSE_PROMPT_TEMPLATE extended with world_rules, world_events,
world_locations, and event_enforcement substitution fields
- EVENT_ENFORCEMENT_STRENGTH set to "hard" — opening line MUST
reference the most recent world event (aligns with existing
punchy, cinematic voice)
- Character summaries now resolve location id → name for prompts
- translate_round loads world_state and filters dead characters
from both the roster and the action list before prose generation
- User-supplied strings (rules, events, locations) brace-escaped
before str.format() to prevent KeyError on stray { or }
Tests: 36/36 passing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When Marcus (the only round-2 actor) was killed, generate_prose short-circuited on empty actions without calling the LLM, so mock_llm.call_args_list only had one entry. Added Elena as a second round-2 actor to exercise the filter with a live participant.
Six new endpoints under /api/narrative/*: - GET /world/<sim_id> — full world state - POST /world/<sim_id>/rules — replace rules list - POST /world/<sim_id>/locations — upsert location - POST /godmode/<sim_id>/inject-event — inject world event - POST /godmode/<sim_id>/modify-emotion — overwrite emotions - POST /godmode/<sim_id>/kill — kill character Validation: - 400 on missing required fields (description, character_id, rules) - 400 on invalid round (must be non-negative int or null) - 404 on character not found (from ValueError in handlers) Smoke-tested via Flask test client — all 11 response codes correct. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- New Vue views: GodModeView (inject event, modify emotions with preloaded current values, kill character with typed-name confirmation) and WorldBuilderView (rules editor, locations with cinematic atmosphere field, event log viewer) - Shared sim-nav strip across Story/GodMode/World views - Location schema extended with optional atmosphere field — a short mood phrase that anchors the opening visual of every scene set there - Translator's _format_world_locations surfaces atmosphere to the LLM prompt so the field actually influences generation - Routes added for /godmode/:simId and /world/:simId Tests: 39/39 passing (added test_location_atmosphere_surfaces_in_prompt). Frontend builds clean. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a Narrative Layer on top of the existing OASIS simulation: translates agent actions into story prose, tracks extended character state, adds author-controlled intervention (God Mode), and grounds scenes in a persistent world state. Builds toward making MiroFish a creative-writing platform without modifying the OASIS simulation core.
Two sub-features, shipped as independent commits on one branch:
1. Narrative Layer foundation (commits
c5cc599→d651cb8)action_mapper(13 OASIS actions → narrative verbs),character_engine(6-dim emotional state + per-action deltas),story_store(file-based persistence),narrative_translator(readsactions.jsonl, generates prose via existing LLM client)/api/narrative/*— full story, per-round story, translate, characters, init charactersStoryTimelineView.vue+StoryBeat.vue+CharacterCard.vueon/story/:simId2. God Mode + World State v1 (commits
7d292e2→4846897)inject_event,modify_emotion,kill_character— all audit-logged toworld_state.event_logatmospherefield), event log — stored innarrative/world_state.json/api/narrative/world/*and/api/narrative/godmode/*GodModeView.vue(with typed-name kill confirmation + preloaded emotion sliders),WorldBuilderView.vue, sharedsim-navacross all three viewsWhat's deferred (explicit non-goals)
Mid-sim OASIS prompt injection, timeline branching, resurrection, time skip, factions, resources, EPUB/DOCX input, export studio.
Test plan
cd backend && uv run pytest tests/— 39/39 passing (action mapper, character engine, story store, translator, god mode, world state, e2e pipeline, event injection integration, kill filter integration)cd frontend && npm run build— clean build, no errorstest_client, correct status codes (400/404/200)docs/superpowers/for reviewArchitecture docs
docs/superpowers/specs/2026-03-26-narrative-layer-design.md(532 lines, reviewed + approved)docs/superpowers/specs/2026-04-20-godmode-worldstate-design.md(372 lines, reviewed + approved)docs/superpowers/plans/2026-03-26-narrative-layer-foundation.md(12 tasks)docs/superpowers/plans/2026-04-20-godmode-worldstate.md(10 tasks)🤖 Generated with Claude Code