Local-first long-form novel operating system.
Write in Markdown. The system maintains narrative consistency.
OpenNovel is a CLI-driven narrative operating system for long-form fiction. It is not a "one-click novel generator" — it is a collaborative writing environment where the author controls the story while AI handles the mechanical complexity of state tracking, consistency verification, and iterative refinement.
The system is organized around three decoupled layers:
- Human Layer — Pure Markdown files (canon, characters, drafts). Editable in any text editor, trackable by git, openable in Obsidian.
- Machine Shadow — Structured state extracted by AI: YAML frontmatter, SQLite event ledger, and file-level snapshots.
- Semantic Layer — LlamaIndex-based vector retrieval for contextual memory (BGE-M3 optional).
- Four-Agent Autonomous Pipeline — Writer (planning + creation + revision), Critic (five-dimension scoring + anchored feedback), Manager (state extraction + event recording), Director (global narrative analysis + scheduling proposals). Full pipeline runs on a single command.
- Agent Autonomy — Writer can proactively query missing information mid-creation via tool-calling protocol. SafetyFence constrains recursion depth, token budget, and timeout.
- Canon Integrity Checking — Rule-based validation against world-building documents. Detects violations of established setting rules without LLM dependency.
- Causal Event Graph — NetworkX-based directed acyclic graph of narrative events. Supports path analysis, centrality computation, upstream/downstream causal tracing.
- Automatic Foreshadowing Tracking — Director detects planted setups, tracks their progression, and identifies resolution points automatically every 3-5 chapters via causal chain analysis.
novel foreshadowfor manual override. - Auto-Generated Timeline & Summaries — Chapter summaries written on commit, event timeline converted from EventStore SQL at zero token cost. Both autonomous and interactive flows emit them automatically.
- Blind Mutation — Key chapters generate multiple structural directions via orthogonal mutation dimensions (narrative structure, point of view, causality, thematic arc). Corrective mode targets weak dimensions from prior evaluation.
- Stage Model Routing — Different LLM models per writing stage: cheap model for planning, flagship model for creation, premium model for revision.
- Model-Agnostic LLM Bus — LiteLLM integration supports any provider (OpenAI, Anthropic, DeepSeek, Ollama, local models). Each agent can be independently configured.
- Three-Layer Model Fallback — Agent-level model in novel.yaml, project-level model, global default in
.opennovel.yaml, hardcoded default. No repeated configuration needed. - Human-in-the-Loop — AI proposes, human approves. Every state change goes through
novel commitwith diff review. Full rollback support. - MCP Server — Four tools exposed via Model Context Protocol for Claude Code and other MCP clients.
git clone https://github.com/Yaemikoreal/OpenNovel.git
cd OpenNovel
pip install -e ".[dev]"Set your LLM provider key as an environment variable:
export DEEPSEEK_API_KEY="sk-xxxx" # DeepSeek
export OPENAI_API_KEY="sk-xxxx" # OpenAI
export ANTHROPIC_API_KEY="sk-ant-xxxx" # Anthropic# Create project in workspace (novels/<name>/)
novel init my-novel
# Or create at specific path
novel init .The workspace is managed by .opennovel.yaml at the project root. Default model is deepseek/deepseek-v4-flash.
# Edit characters, world rules, and outline in your editor
# Then start AI-assisted writing:
novel write novels/my-novel/draft/ch_001.md
# Store inspirations:
novel stash "A sentence fragment" --tag mood
# Review and commit state changes:
novel commit novels/my-novel/draft/ch_001.mdThis is the primary workflow. Prepare your project, then execute:
novel auto novels/my-novelThe system processes all chapters sequentially through the Agent pipeline. See the Autonomous Writing section for details.
The novel auto command orchestrates a four-agent pipeline that generates an entire novel from your outline, character files, and world rules.
┌─────────────────────────────────────────────────────────┐
│ Chapter Loop │
├─────────────────────────────────────────────────────────┤
│ Writer.think() → structured outline with scenes │
│ ↓ │
│ Knowledge Gap Detection → ToolRegistry query │
│ ↓ │
│ Writer.write() / write_with_autonomy() │
│ (mid-write tool calls via ##TOOL_CALL## protocol) │
│ ↓ │
│ Critic.evaluate() → five-dimension score (0-100) │
│ ↓ │
│ if score < 80: │
│ Writer.hot_fix() (targeted paragraph repair) │
│ or Writer.revise() (full chapter rewrite) │
│ → re-evaluate (max 5 retries) │
│ ↓ │
│ Manager.update() → character state + events │
│ ↓ │
│ Snapshot → Diff Check → chapter written │
│ ↓ │
│ Director.analyze() → strategy for next chapter │
└─────────────────────────────────────────────────────────┘
Critic evaluates each chapter across five dimensions, each scored 0-20:
| Dimension | Focus |
|---|---|
| Writing Quality | Sentence fluency, vocabulary, sensory detail |
| Plot Logic | Causal coherence, pacing, payoff setup |
| Character Consistency | Motivation, voice, emotional arc alignment |
| Rhythm Control | Scene length variation, tension modulation |
| Emotional Expression | Subtext, atmospheric resonance, reader impact |
When enabled, Writer can detect knowledge gaps during creation and autonomously query information sources. The protocol is transparent:
- Writer's prompt includes tool-calling instructions.
- If the LLM needs additional information, it emits a
##TOOL_CALL##marker with the query. - The system intercepts the marker, executes the query through ToolRegistry, injects results, and continues the generation loop.
- SafetyFence enforces recursion depth, token budget, and timeout constraints.
This mechanism is controlled by the safety_fence configuration in novel.yaml.
- High-score bypass: Chapters scoring >= 90 skip Manager real-time update, deferred to batch processing at pipeline end.
- Chapter type routing: Climax chapters force Director analysis. Transition chapters skip Director. Routine chapters run Director every N chapters.
- Scheduling proposals: Director can propose chapter insertions, skips, or merges, applied from end to start after current chapter completes.
For chapters detected as climax or when prior score is below 80, Writer generates multiple structural variants through think_variations():
- Exploratory mode: Random dimension selection with varied temperature (0.5/0.7/0.9).
- Corrective mode: Targets weak dimensions identified by Critic, injecting negative constraints into the variant prompt.
- Outline pre-screening: Critic evaluates each variant outline on plot logic, character consistency, and pacing before full creation.
A five-chapter time-paradox short story generated by the autonomous pipeline:
| Chapter | Title | Score | Words |
|---|---|---|---|
| ch_001 | Quantum Whisper | 85 | 6,064 |
| ch_002 | Ripples | 85 | 4,110 |
| ch_003 | Second Attempt | 85 | 5,694 |
| ch_004 | Vortex | 82 | 4,306 |
| ch_005 | Causal Loop | 85 | 5,746 |
| Total | 84.4 avg | 25,920 |
Creation time: approximately 14 minutes. Token consumption: 210,503.
OpenNovel exposes its full creation pipeline through the Model Context Protocol (MCP), enabling Claude Code and other MCP clients to initialize projects, check status, write chapters, and run autonomous creation.
# The server runs on stdio transport
novel-mcpCreate or edit .mcp.json in your project root or in ~/.claude/settings.json:
{
"mcpServers": {
"opennovel": {
"command": "novel-mcp",
"args": [],
"env": {
"DEEPSEEK_API_KEY": "sk-xxxx",
"OPENAI_API_KEY": "sk-xxxx"
}
}
}
}| Tool | Description | Key Parameters |
|---|---|---|
init_project |
Create a new novel project with standard structure | path (str): project directory |
get_status |
Read project state: config, characters, chapters | path (str): project directory |
write_chapter |
Single chapter creation with evaluation | path, chapter_id, chapter_hint (str) |
auto_create |
Full multi-chapter autonomous creation | path, chapters (int, optional) |
Once configured, you can invoke OpenNovel through natural language in Claude Code:
Initialize a science fiction novel project at ./nova.
The setting is a generation ship where the crew discovers
the cryo-pods are slowly failing. Create 3 characters:
a pragmatic captain, a compassionate doctor, and a
mysterious passenger who shouldn't be awake.
Use auto_create to write 5 chapters.
Claude Code will call the MCP tools in sequence: init_project → edit files directly (canon, characters, outline) → auto_create with chapters=5.
You can also combine with direct file editing for finer control:
After init_project, I'll write the world rules myself...
novel --help # View all commands
novel <command> --help # Command-specific help| Command | Description |
|---|---|
novel init <name> |
Initialize project in workspace (novels/<name>/). Use . for current directory. |
novel write <file> |
Interactive AI-assisted writing loop (Gen1 Actor). |
novel auto <path> |
Four-agent autonomous creation pipeline (recommended). |
novel stash <text> |
Store inspiration fragment into subconscious pool. --tag for labels. |
novel commit <file> |
Five-step review: snapshot → state extraction → diff → confirmation → persist. |
novel rollback <snapshot> |
Restore project to a previous snapshot. |
novel diff <file> |
Validate consistency between chapter text and shadow state. |
novel doctor <path> |
Diagnose project health: orphan characters, dangling references, dirty flags. |
novel list |
List all projects in workspace with model, chapter count, word count. |
novel config |
View or modify global configuration (default model, workspace directory). |
novel foreshadow |
View or manage foreshadowing tracking table. --add for manual entries. |
Each novel project has its own novel.yaml:
version: "1.0.1"
model: "deepseek/deepseek-v4-flash"
token_budget: 32000
output_reserve: 4000
creative_direction: "Hard sci-fi, time paradox, tragic aesthetics"
target_chapters: 5
words_per_chapter: 3500
outline: "outlines/story.md"
director_enabled: true
agents:
writer:
think_model: "deepseek/deepseek-v4-flash"
write_model: "deepseek/deepseek-v4-flash"
revise_model: "deepseek/deepseek-v4-flash"
critic:
model: "deepseek/deepseek-v4-flash"
manager:
model: "deepseek/deepseek-v4-flash"
director:
model: "deepseek/deepseek-v4-flash"Located at the project root, searched upwards from current directory:
# Global defaults for all projects
default_model: "deepseek/deepseek-v4-flash"
workspace_dir: "novels"
default_api_base: "https://api.deepseek.com/v1"Agent-level (agents.writer.model)
→ Project-level (novel.yaml model)
→ Global-level (.opennovel.yaml default_model)
→ Hardcoded default (deepseek/deepseek-v4-flash)
- ID as Anchor — Global canonical IDs (
char_001,loc_london). Never use character names for internal references. - Authority Hierarchy —
CANON>STATE MEMORY>SUBCONSCIOUS. Inspiration must never be executed as canon. - Human Review Gate — AI proposes, human approves.
novel commitenforces diff review before persistence. - Reversible Operations — Every destructive write creates a file-level snapshot before modification.
novel rollbackfor instant recovery. - Independent Metrics Storage — Runtime telemetry (token usage, evaluation history, agent traces) stored in
.novel.metrics.db, physically separate from narrative truth (.novel.db).
<project>/
├── canon/ # Immutable world-building (CANON layer)
│ └── world_rules.md
├── characters/ # Character files with YAML frontmatter
│ ├── char_001.md
│ └── char_002.md
├── draft/ # Chapter drafts
│ ├── ch_001.md
│ ├── ch_002.md
│ └── ...
├── outlines/ # Story outline (##-separated chapters)
│ └── story.md
├── foreshadowing/ # Auto-detected foreshadowing tracking
│ └── foreshadowing.md
├── summaries/ # Auto-generated chapter summaries
│ ├── ch_001.md
│ └── ch_002.md
├── timeline/ # Auto-generated event timeline from SQL
│ └── events.md
├── planner_notes.md # Director analysis record (appended)
├── subconscious/ # Inspiration fragments (SUBCONSCIOUS layer)
├── .snapshots/ # File-level incremental snapshots
├── .index/ # Vector index persistence
├── .novel.db # SQLite event ledger (narrative truth)
├── .novel.metrics.db # SQLite metrics database (runtime telemetry)
├── debug/prompts/ # Optional LLM prompt logs
└── novel.yaml # Project configuration
opennovel/
├── cli/ # Typer CLI commands
├── core/ # Core engine
│ ├── llm.py # LiteLLM bus + tenacity retry + token tracking
│ ├── auto_runner.py # Autonomous four-agent orchestrator
│ ├── context_assembler.py # Context assembly + token budgeting
│ ├── agent_autonomy.py # Tool-calling protocol + autonomous loop
│ ├── hybrid_retriever.py # SQL + vector dual-track retrieval
│ ├── retriever.py # Semantic retrieval routing
│ ├── causal_graph.py # NetworkX causal DAG analysis
│ ├── canon_checker.py # World-building rule validation
│ ├── safety_fence.py # Recursion/token/timeout/canon constraints
│ ├── tool_registry.py # Knowledge query dispatch center
│ ├── mutation_strategy.py # Mutation dimension selection
│ ├── global_config.py # .opennovel.yaml loader
│ ├── state_manager.py # Snapshot + rollback + diff
│ ├── config.py # novel.yaml management
│ ├── doctor.py # Project health diagnosis
│ └── diff_checker.py # Text-shadow consistency check
├── agents/ # Agent personalities
│ ├── writer.py # Planning + creation + revision + mutation
│ ├── critic.py # Five-dimension scoring + anchored feedback
│ ├── manager.py # State extraction + event recording
│ ├── director.py # Global narrative analysis + strategy
│ ├── actor.py # Interactive writing (Gen1)
│ └── auditor.py # State extraction with self-correction
├── storage/ # Storage adapters
│ ├── sqlite.py # Event store (SQLModel)
│ ├── metrics.py # Metrics store
│ ├── foreshadowing.py # Foreshadowing Markdown read/write
│ ├── timeline.py # Timeline generator (SQL to Markdown)
│ ├── summaries.py # Chapter summary persistence
│ ├── yaml_storage.py # YAML frontmatter atomic read/write
│ └── vector.py # LlamaIndex vector index
├── schemas/ # Pydantic / SQLModel models
├── prompts/ # Agent prompt assets
└── mcp_server.py # MCP protocol server
# Setup
git clone https://github.com/Yaemikoreal/OpenNovel.git
cd OpenNovel
pip install -e ".[dev]"
# Optional dependencies
pip install -e ".[local-embedding]" # BGE-M3 local embeddings
pip install -e ".[phase2]" # NetworkX for causal graph
# Testing
pytest -v --tb=short # Run all tests
pytest tests/test_auto_runner.py # Single file
pytest -k "test_autonomous" # Filter by name
pytest --cov=opennovel --cov-report=term-missing # Coverage
# Code quality
ruff check opennovel/ tests/
ruff format --check opennovel/ tests/
mypy opennovel/
# Type checking (strict)
mypy --strict opennovel/- 850+ tests across 40 test files
- 88% code coverage
- Modules at or near 100% coverage: parser, state_manager, diff_checker, doctor, schemas, yaml_storage, metrics, foreshadowing
MIT License. See LICENSE for details.