Narrative Engine
Branching story graph engine with interpolation, effects, and traversal. A zero-runtime-dependency TypeScript library unified from three independently identical graph models in Forge, pseudogen, and gw Idea Evolver.
Overview
@ap/narrative-engine is a shared library that abstracts the directed graph model common to multiple Aloysius Productions apps. It provides the core primitives for building branching narratives: nodes, labeled edges (choices), context-driven interpolation, immutable effect processing, and graph traversal utilities.
The library was extracted after discovery that Quest-Forge, gw, and pseudogen had each independently invented the same graph structure. pseudogen had the richest implementation (effects, interpolation, caching) and served as the base. The API surface was generalized — template/templateAlt instead of codeFragment/codeTemplate — to be domain-agnostic: Tavern uses it for RPG dialogue, Forge uses it for interactive coding tutorials, Muse Studio uses it for creative story building.
Status
Phase: Complete (all 8 implementation phases) — staging evaluation Test coverage: >90%, 110 tests passing API stability: All public APIs marked stable Blockers: None — awaiting first consumer integration validation (Forge)
Tech Stack
| Technology | Version | Purpose |
|---|---|---|
| TypeScript | ^5.6.0 | Language — strict mode, ESM |
| Vitest | ^4.0.18 | Test runner |
| fast-check | ^4.x | Property-based testing (dev-only) |
Zero runtime dependencies. Same pattern as eliza-engine.
Key Features
- Story Graphs — Node-based directed graph structures with labeled edges (choices)
- Interpolation —
${var}template substitution with cache invalidation - Effects — Immutable context transforms (safe for undo/redo)
- Traversal — Cycle detection, unreachable node detection, branch/merge point finding
- Graph Builder — Typed helpers for assembling nodes, choices, and graphs immutably
- Session Serialization — Export/restore engine state (
toSession()/fromSession()) - Progress & Achievements — Optional session state for consumer tracking without external persistence
- Validation & QA Gate —
validate(),validateStrict(),analyze(),assertGraphSafe() - Telemetry Hooks — Runtime instrumentation callbacks for consumer observability
Consumer Integration Points
| App | Use Case | Status |
|---|---|---|
| Forge | Interactive coding tutorials | Planned |
| Tavern | RPG branching narratives | Planned |
| Muse Studio | Creative story building | Planned |
| Scribe | Collaborative storytelling | Future |
| Workshop | Code scaffolding narratives | Future |
Key Decisions
| Decision | Rationale |
|---|---|
| Unified three models into one | Quest-Forge, gw, pseudogen had structurally identical graph models — single API serves all consumers |
template/templateAlt naming | Domain-agnostic — not all consumers generate code |
| Zero runtime deps | Keep lightweight for embedding; same pattern as eliza-engine |
| Immutable effect processing | Context transforms return new objects — safe for undo/redo |
| Include graph traversal utilities | Cycle detection and validation needed by all consumers; prevents runtime errors from broken graphs |
| Add progress/achievement session state | Lightweight tracking for consumers without requiring external persistence |
| Pre-release checklist | Reproducible release process enforced before publishing |
Patterns Established
- Telemetry hooks — Runtime instrumentation callbacks (consumer observability without coupling)
- Metadata schema validation — Enforce allowed keys and depth to prevent unsafe drift
- Graph health reporting — Summarize errors/warnings/cycles/unreachable for CI gates and dashboards
- QA gate helper —
assertGraphSafe()enforces baseline graph safety; useful for CI and editors - Property-based tests — Randomized graph checks via fast-check to find edge cases early
- Consumer integration smoke test — End-to-end API usage verifying the public API contract
Lessons Learned
- Three apps independently inventing the same graph model validates the abstraction — extract shared models early
- pseudogen has the richest implementation and is the best source for a unified engine
- Tavern tests require Web Audio API shims in Node — use jsdom + AudioContext mocks for audio integrations
CI/CD
| Check | Status | Notes |
|---|---|---|
| CI workflow | Configured | Runs tests, typecheck, and QA gate on PRs |
| Security | security.yml | Hardened with sanitization and validation helpers |
| Release readiness | Pre-release checklist | Validates version + QA before tagging |
| Scale tests | Passing | Detects performance regressions on large graphs |
Commands
npm run build # tsc
npm run test # vitest run
npm run typecheck # tsc --noEmit
npm run qa-gate # tsc && node scripts/qa-gate.mjsSee Also
- Forge — first planned consumer; interactive coding tutorials
- Tavern — RPG companion app using narrative-engine for branching campaigns
- pseudogen — source of the richest graph implementation
- eliza-engine — sibling zero-deps shared library pattern
- gw — one of the three source models