What is Fabula?
Fabula is a bookkeeping system for stories. It tracks the state of your narrative—characters, locations, events, what each character knows, what the reader knows—and tells you when something doesn't add up.
Write a scene where two characters have a conversation? Fabula checks: are they in the same place? Do they know each other? Introduce a mysterious letter? Fabula remembers: that letter needs to be opened eventually, or you've got a loose thread.
The Human-AI-Algorithm Triad
Fabula acts as the "algorithm/bookkeeper" in a collaborative storytelling system:
| Role | Responsibility |
|---|---|
| Human | Creative direction, high-level plot decisions, aesthetic judgment |
| AI (LLM) | Prose generation, dialogue, scene details, creative suggestions |
| Fabula | State tracking, constraint validation, implication surfacing |
The AI generates, the human guides, and Fabula ensures nothing breaks.
Why Prolog?
Stories are fundamentally about relationships and rules:
- If character A knows a secret, and A tells B, then B knows the secret
- If the gun appears in Act 1, it must fire by Act 3 (Chekhov's constraint)
- If two characters are enemies, their dialogue should reflect tension
Prolog's logic programming paradigm naturally expresses these constraints. Fabula uses a metainterpreter pattern—Prolog reasoning about Prolog—to:
- Track narrative state as facts
- Express story rules as logical implications
- Query for violations and loose threads
- Surface consequences of plot decisions
Core Concepts
Story State
% Characters exist in locations
at(alice, library, chapter_1).
at(bob, garden, chapter_1).
% Characters possess items
has(alice, mysterious_letter).
% Knowledge tracking
knows(alice, secret_password).
knows_about(reader, mysterious_letter). % Reader has seen this
Narrative Operations
% Moving a character
move(Character, From, To, Chapter) :-
at(Character, From, Chapter),
retract(at(Character, From, Chapter)),
assert(at(Character, To, Chapter)).
% Conversation requires co-location
can_converse(A, B, Chapter) :-
at(A, Location, Chapter),
at(B, Location, Chapter),
A \= B.
Constraint Validation
% Chekhov's Gun: introduced items must be used
loose_thread(Item) :-
introduced(Item, Chapter),
\+ used(Item, _),
current_chapter(Current),
Current > Chapter + 2.
% Knowledge consistency
plot_hole(Character, Info) :-
uses_knowledge(Character, Info, Scene),
\+ knows(Character, Info, Scene).
Workflow
- Author writes scene (or AI generates draft)
- Scene is parsed into narrative operations
- Fabula validates operations against current state
- Violations surfaced → author fixes or acknowledges
- State updated → ready for next scene
Current Status
Fabula is in active development. Current focus:
- Core metainterpreter for state tracking
- Basic constraint library (co-location, knowledge, item tracking)
- Integration protocol for LLM-generated scenes
Related Research
This project emerged from experiments on procedural story generation, specifically investigating how constraints affect LLM creativity. See:
- Thematic Passphrases - How seeds influence story generation
- Why LLMs Name Characters "Jack" - Absorption points in narrative generation