Named after the Russian Formalist concept distinguishing fabula (chronological events) from syuzhet (how the story is told)
A browser-based control panel for multi-agent fiction writing with enforced information discipline.
LLMs are terrible at writing suspenseful fiction—but not for the reason you think.
The issue isn't prose quality, characterization, or plot structure. It's information economy.
LLMs are trained to be helpful, clear, and complete. They want to:
- Resolve ambiguity
- Answer questions
- Explain motivations
- Close narrative loops
Good fiction does the opposite. It:
- Maintains strategic ambiguity
- Delays answers
- Shows behavior without explaining it
- Keeps loops open until the right moment
Syuzhet provides a scaffolding system to enforce information discipline when using LLMs for fiction writing.
Visit the live demo or host index.html yourself.
Enter at least one API key on the welcome screen:
- Anthropic (Claude Opus/Sonnet/Haiku)
- OpenAI (GPT-5/o3/GPT-4.1)
- Kimi/Moonshot (Kimi K2 Turbo)
Go to the Bible tab and define:
- Objective reality (what's true)
- Disclosure schedule (when reader learns each fact)
- Character knowledge (who knows what)
Use the four specialized agents to plan, write, critique, and verify your chapters:
| Agent | Role | What They See |
|---|---|---|
| Architect | Plans information economy | Everything |
| Scribe | Writes prose from beats | Story bible, beats, chapters |
| Critic | Models reader experience | Only chapters (reads blind) |
| Keeper | Verifies information discipline | Everything |
Write chapters → Get critique → Revise → Verify → Repeat.
Switch between AI providers on the fly:
| Provider | Models |
|---|---|
| Anthropic | Claude Opus 4.5, Sonnet 4.5, Haiku 4.5 |
| OpenAI | GPT-5.2, o3, GPT-4.1, GPT-5 Mini |
| Moonshot | Kimi K2 Turbo |
Three visual themes for different writing contexts:
| Theme | Description |
|---|---|
| 🌙 Dark | Easy on the eyes for late-night sessions |
| ☀️ Light | Clean and bright |
| 📜 Paper | Warm sepia with serif fonts—like Scrivener |
The Critic cannot see the story bible. This is by design.
The Critic models what an actual reader experiences—they only know what's on the page. If the Critic can figure out your twist early, so can your readers.
All data stored in browser localStorage:
syuzhet_api_keys— Your API keys (per provider)syuzhet_selected_model— Currently selected modelsyuzhet_theme— Your theme preferencesyuzhet_chats— All conversation historysyuzhet_story_bible— Story bible YAMLsyuzhet_tension_curve— Tension curve YAMLsyuzhet_chapters— Chapter beats, drafts, feedback
Export/Import: Use Settings → Export Project Data to download a JSON backup.
| Layer | Description |
|---|---|
| Plot | What happens (events, actions, consequences) |
| Information Disclosure | What the reader learns, when, and how |
These are separate authorial decisions.
- A murder can happen in Chapter 1, but the reader might not learn who did it until Chapter 20
- Or the reader might know from page 1 while watching characters fumble toward truth (dramatic irony)
Most LLM prompts treat these as one thing. They're not.
At any moment in a story, there are four distinct information layers:
┌─────────────────────────────────────────────────────────┐
│ OBJECTIVE REALITY │
│ Everything that is "true" in the story world │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ CHARACTER KNOWLEDGE │
│ What each character knows/believes (often wrong) │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ READER KNOWLEDGE │
│ What's been disclosed to the reader so far │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ READER SUSPICION │
│ What the reader infers from patterns/hints │
└─────────────────────────────────────────────────────────┘
The gaps between these layers are the story's engine:
- Suspense = gap between reader suspicion and reader knowledge
- Dramatic irony = gap between reader knowledge and character knowledge
- Surprise = gap between reader suspicion and objective reality
LLMs collapse these layers because they're trained to be clear. Clarity is the enemy of suspense.
Sees: Everything
Creates: Story bible, disclosure schedules, tension curves, beat sheets
The Architect plans what information exists and when readers learn it. They design the information economy before any prose is written.
Use the Architect to:
- Extract objective reality from your outline/draft
- Plan disclosure arcs for each secret
- Create beat sheets with explicit WITHHELD tags
- Design tension curves across chapters
Sees: Story bible, beats, feedback, chapters
Creates: Chapter prose, revisions
The Scribe writes prose from beat sheets. They know the full story but are constrained by what each beat allows them to reveal.
Key rules the Scribe follows:
- NEVER reveal anything marked WITHHELD in the beat sheet
- NEVER have characters explain motivations unless the beat specifies
- End scenes on questions, not answers
- Show behavior AS IF character knows secrets, without stating them
Sees: Only chapters (NO story bible access)
Creates: Reader state analysis, tension scores, craft notes
The Critic models what a first-time reader experiences. They read blind—just like your audience will.
The Critic evaluates through three lenses:
-
Reader Simulation
- What does the reader NOW believe to be true?
- What do they SUSPECT but not know?
- What questions are they actively holding?
- Where was curiosity killed by over-explanation?
-
Tension Assessment
- Does this chapter hit its target tension?
- Where are stakes deflated unnecessarily?
- Are there micro-tensions within quiet scenes?
-
Craft Critique
- Clichés and weak phrases
- Telling instead of showing
- Overwriting
- Strengths to preserve
Sees: Everything
Creates: Pass/fail verification, leakage reports
The Keeper is the final gate. Nothing ships without their clearance.
The Keeper checks:
- Information Discipline — Is any fact revealed before its scheduled chapter?
- Revision Integrity — Did the Scribe honor preserve markers? Any new leakage?
The Keeper does NOT suggest fixes—only pass/fail with reasons.
Use YAML in the Bible tab. Here's the structure:
# ============================================
# OBJECTIVE REALITY
# Everything that is TRUE in the story world
# ============================================
objective_reality:
- id: killer_identity
fact: "Marcus Webb killed Elena Reeves"
when_happened: "Three months before story opens"
method: "Pushed her from lighthouse observation deck"
motive_true: "Elena discovered Marcus embezzled $2M"
- id: sibling_secret
fact: "Marcus and Elena are half-siblings"
when_happened: "Always true, discovered age 15"
known_by: [marcus]
# ============================================
# DISCLOSURE SCHEDULE
# When reader learns/suspects each fact
# ============================================
disclosure_schedule:
- fact_id: killer_identity
hinted_at: [3, 7, 11] # Breadcrumbs
reader_suspects: 12 # Should start suspecting
reader_fairly_certain: 16 # Building conviction
confirmed: 18 # Explicit reveal
confirmation_method: "Witness testimony"
- fact_id: sibling_secret
hinted_at: [7] # "Same gray-green eyes"
confirmed: 17
confirmation_method: "Old photograph with inscription"
# ============================================
# CHARACTER KNOWLEDGE
# What each character knows/believes
# ============================================
character_knowledge:
marcus:
knows:
- "He killed Elena"
- "They are half-siblings"
- "He forged the suicide note"
believes_falsely:
- "No one saw him that night"
arc:
- chapter: 15
learns: "Investigation focusing on him"
sarah:
knows:
- "Elena's death was ruled suicide"
suspects:
- "Something doesn't add up"
arc:
- chapter: 8
learns: "Marcus was at lighthouse that night"
# ============================================
# WITHHELD RULES
# Explicit constraints
# ============================================
withheld_until_scheduled:
- fact: "Marcus killed Elena"
forbidden_before_ch_18:
- "Character stating it directly"
- "Narrator confirming it"
- "Undeniable physical proof"
allowed_before:
- "Suspicious behavior"
- "Guilty body language"
- "Dramatic irony via Marcus POV"
- "Other characters suspecting"Define target tension levels (1-10) in the Bible tab under Tension Curve:
# Tension Scale:
# 1-3: Low (setup, breathing room, character moments)
# 4-6: Medium (investigation, complications, rising action)
# 7-8: High (revelations, confrontations, turning points)
# 9-10: Peak (climax, life-or-death, major reveals)
chapters:
1:
target: 4
type: "Hook, establish normal world"
end_on: "First hint something is wrong"
2:
target: 3
type: "Deepen character, plant seeds"
end_on: "Quiet unease"
3:
target: 5
type: "First complication"
end_on: "Question that demands answer"
7:
target: 6
type: "Ominous behavior, psychological unease"
micro_tensions:
- "Why is Marcus burning the photograph?"
- "What will happen if Sarah discovers it?"
end_on: "Image - photo disappears into ash"
12:
target: 7
type: "Reader should suspect Marcus"
end_on: "Evidence pointing at Marcus"
18:
target: 9
type: "Killer revealed"
end_on: "Confirmation + new danger"Create beat sheets for each chapter in the Chapters tab:
chapter: 7
title: "The Burning"
pov: "Marcus (close third)"
target_tension: 6
# ============================================
# INFORMATION STATE FOR THIS CHAPTER
# ============================================
information_state:
reader_learns:
- "Marcus has childhood photograph with Elena"
- "He destroys it in secret"
reader_suspects:
- "Marcus is hiding something about their relationship"
- "He may have been involved in Elena's death"
withheld: # CRITICAL - Scribe must not reveal these
- "That they're siblings (scheduled ch 17)"
- "That Marcus killed Elena (scheduled ch 18)"
- "Any explicit guilty thoughts"
# ============================================
# BEATS
# ============================================
beats:
- beat: 1
description: "Marcus retrieves hidden box from closet, 3 AM"
information_function:
reveals: "Marcus has kept something secret"
withholds: "What else is in the box"
hints_at: "He's been protecting this secret for years"
pacing: "Slow, building tension"
- beat: 2
description: "Opens box, finds old photograph"
information_function:
reveals: "Photo shows two children with similar features"
withholds: "Their relationship"
hints_at: "Same gray-green eyes, same half-smile"
end_beat_on: "The photograph - holding, not explaining"
- beat: 3
description: "Burns the photograph in kitchen sink"
information_function:
reveals: "Marcus needs to destroy this evidence"
withholds: "Why this matters"
execution_notes:
- "Physical details: match flare, edges curl black"
- "No internal monologue about guilt"
- "Just the action and its weight"
end_beat_on: "Image - children disappear into ash"
chapter_ending:
type: "Ominous image"
pull_forward: "What is Marcus hiding? What else was in that box?"- Define objective reality — What's actually true in your story?
- Create disclosure schedule — When does the reader learn each fact?
- Map character knowledge — Who knows what? Who's wrong about what?
- Set tension curve — Target tension for each chapter
- Write beat sheets — Plan each chapter with explicit WITHHELD tags
- Review beat sheet — Understand what's allowed and forbidden
- Write prose — Follow the beats, honor the constraints
- Focus on craft — Show don't tell, behavior over explanation
- Reader simulation — What does the reader know/suspect now?
- Tension assessment — Did we hit the target? Where did it sag?
- Craft notes — What's working? What needs revision?
- Apply feedback — In priority order
- Preserve strengths — Don't lose what's working
- Fix leakage — Remove premature revelations
- Information audit — Any facts revealed too early?
- Revision check — Were preserve markers honored?
- Pass/fail — If fail, back to Scribe with specific flags
- Target tension: 6/10 (medium-high, ominous)
- POV: Marcus (knows he killed Elena, reader doesn't)
- Plot: Marcus burns childhood photograph
- Goals: Reader suspects hiding something, does NOT learn he's killer or sibling
Marcus's hands shook as he turned on the kitchen faucet. The
match flared in the dark.
The photograph caught quickly, edges curling black. The two
children—those same gray-green eyes, that same half-smile—
disappeared into ash.Why this works:
- Shows Marcus destroying evidence (action)
- Doesn't explain why (withheld)
- Plants breadcrumb about similarity ("same eyes") without stating sibling connection
- Creates ominous atmosphere (tension target: 6)
- Ends on image, not explanation
Marcus burned the photo of him and his half-sister Elena.
If Sarah found it, she'd know they were related, which would
expose his embezzlement motive and prove he'd killed her.Why this fails:
- States sibling connection (withheld until ch 17)
- States he killed her (withheld until ch 18)
- Explains motivation (over-clarification)
- No mystery, no suspense
- Reader knows everything, nothing left to discover
# Clone or fork the repo
git clone https://github.com/mmulqu/Syuzhet.git
cd Syuzhet
# The index.html is standalone - just deploy it
# GitHub Pages: Settings → Pages → Deploy from root# Just open the file - no build step required
open index.html
# Or use any static server
python -m http.server 8000
npx serve .Add models — Edit the MODELS object:
'new-model-id': { provider: 'openai', name: 'Display Name', tier: 'balanced' }Add providers — Add to PROVIDERS and create a callNewProvider() function following existing patterns.
Adjust themes — Modify CSS variables in the :root, [data-theme="light"], and [data-theme="sepia"] blocks.
The app calls APIs directly from your browser:
- Anthropic: Uses
anthropic-dangerous-direct-browser-accessheader - OpenAI/Moonshot: Standard CORS-enabled endpoints
- Max tokens: 64000 (you only pay for actual generation)
- API keys stored only in your browser's localStorage
- Keys sent only to their respective API endpoints
- No backend, no analytics, no tracking
- Each visitor's data is completely isolated
Each agent receives different context:
// Architect, Scribe, Keeper: Full context
if (agent.contextAccess.includes('story_bible')) {
context += storyBible;
}
// Critic: NO story bible - reads blind like a real reader
// Only sees: chaptersWhile examples use mystery/thriller, this architecture applies to any genre where information control matters:
| Genre | Core Mechanic | Key Technique |
|---|---|---|
| Mystery | Withhold whodunit until climax | Plant clues without confirming |
| Thriller | Withhold extent of danger | Reveal threat incrementally |
| Romance | Withhold whether couple gets together | Show desire while maintaining facades |
| Horror | Withhold nature of threat | Wrongfoot reader expectations |
| Literary | Withhold character's true nature | Unreliable narration, gradual backstory |
The author controls:
- What the reader knows
- When they learn it
- How they learn it (directly/indirectly, reliably/unreliably)
Suspense = uncertainty about important outcome
- Reader knows too much too soon → No suspense
- Reader knows too little → Confusion, detachment
- Sweet spot: Reader suspects but can't confirm
LLMs are aligned for helpfulness, clarity, completeness, directness.
Fiction requires strategic withholding, ambiguity, incompleteness, indirection.
Syuzhet re-aligns LLMs through:
- Explicit constraints (withheld lists in beat sheets)
- Architectural separation (plot ≠ disclosure)
- Blind criticism (Critic can't see story bible)
- Multi-agent specialization (each agent has one job)
- Russian Formalists (Shklovsky, Propp): Fabula vs. Syuzhet
- Narratology (Genette): Story vs. Discourse
- Cognitive narratology (Herman): Reader mental models
- Information theory (Shannon): Uncertainty and entropy
- Four-agent architecture with context isolation
- Multi-provider API support (Anthropic, OpenAI, Moonshot)
- Story Bible and Tension Curve editors
- Chapter management (beats, drafts, feedback)
- Theme system (dark, light, paper)
- Persistent localStorage
- Export/import project data
- Chapter summaries for scaling (avoid dumping all chapters into context)
- Automated leakage detection (regex + LLM-based)
- Tension curve visualization
- Import existing manuscript for "archaeological mode"
- Multi-project support
- Collaborative editing (CRDTs)
This system is a proof-of-concept. Ways to contribute:
- Add example stories — Different genres, structures, traditions
- Improve the UI — Better chapter navigation, visualization
- Build verification tools — Automated leakage detection
- Research extensions — Empirical testing with readers, cross-genre analysis
MIT License
"The art of storytelling is not just about what you tell, but what you withhold—and when you finally reveal it."