Architecture.

170 TypeScript/TSX source files across five clean architecture layers. Dependency injection. No DI container. Streaming CLI integration.

Five-Layer Clean Architecture.

Every file belongs to exactly one layer. Import rules are strictly enforced — inner layers never depend on outer layers.

LAYER 1
Domain
src/domain/
Pure types. Zero imports. Everything depends on this.
LAYER 2
Infrastructure
src/infrastructure/
Implements domain interfaces. Isolated modules.
LAYER 3
Application
src/application/
Orchestrates infrastructure through injected interfaces.
LAYER 4
Main / IPC
src/main/ + src/preload/
Composition root + thin IPC adapters.
LAYER 5
Renderer
src/renderer/
React + Zustand. Preload bridge only.

Technology Stack.

LayerTechnologyVersion
ShellElectron33.4.0
BundlerVite (via Electron Forge)^5.4.21
FrameworkReact^18.3.0
LanguageTypeScript~5.5.0
StylingTailwind CSS^4.0.0
StateZustand^5.0.0
Databasebetter-sqlite3^11.0.0
AI BackendClaude Code CLI(system-installed)
BuildPandoc(bundled binary)
IDsnanoid3
Markdownmarked^15.0.0
Diffdiff^8.0.4
Archivearchiver^7.0.1
Build ToolElectron Forge^7.11.1

Service Dependency Graph.

All services are composed in src/main/index.ts (the composition root) and injected via constructors. No DI container — plain constructor injection.

SettingsService(userDataPath)
DatabaseService(dbPath)
AgentService(agentsDir)
FileSystemService(booksDir, userDataPath)
ClaudeCodeClient(booksDir, db)
ProviderRegistry(settingsService)

UsageService → IDatabaseService
ChapterValidator(booksDir)

ChatService
├── ISettingsService
├── IAgentService
├── IDatabaseService
├── IProviderRegistry
├── IFileSystemService
├── UsageService
└── ChapterValidator

PipelineService → IFileSystemService
BuildService → IFileSystemService, pandocPath, booksDir

RevisionQueueService
├── IFileSystemService
├── IProviderRegistry
├── IAgentService
├── IDatabaseService
└── ISettingsService

MotifLedgerService → IFileSystemService, IProviderRegistry
VersionService → IDatabaseService, IFileSystemService
ManuscriptImportService → IFileSystemService, pandocPath
SourceGenerationService
├── ISettingsService
├── IAgentService
├── IDatabaseService
├── IFileSystemService
└── IProviderRegistry

SeriesImportService → IManuscriptImportService, ISeriesService
HelperService
├── ISettingsService
├── IAgentService
├── IDatabaseService
├── IFileSystemService
├── IProviderRegistry
└── StreamManager

NotificationManager → ISettingsService
BookWatcher(booksDir, callback)
BooksDirWatcher(booksDir, callback)

Key Design Decisions.

Constructor Injection

No DI container. Services depend on interfaces, not concrete classes. The composition root in src/main/index.ts is the only place concrete classes are instantiated.

No API Keys

Claude Code CLI handles its own authentication through the user's Anthropic subscription. The app stores no secrets. Additional OpenAI-compatible providers manage their own keys.

Multi-Model Provider Registry

Central ProviderRegistry routes model requests to the correct provider. O(1) reverse model index. Protects built-in providers from deletion. Config persisted to settings.json.

Streaming CLI Integration

Claude CLI spawned as child process with --output-format stream-json. NDJSON events parsed line-by-line and mapped to a 12-variant StreamEvent discriminated union.

Context Budget System

Per-agent read guidance determines which files to include. Dynamic conversation compaction based on available context window: generous (all turns), moderate (8), tight (4), critical (2).

File Version History

Every file write (agent or user) creates a snapshot in SQLite. SHA-256 dedup prevents duplicate storage. Structured diffs via the diff library. One-click revert with audit trail.

Database Schema.

7 tables in SQLite with WAL mode and foreign keys enabled. Forward-only migration system via src/infrastructure/database/migrations.ts.

TablePurposeKey Columns
conversationsChat conversations per book/agentid, book_slug, agent_name, pipeline_phase, purpose, title
messagesMessage history with thinkingid, conversation_id (FK), role, content, thinking
token_usageToken consumption per callconversation_id (FK), input/output/thinking tokens, model
stream_eventsPersisted stream events for replaysession_id, sequence_number, event_type, payload
stream_sessionsCLI call lifecycle trackingid, conversation_id, agent_name, model, ended_at, interrupted
file_versionsFile snapshots with dedupbook_slug, file_path, content, content_hash, source
schema_versionMigration trackingversion, applied_at, description

Source Tree.

src/
├── domain/                              # Pure types, zero imports
│   ├── types.ts                         # All shared type definitions
│   ├── interfaces.ts                    # Service contracts (ports)
│   ├── constants.ts                     # Agent registry, pipeline phases, defaults
│   ├── statusMessages.ts               # Rotating status messages
│   └── index.ts                         # Barrel export
│
├── infrastructure/                      # Implements domain interfaces
│   ├── settings/                        # SettingsService — JSON preferences
│   ├── database/                        # DatabaseService + schema + migrations
│   ├── agents/                          # AgentService — .md prompt loader
│   ├── filesystem/                      # FileSystemService + BookWatcher + BooksDirWatcher
│   ├── claude-cli/                      # ClaudeCodeClient + StreamSessionTracker
│   ├── providers/                       # ProviderRegistry + OpenAiCompatibleProvider
│   ├── series/                          # SeriesService — file-based series CRUD + bible
│   └── pandoc/                          # Pandoc binary path resolution
│
├── application/                         # Business logic via injected interfaces
│   ├── ChatService.ts                   # Send → stream → save orchestration
│   ├── ContextBuilder.ts                # Budget-aware context assembly
│   ├── PipelineService.ts              # Phase detection + user confirmation gates
│   ├── BuildService.ts                  # Pandoc execution for DOCX/EPUB
│   ├── UsageService.ts                  # Token tracking
│   ├── RevisionQueueService.ts          # Revision plan parsing + session execution
│   ├── ChapterValidator.ts              # Auto-corrects misplaced chapter files
│   ├── AuditService.ts                  # Verity audit/fix pipeline
│   ├── PitchRoomService.ts              # Pitch Room message handling
│   ├── HotTakeService.ts                # Ghostlight hot-take orchestration
│   ├── AdhocRevisionService.ts          # Direct feedback → Forge revision plan
│   ├── StreamManager.ts                 # Stream lifecycle + session tracking
│   ├── MotifLedgerService.ts            # Motif ledger CRUD + CLI normalization
│   ├── VersionService.ts                # File versioning (snapshot/diff/revert)
│   ├── ManuscriptImportService.ts       # DOCX/MD import + chapter detection
│   ├── SourceGenerationService.ts       # Multi-agent source doc generation
│   ├── SeriesImportService.ts           # Batch series import orchestration
│   ├── HelperService.ts                 # In-app help assistant
│   ├── DashboardService.ts             # Book overview dashboard aggregation
│   ├── StatisticsService.ts            # Writing statistics + cost estimates
│   ├── FindReplaceService.ts           # Bulk find & replace across chapters
│   ├── thinkingBudget.ts                # Thinking budget resolution
│   └── context/TokenEstimator.ts        # ~4 chars/token estimation
│
├── main/                                # Electron main process
│   ├── index.ts                         # Composition root
│   ├── bootstrap.ts                     # First-run directory/file creation
│   ├── notifications.ts                 # OS notification manager
│   └── ipc/handlers.ts                  # Thin IPC adapter (80+ channels)
│
├── preload/index.ts                     # contextBridge: typed API for renderer
│
└── renderer/                            # React UI
    ├── App.tsx                          # Root component, onboarding gate
    ├── main.tsx                         # React 18 createRoot entry
    ├── stores/ (23 stores)              # Zustand state management
    ├── components/ (20 groups)          # Layout, Chat, Files, Build, PitchRoom,
    │                                    # RevisionQueue, MotifLedger, Import,
    │                                    # Helper, Series, Dashboard, Statistics,
    │                                    # Reading, RightPanel, common, etc.
    ├── hooks/ (6 hooks)                 # Resize, theme, events, status, tooltip
    ├── tours/                           # Guided tour step definitions
    └── styles/globals.css               # Tailwind CSS v4 base

Contributing.

Prerequisites

Node.js 20+, npm 9+, Claude Code CLI installed and authenticated.

Development

git clone https://github.com/john-paul-ruf/novel-engine.git
cd novel-engine
npm install
npm run download-pandoc
npm start

Architecture Rules

If you contribute, respect these non-negotiable rules:

Detailed architecture docs are maintained in the repo at docs/architecture/ — ARCHITECTURE.md, DOMAIN.md, INFRASTRUCTURE.md, APPLICATION.md, IPC.md, RENDERER.md.