-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Multi-Guide Narrative Systems: Architecture Summary
Core Insight: Guide as Orthogonal Role
Your original framework had four roles:
- Developer - builds the system
- Author - creates fabula content
- Guide - advances cursor(s) through the graph
- Reader - consumes journal output
Key realization: Guide ≠ Reader and Guide ≠ Author
Traditional novel: Author = Guide (predetermined path)
CYOA: Reader = Guide (choose your own path)
Procedural game: Developer = Guide (via rules/algorithms)
Multi-lane StoryTangl: Guide = Distributed (multiple actors/systems)
Provisioning at a Distance
The fundamental architectural primitive:
# Traditional single-cursor planning:
frontier = get_nodes_reachable_from(cursor)
provision(frontier)
# Multi-guide "provisioning at a distance":
my_frontier = get_nodes_reachable_from(my_cursor)
coupled_frontiers = get_frontiers_from_coupled_lanes()
shared_concepts = get_nodes_with_shared_concepts()
expected_intersections = predict_convergence_points()
provision_all([
my_frontier,
coupled_frontiers,
shared_concepts,
expected_intersections,
])Planning doesn't care about cursor ownership. It provisions based on multiple distance metrics:
- Structural (reachable edges)
- Conceptual (shared tags/concepts)
- Temporal (expected to be reached soon)
- Causal (coupled by authoring rules)
The Guide Interface
class Guide(ABC):
"""
Abstract interface for anything that advances a cursor.
VM doesn't care if it's human, AI, scheduled, etc.
"""
@abstractmethod
async def select_choice(
self,
choices: list[Choice],
context: NavigationContext,
) -> UUID:
"""Pick which choice to execute."""
passGuide Implementations
HumanGuide: Waits for player input via Discord/REST/CLI
AIGuide: Uses LLM to make narrative decisions based on optimization goals
personality="cautious"- avoid riskspersonality="dramatic"- maximize tensionpersonality="optimal"- minimax strategy
ScheduledGuide: Follows predetermined script or timeline
VotingGuide: Aggregates multiple influences (crowd-driven)
CoupledGuide: Decides based on other lanes' state
ReplayGuide: Follows recorded choices from prior playthrough
The VM doesn't care. All guides just call:
orchestrator.execute(
"RuntimeController.resolve_choice",
user_id=lane_id,
choice_id=choice_id,
)Multi-Lane Narrative Structure
The Heist Example
lanes:
- id: mastermind_lane
guide: AIGuide(personality="methodical")
visibility: [high_level_plan, relationship_drama]
- id: safecracker_lane
guide: HumanGuide() or AIGuide(personality="anxious")
visibility: [technical_details, hand_injury]
- id: lookout_lane
guide: AIGuide(personality="unreliable_drunk")
visibility: [guard_schedules, personal_stress]
convergence_scenes:
- id: the_heist
participants: [all_lanes]
requirements: compound_across_all_lanesEach lane accumulates rich state independently:
- Mastermind deals with girlfriend drama → distracted during heist
- Safecracker injures fingers with firecrackers → can't feel tumblers
- Lookout gets drunk to cope with stress → unavailable, triggers backup
At convergence: All accumulated state combines to create compound dramatic situation
Cross-Lane Echoes
# Events in one lane echo into others:
echo_rules:
- source: mastermind_lane
event: {type: "high_stress"}
observers: [safecracker_lane]
effect:
fragment: "Boss sent terse text. Something's wrong."
modifier: {stress: +1}Lanes aren't isolated until convergence - they leak information creating cascading effects.
Discord as Presentation Layer
Persistent Narrative World
Server: "The Heist Chronicles"
#mastermind-perspective
└─ AI posts updates every 6 hours
└─ Humans react/suggest
└─ Story unfolds over days
#safecracker-perspective
└─ Different AI, different schedule (3 hours)
└─ Different personality (accepts suggestions)
#lookout-perspective
└─ Third AI, unreliable schedule
└─ Sometimes misses updates (drunk)
#convergence-events
└─ When lanes sync, major scenes post here
Key insight: Discord handles the temporal coordination and human interface. The narrative engine runs in backend, Discord is just a thin adapter.
Human Influence Mechanics
Suggestion System: Humans suggest, AI considers
!suggest apologize_to_girlfriend (5 votes)
AI: "I see the suggestions, but my character would ignore her..."
Vote Override: Critical moments allow community override
Temporary Takeover: Human players can request direct control
!takeover safecracker 1hour
The guide role is fluid - can transfer between AI and human dynamically.
The Tic-Tac-Toe Book Connection
Physical book that plays tic-tac-toe:
- Every game state = one page (~5,478 pages)
- Reader chooses X moves → links to page
- Book plays optimal O → links to next page
- Shared guide role between reader and book
This proved the concept works - fully materialized decision tree with distributed guidance IS compelling.
Your epub export script does the same:
# Materialize graph with guide (any guide)
materialized_graph = explore_with_guide(world, guide=DFS)
# Export is trivial once materialized
markdown = render_to_md(materialized_graph)
epub = convert_with_pandoc(markdown)Guide is just a graph materialization strategy.
Why This Architecture Works
Your phase bus already supports this:
VALIDATE → Check if choice valid
PLANNING → Provision at distance (all coupled lanes)
PREREQS → Auto-redirects
UPDATE → Apply effects
JOURNAL → Generate fragments (perspective-specific)
FINALIZE → Provision coupled content for other lanes
POSTREQS → Trigger consequences
The VM doesn't care who advanced the cursor. It just:
- Runs phases deterministically
- Provisions based on requirements
- Emits journal fragments
- Updates graph state
Applications
Solo Play with AI Supporting Cast
Human plays detective, AIs play suspects with hidden goals
Perspective Swapping
First playthrough as mastermind, replay as safecracker seeing same events from different angle
Research Tool
Run 1000 simulations with different AI personalities, analyze emergent narratives
Persistent World
Story unfolds 24/7 on Discord, humans drop in/out, AIs keep it running
Adaptive Difficulty
AI opponents with different strategies (easy/medium/hard) all from same fabula
Collaborative Authoring
Multiple humans vote on collective lane progression
The Thin Discord Adapter
class StoryTanglDiscordBot:
"""
Thin presentation layer.
All logic in backend orchestrator.
"""
async def on_message(self, message):
# Route human input to appropriate lane
lane = self.get_player_lane(message.author.id)
action = self.parse_action(message.content)
# Backend does all the work
result = await orchestrator.execute(
"LaneController.resolve_lane_action",
lane_id=lane.lane_id,
action_id=action.uid,
)
# Just format and post
await message.author.send(format_journal(result))Discord only handles:
- Message routing
- Human input parsing
- Fragment formatting
- Channel management
Backend handles:
- All narrative logic
- AI guide decisions
- Cross-lane coupling
- Convergence planning
- State management
Key Architectural Wins
- Guide abstraction is correct - DFS/human/AI/scheduled all produce valid traversals
- Provisioning at distance is correct - same planning system, different scope
- Fabula/discourse separation is correct - same graph exports to any platform
- Event sourcing is correct - can replay/analyze/debug any traversal
- No new architecture needed - existing primitives compose perfectly
What Makes This Novel
Not "multiplayer coordination" (solved problem).
But: Parallel narratives with authored coupling that interfere with each other
- Each lane accumulates rich independent state
- Lanes observe/affect each other through coupling rules
- Convergence creates compound dramatic situations
- Guide role is distributed and fluid
- Same fabula, multiple perspectives, emergent understanding
Computational narratology for entangled multi-POV stories.