ABook is a self-hosted web application that uses AI agents to collaboratively write books. Seven specialized agents — Story Bible, Characters, Plot Threads, Chapter Outlines, Writer, Editor, and Continuity Checker — work together under your direction, streaming their progress in real time and pausing to ask clarifying questions when needed.
- Seven specialized agents across two phases: a 4-phase Planner (Story Bible → Characters → Plot Threads → Chapter Outlines) and a 3-agent writing pipeline (Pre-write Check → Write → Check → Edit → final Check) per chapter
- Human-assisted generation — enable a per-book assisted mode that pauses after each planning phase and during chapter checking so you can add optional guidance; optional prompts support Skip and pending questions are restored after page refresh
- Guided planning Q&A — agents ask clarifying questions up front before planning begins, then carry your answers through Story Bible, Characters, Plot Threads, and Chapter Outlines
- Real-time streaming — watch chapters being written token by token via SignalR; Story Bible, Characters, and Plot Threads stream to their respective tabs with live progressive JSON previews
- Checker → mechanical patch apply — the Checker flags continuity, grammar, repetition, and style issues as structured JSON patches with verbatim original text and replacement; the Editor applies them mechanically (no LLM call) using IndexOf-first matching with whitespace normalization and position-as-hint disambiguation, then re-indexes the chapter for RAG. Feedback message grouped by type shows all fields per fix.
- Token usage statistics — per-agent prompt and completion token counts displayed in a scrollable collapsible panel and persisted to the database; Clear button to reset
- RAG context retrieval — Writer uses 3 targeted queries (characters, locations, plot threads) and Editor uses 4 (same + repeated-phrase detection) against pgvector embeddings to keep chapters consistent and avoid re-introductions
- Book continuation mode — create a new book based on a previous one; the new book copies key settings (language, human-assisted mode, target chapter count, all system prompts, and book-scoped LLM config)
- Ancestry-aware memory retrieval — RAG queries for a continued book include the full base-book chain (parent, grandparent, etc.), so sequels keep awareness of earlier events
- Ancestor-aware planning references — when generating a new Story Bible / Characters / Plot Threads / Chapter Outlines for a continued book, prior books’ artifacts are injected as reference context
- Full synopsis spine — every prior chapter's title and outline is injected into Writer and Editor user messages so agents can see the narrative shape of the whole book and avoid recycling scene beats, re-describing established characters, or restating established facts
- Explicit anti-repetition rules in default Writer, Editor, and Checker prompts — never re-introduce a known character/place, never restate established facts, vary scene-entry beats, flag echoed phrases
- Pluggable LLM backend — Ollama (default, local), OpenAI (or any OpenAI-compatible API), or Google AI Studio; configurable globally, per-user, or per-book
- Per-book customization — language, assisted-generation toggle, and per-phase system prompt overrides (Story Bible, Characters, Plot Threads, Chapter Outlines, Writer, Editor, Checker) with supported template tokens
- Inline editing — edit book metadata, chapter titles/outlines, and add chapters manually without leaving the detail page
- Multi-user — cookie-based authentication with admin role for user management
- Ollama model management — browse installed models, pull new ones with live progress
- Story Bible, Characters & Plot Threads — automatically generated by the Planner agent (4-phase: Story Bible → Characters → Plot Threads → Chapter Outlines); each phase has its own configurable system prompt, tracks a Complete / Not Started status, is fully editable, and can be individually completed, reopened, or cleared
- Flexible workflow controls — Plan Only (outline the book and stop, so you can review/edit outlines before writing), Write Book (full autonomous pipeline), Continue (resume from the first non-Done chapter), Continue Planning (re-run only the incomplete planning phases, skipping any already marked Complete), and individual per-chapter agent buttons
- Global concurrency limit — cap simultaneous agent runs across all books/users with
AgentSettings__MaxConcurrentRuns(changes apply after app restart) - Clear buttons — clear agent messages or token stats for a book without deleting any content
- Multiple export formats — download the finished book as HTML (6 colour themes, adjustable font size), EPUB, or FB2; or download a Metadata document (book info, chapter outlines, Story Bible, Characters, Plot Threads, agent messages, token statistics) as themed HTML
- Public Library — browse and read published books without logging in (when public mode is enabled); each chapter has its own URL (
/library/:bookId/chapters/:chapterId) for bookmarking and sharing; the Library uses the same sidebar layout as the rest of the app with download buttons (HTML / FB2 / EPUB) in the sidebar; chapter numbers appear as circular accent-colored badges in the sidebar; unauthenticated users land on the Library page by default - MCP server — built-in Model Context Protocol server at
/mcp; any MCP-compatible client (Claude Desktop, VS Code Copilot) can read and write book content and trigger agents using a per-user API token generated in Settings
[React SPA — served as static files from ASP.NET wwwroot]
↕ REST API + SignalR
[ASP.NET Core 10 API]
↕ Semantic Kernel ↕ EF Core + pgvector
[LLM (Ollama/OpenAI/…)] [PostgreSQL (vectors stored in-DB)]
React is built at image-build time and served from wwwroot/ — there is no separate frontend container.
- Docker + Docker Compose
- Ollama running on the host machine (or any OpenAI-compatible API)
# Pull and start everything
docker-compose up -d
# App is available at
open http://localhost:5000On first launch the app shows a Create Admin Account setup screen — the first account registered automatically becomes admin. After signing in, go to Settings to configure your LLM provider and pull an Ollama model.
# Create a docker-compose.yml or run directly:
docker run -d \
-p 5000:8080 \
-e ConnectionStrings__DefaultConnection="Host=<postgres-host>;Port=5432;Database=abook;Username=abook;Password=abook" \
--add-host host.docker.internal:host-gateway \
jncchds/abook:latestPostgreSQL (with the pgvector extension) must be reachable. The compose file below starts it automatically.
Full docker-compose.yml
services:
abook-api:
image: jncchds/abook:latest
ports:
- "5000:8080"
environment:
- ConnectionStrings__DefaultConnection=Host=postgres;Port=5432;Database=abook;Username=abook;Password=abook
- ASPNETCORE_ENVIRONMENT=Production
depends_on:
postgres:
condition: service_healthy
extra_hosts:
- "host.docker.internal:host-gateway"
restart: unless-stopped
postgres:
image: pgvector/pgvector:pg16
environment:
POSTGRES_DB: abook
POSTGRES_USER: abook
POSTGRES_PASSWORD: abook
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U abook -d abook"]
interval: 5s
timeout: 5s
retries: 10
restart: unless-stopped
volumes:
postgres_data:| Variable | Default | Description |
|---|---|---|
ConnectionStrings__DefaultConnection |
— | PostgreSQL connection string |
ASPNETCORE_ENVIRONMENT |
Development |
Production disables Swagger |
LlmDefaults__Provider |
Ollama |
Default LLM provider (Ollama, OpenAI, GoogleAIStudio) |
LlmDefaults__ModelName |
llama3 |
Default model name |
LlmDefaults__Endpoint |
http://host.docker.internal:11434 |
Default LLM endpoint |
LlmDefaults__ApiKey |
— | API key for the default LLM provider (required for OpenAI / GoogleAIStudio; optional for Ollama) |
LlmDefaults__EmbeddingModelName |
— | Embedding model for RAG (optional; falls back to chat model) |
AgentSettings__MaxConcurrentRuns |
3 |
Global max number of simultaneous agent runs across all books/users (Running + WaitingForInput) |
Changing
AgentSettings__MaxConcurrentRunsrequires restarting the API process/container.
ABook includes a built-in Model Context Protocol (MCP) server at /mcp. Any MCP-compatible client (Claude Desktop, VS Code / GitHub Copilot, etc.) can connect to it to:
- Read and manage books, story bibles, characters, plot threads, and chapters
- Trigger agent workflows (plan, write, edit, continuity check)
- Answer agent questions and poll run status
To connect:
- Open Settings in ABook and find the MCP Access section
- Generate an API token (or click Regenerate to rotate)
- Add the server to your MCP client config using
Authorization: Bearer <token>
Claude Desktop (claude_desktop_config.json):
{
"mcpServers": {
"abook": {
"type": "http",
"url": "http://localhost:5000/mcp",
"headers": { "Authorization": "Bearer YOUR_TOKEN" }
}
}
}VS Code / GitHub Copilot (.vscode/mcp.json):
{
"servers": {
"abook": {
"type": "http",
"url": "http://localhost:5000/mcp",
"headers": { "Authorization": "Bearer YOUR_TOKEN" }
}
}
}The LlmDefaults__* variables seed the global LLM configuration on startup. They can also be set in appsettings.Local.json (copy from appsettings.Local.example.json) for local development, or in docker-compose.override.yml for Docker-based local overrides.
Configure the LLM backend in the app's Settings page or via the API:
| Provider | Notes |
|---|---|
| Ollama | Default. Runs locally; host.docker.internal resolves to the host from inside Docker. |
| OpenAI | Provide API key and model name (e.g. gpt-4o). Leave endpoint blank for the real OpenAI API; set a custom endpoint to use any OpenAI-compatible API (Groq, Together, etc.). |
| Google AI Studio | Native Gemini connector. Requires an API key (get one at aistudio.google.com). Models: gemini-2.0-flash, gemini-2.5-pro, etc. Embedding model: text-embedding-004. |
Removed providers: Azure OpenAI (functionally identical to the OpenAI provider — use OpenAI with a custom endpoint instead) and LM Studio (use OpenAI with endpoint
http://host.docker.internal:1234/v1).
Configurations can be set globally, per-user, or per-book. The lookup order is: book-specific → user-default → global.
User creates book (title, premise, genre, target chapters)
│
├─ optional: choose a base book (settings copied once at creation)
│
▼
┌─────────────────────────────────────────────────────┐
│ [Planner Agent] — 4-phase planning pipeline │
│ Phase 1: Story Bible (world-building, tone, rules)│
│ Phase 2: Character Cards (roles, arcs, goals) │
│ Phase 3: Plot Threads (subplots, themes, arcs) │
│ Phase 4: Chapter Outlines (title + synopsis each) │
│ Prior books in the continuation chain are included │
│ as reference context for planning │
│ ─ asks clarifying questions up front, then │
│ optionally pauses after each phase in │
│ Human-assisted mode │
└─────────────────────────────────────────────────────┘
│
│ ← "Plan Only" stops here so you can review
│ and edit outlines, characters, plot threads
│ before clicking "Continue"
▼
For each chapter:
[Continuity Checker] ── pre-write: checks outline for contradictions
│
▼
[Writer Agent] ── writes full chapter prose
│ draft prose
▼
[Checker Agent] ── per-chapter continuity + style review
│ structured issue report (+ optional author notes in assisted mode)
▼
[Editor Agent] ── fixes reported issues (skipped if no issues found)
│ revised prose
▼
[Checker Agent] ── final informational re-check (no further editing)
│
▼
[Continuity Checker] ── final full-manuscript pass after all chapters complete
│
▼
Done ✓
Agents stream tokens via SignalR as they write. Workflow controls:
- Plan Only — runs the Planner and stops so you can edit outlines before writing
- Write Book — runs the full pipeline automatically from scratch
- Continue — resumes from the first non-Done chapter (skips already-completed ones)
- Continue Planning — re-runs only the incomplete planning phases; phases already marked Complete are skipped
- Stop — cancels any running agent cleanly
- Individual stage buttons (Write / Edit / Continuity) are available per chapter
In Human-assisted generation mode, the app also pauses:
- after each completed planning phase to collect optional author notes
- after each Checker pass so you can add extra attention points before the Editor runs
- with support for Ctrl+Enter to submit answers quickly in the chat panel
For books created from a base book, chapter-level RAG retrieval also includes embeddings from all ancestor books in the base chain.
- .NET 10 SDK
- Node.js 20+
- Docker (for PostgreSQL with pgvector)
# Start supporting services
docker-compose up postgres -d
# Start the UI dev server (proxies API to localhost:5178)
cd src/abook-ui
npm install
npm run dev
# Start the API (in a second terminal)
cd src/ABook.Api
dotnet runFor local LLM configuration, copy src/ABook.Api/appsettings.Local.example.json to appsettings.Local.json and fill in your values. Alternatively, create a docker-compose.override.yml (see the committed example) to set LlmDefaults__* environment variables for Docker runs.
The React dev server runs at http://localhost:5173 and proxies /api and /hub to the ASP.NET server at http://localhost:5178.
docker build -t abook .The multi-stage Dockerfile builds the React app (Node 20), compiles the .NET API (.NET 10 SDK), and produces a minimal runtime image (ASP.NET 10).
| Layer | Technology |
|---|---|
| Frontend | React 19, TypeScript, Vite, Zustand, react-markdown |
| Backend | ASP.NET Core 10, C#, Semantic Kernel |
| Database | PostgreSQL 16 via EF Core 10 + Npgsql |
| Vector store | pgvector (stored in PostgreSQL, Pgvector.EntityFrameworkCore 0.x) |
| Real-time | SignalR |
| Auth | Cookie-based, IPasswordHasher<T>, API token (Bearer) for MCP |
| MCP | ModelContextProtocol.AspNetCore 1.2.0 — HTTP/SSE transport, 37 tools |
| Container | Docker, Docker Compose |