Manuscript Compiler is an offline, mobile-safe Obsidian plugin that converts an author-reviewed vault structure into six native manuscript formats. The architecture is designed around several non-negotiable principles:
1.**One interpretation of the manuscript.** Scanning, detection, correction, parsing, cleaning, and ordering produce one semantic `Book`.
2.**Prepared identity.** Preview and export share the same `Book` instance inside a `PreparedCompileSession`.
3.**Format independence.** Exporters receive a shared `SemanticDocument`; they do not inspect the vault or reinterpret structure.
4.**Validate before delivery.** Generated bytes pass their format validator before any browser download starts.
5.**No manuscript vault output.** Delivery is a Blob download controlled by the host, never a vault or Node filesystem write.
6.**Privacy by construction.** No network, telemetry, cloud, prose-bearing logs, absolute-path history, or external tool exists.
7.**Deterministic native output.** Exporters generate their formats directly and use only controlled local data.
8.**Obsidian ownership.** Commands, events, settings, DOM, focus, and lifecycle use documented Obsidian APIs.
These are architectural constraints, not current implementation accidents.
No route may skip stages. Command-palette, current-book, selected-folder, guided, validation, and sample entry points all converge on `CompilePreparationService.prepareAuthoritative`.
## Physical discovery and folder detection
`VaultScanner` performs mechanical discovery inside one exact `TFolder`. It identifies Markdown files and broad physical Part/Chapter containers but does not decide what should be published. Its output, `ScannedBook`, contains Obsidian file/folder objects and is intentionally unsuitable for export.
`BookRootResolver` centralises root selection. A root explicitly chosen through the File Explorer context menu is authoritative and is returned exactly. Compatibility commands may resolve a root from settings or active-note ancestry. The selected root names the Book but never becomes a Part, Chapter, or transparent heading.
`ContentPlanItem[]` is the bridge between physical discovery and semantic parsing. Each item records path, parent, inferred/current role, local inclusion, sibling order, reason/warning, and whether the author overrode detection.
`workspace/content-tree.ts` owns pure inclusion/order transformations. `ContentsTreeViewState` owns scroll, focus identity, folder expansion, review filter, and correction mode; it does not own manuscript semantics. `CompileWorkspaceController` applies mutations and invalidates prepared output.
`ManuscriptParser` reads only the content-plan-rewritten `ScannedBook`. It parses YAML metadata for structure/filter decisions, applies `MetadataFilterEngine`, cleans publishable Markdown through `ContentCleaningPipeline`, constructs `Book`, and orders Parts/Chapters/Scenes.
Cleaning removes authoring syntax and structured project metadata while preserving ordinary prose. Supported rules include YAML front matter, Obsidian comments, HTML comments, Dataview blocks, callout markers, internal-link syntax, known authoring sections, and structured metadata regions. Body-section aliases can extract manuscript prose from templated notes.
`Book` contains cleaned manuscript content and semantic hierarchy. It contains no dependency on exporters or the UI. Changing this model is a cross-format product change and requires migration/fixture/export review.
`ScannedBook` and `Book` must never be conflated: the former is physical discovery; the latter is publication truth.
## PreparedCompileSession
`PreparedCompileSession` is an immutable-in-practice snapshot owned by one command or workspace. It contains:
- the exact resolved request and content plan;
- resolved profile;
- physical scan for diagnostics only;
- semantic `Book`;
- statistics, warnings, exclusions, variables, and compile result;
- included source paths;
- source-content fingerprint;
- semantic input signature;
- route and purpose.
Preview, validation, and export retain this object. They must not reconstruct its Book.
### Preview reuse and invalidation
Changes to inclusion, role, order, root, cleaning inputs, title/author variables, title page, table of contents, scene separator, semantic headings, or formatting that changes bytes invalidate preparation. Selected format and filename do not affect manuscript interpretation and therefore do not rebuild the Book.
Before export, `ExportCoordinator` recalculates:
- the source fingerprint from included file contents;
- the input signature from semantic request fields and plan.
A mismatch blocks export and instructs the author to refresh preview. Source hashing detects equal-size edits even when file timestamps do not change.
## SemanticDocument export projection
`SemanticDocument` is a format-oriented projection of the prepared `Book`. It provides ordered sections and blocks:
- title/author;
- front/back matter headings;
- Part/Chapter number and title headings;
- optional body headings;
- first paragraphs;
- later body paragraphs;
- scene and page breaks;
- inline bold/italic/link semantics.
The projection centralises presentation-relevant classification so exporters do not duplicate structural interpretation. It does not scan, parse, clean, reorder, or replace `Book`.
Paragraph state is semantic and presentation-independent. The first paragraph after a structural/body heading or scene break is marked `first`; later ordinary prose is Body Text. The indentation toggle only changes style declarations.
## Export pipeline
`ExportCoordinator` owns the terminal transaction:
1. acquire the global export operation;
2. verify prepared source/input fingerprints;
3. apply format-independent blocking policy;
4. persist current safe defaults;
5. create one `SemanticDocument` from `session.book`;
6. generate bytes using `EXPORTERS[format]`;
7. validate using `EXPORT_VALIDATORS[format]`;
8. enter non-cancellable finalisation;
9. start one browser download;
10. record success only if dispatch started;
11. release operation state in `finally`.
Exporters do not own UI, settings persistence, validation policy, delivery, or history. Validators do not repair bytes. Download service does not know semantic content.
### Export contracts
`ExportFormat` is the exhaustive union:
```text
docx | odt | epub | html | markdown | xml
```
`ManuscriptExportContext` contains the prepared session, shared `SemanticDocument`, resolved formatting, and portable filename. `GeneratedExport` contains format, filename, MIME type, bytes, and non-prose warnings.
Adding a format requires updating both exhaustive registries and all UI/testing/documentation/package surfaces. A registry gap is a compile-time error.
## Export formats
### DOCX
`docx.ts` produces native WordprocessingML using named styles and `fflate`. Styles explicitly encode title/matter/Part/Chapter weight, First Paragraph versus Body Text indentation, scene separators, page size, chapter page starts, and optional TOC field. It never converts another format. `docx-validator.ts` verifies essential ZIP and OOXML structure; it does not claim complete OOXML conformance.
### ODT
`OdtExporter` produces a native OpenDocument Text ZIP. The `mimetype` entry is first and uncompressed. Generated content references named paragraph styles in `styles.xml`; heading styles explicitly declare bold and body styles explicitly declare indentation. Validation checks package entries, mimetype ordering/storage, manifest targets, XML shape, and required styles.
### EPUB
`EpubExporter` produces an EPUB 3 ZIP with container, package document, navigation, ordered XHTML sections, and embedded stylesheet. The mimetype entry is first/uncompressed. XHTML uses semantic manuscript classes; CSS explicitly styles structural headings and body indentation without scripts, remote assets, or inline styles.
### HTML
`HtmlExporter` produces one offline HTML5 document with embedded CSS and semantic manuscript classes. It contains no JavaScript or remote reference. Presentation uses manuscript-specific selectors rather than global heading-weight rules.
### Markdown
`MarkdownExporter` renders deterministic UTF-8 Markdown from `SemanticDocument`. It preserves heading syntax, emphasis, readable link text, Unicode, paragraph spacing, and exactly one final newline. It does not fake first-line indentation with spaces, tabs, HTML, entities, or CSS.
### XML
`XmlExporter` produces deterministic semantic XML in `https://manuscript-compiler.dev/schema` with `schemaVersion="1.0"`. It contains metadata, matter, Part/Chapter/Scene hierarchy, paragraph elements, and inline emphasis/link spans. It excludes source paths, settings, profile IDs, diagnostics, and presentation styling.
## Browser download
`BrowserDownloadService` is the only completed-export delivery path. It creates a Blob and object URL, assigns URL/filename as anchor properties, appends and clicks one temporary `<a download>`, removes it, and revokes the URL on success or failure.
This boundary exists because:
- Obsidian Community Plugins must remain mobile-safe;
- the host owns save/share behavior;
- Node/Electron filesystem paths are unavailable or non-compliant;
- the plugin must not write manuscript exports into the vault;
- final external persistence cannot be observed truthfully.
Dispatch success means the host accepted the click. It does not mean a known filesystem path was written.
## Validation
The registry in `export-validators.ts` mirrors `EXPORTERS`. Validators perform restrained structural checks appropriate to each format:
- XML: namespace/schema, structure, escaping, and presentation/privacy exclusions.
Validation failure blocks download. Automated structural validation does not replace Word/Vellum/LibreOffice/reader/browser interoperability checks.
## Operation state and cancellation
`OperationStateController` permits one active global operation and defines these states:
```text
idle → preparing → ready
idle/ready → exporting → finalising → complete
preparing/exporting → cancelled
preparing/exporting/finalising → failed
```
`AbortController` supplies cancellation before finalisation. `CompilationCancelledError` lets callers distinguish cancellation from failure. Finalisation locks cancellation because the download click cannot be rolled back or observed reliably.
The workspace controller deduplicates preparation/export promises, cancels preparation when appropriate, and releases state in terminal paths. A partially prepared Book is never published.
## Settings and presets
`settings.ts` defines persisted schema/defaults. `simple-workflow.ts` resolves guided choices into a complete compatibility profile. Vellum and Standard Manuscript are deterministic formatting presets; Custom preserves manual values.
`main.ts` loads raw settings, then calls `repairSettings` before services or UI consume them. UI components receive repaired data only.
Historical fields may remain for backward-compatible loading. They are storage-only if their feature was removed. In particular, legacy vault-output or external-converter fields cannot activate production behavior.
## Migration and repair
`migrateSettings` translates known historical shapes. `repairSettings` validates and bounds untrusted persisted data, nested profiles, history, and logs. Both are idempotent and preserve explicit user choices, including false/zero values and custom formatting.
- profile IDs and bounded nested structures are repaired;
- removed fields are never revived;
- a second migration/repair pass makes no changes.
## History and diagnostics
`CompileHistoryService` records bounded terminal facts only after truthful outcomes. Success follows validation and started download dispatch. Cancellation and failure are distinct. Records can include format, portable filename, counts, timings, validation status, and download-started flag.
`history-storage.ts` whitelists persisted fields and repairs malformed arrays. `DiagnosticsReportGenerator` produces a redacted support summary without reading notes. Neither history nor diagnostics may retain manuscript prose, metadata values, warning details, absolute paths, usernames, Blob URLs, or external destinations.
## Obsidian integration
`main.ts` is the composition root. It:
- loads and repairs settings;
- constructs history, operation, preparation/export, and command services;
- registers stable command IDs;
- registers the documented File Explorer `file-menu` event;
- registers settings UI;
- owns onboarding and unload cancellation.
The selected folder action accepts only `TFolder`. UI uses Obsidian `Modal`, `Setting`, `Notice`, suggestion, icon, and component APIs. No global `app` is used. CSS is scoped to plugin roots and retains theme variables, focus-visible behavior, reduced-motion, high-contrast, narrow-pane, and mobile behavior.
## Security, privacy, and dependency policy
Production guarantees:
- offline execution;
- no telemetry/accounts/cloud/network;
- no remote resources;
- no Electron or Node filesystem;
- no shell, `child_process`, or external executable;
- no other community-plugin dependency;
- no manuscript vault output;
- no unsafe HTML injection;
- deterministic escaping for XML/HTML/OOXML;
- controlled ZIP entry paths;
-`fflate` as the sole runtime dependency.
Dependency additions require product approval, security/licence/maintenance/bundle/mobile analysis, lockfile review, updated notices, clean tests, and clean audit. See [SECURITY.md](SECURITY.md).
## Performance model
Preparation reads notes with bounded concurrency, builds one Book, calculates shared statistics/warnings, and hashes included content. Exporters reuse one SemanticDocument and do not repeat preparation.
The benchmark constructs 500 Chapters, 2,000 Scenes, and 2 million words, then runs all six formats with indentation enabled and disabled from the same Book. Results are informational; there is no strict machine-specific threshold. Maintainers should investigate repeated scanning, quadratic transforms, or disproportionate memory growth.
| `benchmark:large` | one preparation, all exporters, runaway regression guard |
| package validation | exact release allowlist and version identity |
Fixtures use synthetic content. Generated manual-inspection artifacts are ignored and excluded from packages. Live application checks remain unchecked in `MANUAL_TESTING.md` until actually performed.
## Directory layout
```text
src/ production TypeScript
src/workspace/ three-stage workspace state, views, and projections
New formats, semantic Book fields, workflow stages, dependencies, delivery routes, or persistent data are product changes requiring explicit architecture review.
Any future feature proposal must first show how it preserves the semantic Book, prepared identity, exhaustive export/validation contract, offline privacy model, browser delivery, mobile safety, and dependency policy.