"Raw text is just noise. Evolving story-graph memory is the signal."
Welcome to the future of developmental book editing. The Narrative Intelligence Engine is a computational developmental editor designed to read, analyze, and track the evolution of complex, multi-chapter novels. By representing narrative memory as a stateful, chronological knowledge graph, the engine knows everything important about Chapters 1β99 by the time it reaches Chapter 100βwithout re-reading a single line of text.
Unlike simple chat interfaces or generic vector retrieval tools that lose track of context over long texts, the Narrative Intelligence Engine splits Sensory Ingestion (observations) from Narrative Understanding (beliefs), feeding state updates into an editorial reasoning core.
π Raw Chapter Text (PDF, DOCX, TXT)
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββ
β SENSORY NLP PIPELINE β
β β’ spaCy: tokenization, syntax, SVO parsing β
β β’ GLiNER: zero-shot Named Entity tagging β
β β’ FastCoref: coreference resolution β
β β’ Dialogue: quote isolation & attribution β
βββββββββββββββββββββββββ¬βββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββ
β STRUCTURED EVIDENCE β
β ChapterData JSON (Observable Facts) β
βββββββββββββββββββββββββ¬βββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββ
β NARRATIVE STATE ENGINE β
β Processes evidence, determines delta, and β
β propagates transitions to narrative memory β
βββββββββββββββββββββββββ¬βββββββββββββββββββββββ
β
ββββββββββββββββ΄βββββββββββββββ
βΌ βΌ
βββββββββββββββββββ βββββββββββββββββββ
β STORY MEMORY β βEDITORIAL ENGINE β
β Characters β β 8 Inspectors β
β Relationships β β (Pacing, Arc, β
β World Lore β β Voice, Conflictβ
β Timeline β β Timeline, etc.)β
β Themes β β + β
β Promises β β LLM Critique β
ββββββββββ¬βββββββββ ββββββββββ¬βββββββββ
β β
βΌ βΌ
βββββββββββββββββββ βββββββββββββββββββ
β NARRATIVE GRAPH β βEDITORIAL REPORT β
β Vis.js HTML Web β βPlot inconsistenciesβ
β Interactive β β pacing & motivesβ
βββββββββββββββββββ βββββββββββββββββββ
Story elements are alive. We don't overwrite character details or plot lines; we model their evolution. Every character, relationship, and setting contains a versioned history of state transitions, supported by confidence scores, reasoning, and chapter evidence markers.
- Characters: Tracks dynamic goals, deep-seated fears, emotional states, physical traits, possessions, and story arc stages.
- Relationships: Records interactive events, mapping trust metrics and bidirectional stances (e.g. Rivals β Lovers β Nemeses).
- Promises & Mysteries: Monitors foreshadowing, setups, and open questions, throwing alerts if they remain unresolved near the climax.
Nine custom-tailored static inspectors scrutinize your story's data structure to flag plot holes:
- Arc Inspector: Evaluates character progression through structural beats (Introduction, Rising Action, Climax, Resolution).
- Pacing Inspector: Analyzes dialogue density, scene length, and action ratios.
- Voice Inspector: Tracks syntactical rhythm, average sentence lengths, and stylistic drift.
- Timeline Inspector: Detects temporal shifts, flashbacks, and chronological gaps.
- Spatiotemporal Inspector: Flags characters in two places at once or impossible travel times.
- Plus Scene, Conflict, Relationship, and Character Inspectors.
- Signal triage: Inspector output is grouped before anything reads it. Nine detectors emitting one finding per offending entity is the right granularity for a detector and the wrong one for a report β an early chapter-3 report was 81 findings of which 50 were the same note repeated once per entity.
src/review/signal_triage.pycollapses those into distinct signals with a count and exemplars, and deliberately does not let priority scale with repetition: fifty identical notes are one observation, usually an over-eager rule rather than fifty story problems. - LLM Critique: A fallback-resilient LLM reviewer (Gemini β Groq β Ollama, auto-failover) adds thematic evaluation, grounded in a token-budgeted
ContextRetrievercontext block rather than raw text alone. - LLM Synthesis: A second pass ranks the grouped signals and the critique's own findings together, verifies them against the chapter, merges duplicates, drops detector noise, and writes a prose developmental-editor letter plus 3β7 ranked
top_findingscarryingwhy_it_mattersand a concreterecommendation. This is what turns a flat list of detector output into a review. Reports also carrykey_eventsβ with a deterministic fallback derived from the curated timeline, so a failed or non-compliant LLM response can never silently ship a report with the chapter's beats missing. - ValidationEngine: Gates every LLM-authored proposal (new character, world item, relationship) against deterministic NLP evidence before it reaches state β rejects unsupported entities and flags field-level contradictions instead of silently trusting the LLM.
No more waiting on heavy models. The pipeline hashes chapter texts with SHA-256. If a chapter hasn't changed, cached evidence is returned instantlyβdropping processing times from 60β90 seconds to under 0.1 seconds!
Built completely with Python's standard library (urllib.request + json), the engine automatically auto-detects and prioritizes your available LLM backends:
- Gemini (
gemini-2.0-flash) - Groq (
openai/gpt-oss-120b) - Ollama (
llama3running locally)
Transform raw data into art. The visualizer compiles the NetworkX story relationships and outputs a standalone, interactive HTML file (narrative_graph.html) built with Vis.js.
- Drag, zoom, and dynamic physics layout.
- Color Coded: Blue for Characters, Green for Locations, Yellow for Events, Purple for Themes, Gray for Chapters.
- Interactive details pane updates on node selection.
-
Clone the repo and navigate to the project directory:
cd Narrative_Engine -
Spin up a virtual environment and activate it:
python -m venv venv # Windows: venv\Scripts\activate # Linux/macOS: source venv/bin/activate
-
Install requirements and download the base NLP model:
pip install -r requirements.txt python -m spacy download en_core_web_sm
-
Configure your environment (Optional for LLM critiques): Create a
.envfile in the root directory:GEMINI_API_KEY="your-gemini-api-key" # OR GROQ_API_KEY="your-groq-api-key"
Run the end-to-end processing pipeline over any raw text, DOCX, or PDF chapter:
python src/main.py --chapter path/to/chapter.txtGet a high-level summary of your evolving novel's graph statistics:
python src/main.py --statusGenerate the gorgeous network graph from your current memory:
python scripts/visualize_graph.pyOpen data/memory/narrative_graph.html in any browser to interact with the narrative network!
Narrative_Engine/
βββ src/
β βββ pipeline/ # NLP Sensory Pipeline (Parser, Cleaner, NER, Coref, Dialogue)
β βββ models/ # Core State & Evidence Dataclasses
β βββ memory/ # Stateful Memories (Character, Relationship, World, Theme, etc.)
β βββ engines/ # Reasoning Cores (Narrative State, Scene, Editorial, Graphs)
β βββ review/ # Rule-based Critique Inspectors
β βββ utils/ # Config & LLM Provider abstractions
βββ tests/ # 100% covered Test Suite
βββ config/ # YAML configurations
βββ data/
β βββ memory/ # Saved JSON states, reports, and interactive HTML files
β βββ cache/ # Cached NLP extraction packets
βββ scripts/ # Visualizer scripts & setup tools
The project has a robust testing suite running 93 unit and integration tests. Run them instantly:
pytestThe core architecture β deterministic NLP evidence β grounded LLM interpretation β validated state β editorial critique β is fully wired and tested end-to-end. What's still rough:
- Theme/mystery/symbol detection is hybrid: keyword-based by default, zero-shot when available (2026-08-15).
src/utils/zero_shot_classifier.pywraps atransformerszero-shot-classification pipeline (facebook/bart-large-mnli) that, when installed and reachable, batch-classifies sentences against theme/symbol/mystery/clue/revelation labels as a semantic signal alongside the existing keyword gates.transformers/torchare optional (commented out inrequirements.txt, ~1.6GB) β the engine falls back automatically and deterministically to the original keyword logic when they're absent or the model can't be reached, so nothing is required to run the core engine. - VADER sentiment and textstat readability are now live β
sentiment_compound(VADER) is computed per-scene and per-chapter alongside the existing keyword-based emotional tone label, andflesch_reading_ease/flesch_kincaid_grade(textstat) are computed in chapter style metrics. Dialogue attribution has real turn-taking inference (alternates between the two known speakers in a scene when a quote's speaker is otherwise unresolved) in addition to the speech-tag regex. Still missing: BookNLP, LanguageTool, and any DistilRoBERTa-style emotion classifier β those roles remain custom heuristics/regex, not the mature OSS libraries originally scoped. - Coreference now feeds character attribution directly. FastCoref's real mention spans and sentence spans are carried through
ChapterData(previously computed and discarded), and character trait/goal/fear/etc. extraction is attributed via a per-chapter sentenceβcharacter map built from literal name matches plus resolved coreference clusters (with LLM disambiguation fallback) β replacing the old unusedcoref_mapparameter. - LLM backend priority is Gemini β Groq β Ollama with automatic failover on error, but a Gemini project with an exhausted/zero quota will still burn ~60s retrying with exponential backoff before failing over β check quota status if chapter processing feels slow.
- Contextual lookback across chapter breaks (2026-08-16).
NarrativeStatenow carries the previous chapter's raw-text tail (previous_chapter_excerpt) forward, andContextRetrieversurfaces it as a fixed<PreviousChapterExcerpt>context tier β LLM extraction stages get direct continuity across a chapter break, not just structured state fields. - Not yet validated at real scale. Everything so far has run on a small number of chapters; confidence decay, dormancy tracking, and reconciliation logic are implemented but unverified across a 50-100 chapter novel.
- Web dashboard exists now, and has been exercised end-to-end with a real chapter upload (
api/FastAPI backend +frontend/React/TypeScript SPA) β browses every tracked collection (characters, relationships, world, themes/motifs, promises/mysteries/threats, conflicts/arcs, style/readability metrics), the timeline, editorial reports, an interactive force-directed Story Graph (canvas +d3-force, built fromnarrative_graph.json), and chapter ingestion with live job-status polling and job history β all backed by the canonicalnarrative_state.json/report/graph files rather than a separate database. EveryStateSnapshot'sevidence_idsresolve to real evidence text viaGET /api/evidence, expandable inline. Not yet load-tested at real novel scale. The Story Graph now also carries characterβworld and characterβtheme edges (2026-08-15/16, derived from chapter co-occurrence, tinted by connected node type) β world/theme nodes are no longer islands. Run withuvicorn api.main:app --port 8420(backend β--reload's file-watcher has been unreliable on Windows in testing; restart manually after backend edits) andnpm run devinfrontend/(Vite dev server, proxies/apito 8420).
Created with π for writers, editors, and computational narrative engineers.