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>
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.
- 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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
- 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>
- Add sans-serif font for English left-pane (status, workflow sections)
- Shorten English workflow step descriptions
- Reduce English report title font-size from 36px to 28px
- Use sans-serif font for English titles, descriptions and navbar
- Shorten English hero text to avoid overflow
- Fix :global() scoped CSS issue that was setting root font-size to 3.5rem
- Use separate unscoped style block for html[lang] selectors
Background threads (graph building, simulation prep, report generation,
profile generation) now inherit the requesting user's locale preference.
Previously these fell back to 'zh' because Flask request context was
unavailable in spawned threads.
Ensure poster_type stays PascalCase English and stance stays English enum
values regardless of language setting. Only natural language fields follow
the user's language preference.
The language instruction was causing LLM to change entity/relation naming
conventions. Now explicitly enforce PascalCase/UPPER_SNAKE_CASE for technical
identifiers while only applying language preference to description fields.