Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

841 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Docxodus

Free your .docx files.
Render them, edit them, diff them, and hand them to an agent — from .NET, the browser, Python, or the shell.

CI NuGet npm PyPI License: MIT


A .docx is a zip full of XML that only one program really understands. Docxodus is the toolkit that changes that: a structure-aware OOXML engine that reads Word documents faithfully, writes them back losslessly, and exposes them through whichever surface your program actually needs — an HTML render, a stable markdown projection, a stateful edit session, a tracked-changes redline, or a live in-browser editor.

It runs as a .NET library, a WebAssembly module in the browser, an npm/TypeScript package, a Python client, and three CLI tools — all over the same engine, so a document behaves the same everywhere.

                    ┌───────────────────────────────────────────┐
  your .docx  ──▶   │       Docxodus  ·  one OOXML engine       │   ──▶   .docx  (lossless)
                    └────┬─────────┬──────────┬──────────┬──────┘
                         │         │          │          │
                      render     edit      compare    project

Every screenshot below is real output, captured from the NVCA model financing documents — the venture-financing forms that every startup lawyer actually redlines.


Compare — a redline Word will open

DocxDiff compares two documents structurally and emits native Word tracked-changes markup: w:ins, w:del, w:moveFrom/w:moveTo, and w:pPrChange. Not a text diff with highlighting — a file you can hand to opposing counsel, who accepts and rejects changes in Word as usual.

A redlined venture financing agreement

One frame, four kinds of change, all detected automatically: a struck definition (red), an inserted definition (green), word-level substitutions inside an otherwise untouched sentence (Series A replacing a blank; means replacing shall mean and include), and a move — the interpretation clause struck at the bottom in purple and re-inserted at the top, linked as one operation rather than reported as an unrelated delete and insert. Note the list numbering: it renumbers as if every change were already accepted — the struck (g) is followed by the live (g), exactly the duplicate-number display Word uses in All Markup view — so the letters a reader cites are the final document's.

  • Round-trip contract: accept(compare(left, right)) ≡ right and reject(...) ≡ left, verified at the block-text level.
  • The diff is also data. GetRevisions() returns typed revisions carrying stable kind:scope:unid anchors; GetEditScriptJson() returns the whole edit script as JSON, so you can drive a review UI or an approval workflow without parsing OOXML.
  • N-way consolidate. Merge many reviewers' copies against one base into a single multi-author tracked-changes document, with a structured conflict report.
  • Headers and footers are compared too — the way Word's own "Headers and footers" option does, and the way WmlComparer never did.

Two engines ship: the incumbent WmlComparer and the newer structure-aware DocxDiff. See docs/architecture/ir_diff_engine.md.


Render — fidelity, not approximation

DOCX → HTML that keeps the things naive converters drop: justification, style inheritance, legal numbering, tables, images, comments, headers and footers, and real footnotes with back-references.

The NVCA model charter rendered to HTML

  • Paginated mode flows content into real page boxes with per-page numbers, page-anchored footnotes, and running heads — a print-accurate preview in the browser.
  • Tracked changes render as <ins>/<del> with author metadata and move-aware styling (that's exactly what the redline screenshot above is).
  • Comments render endnote-style, inline, or in a margin; annotations can be overlaid incrementally without re-converting the document (~0.3 ms to add one, vs. a full re-conversion).
  • HtmlToWmlConverter goes the other way.

Project — a text view an LLM can actually address

WmlToMarkdownConverter renders a document as markdown where every block carries a stable id. The same document, two views, one addressing system:

Markdown projection beside the rendered document

An anchor like {#p:body:09612b1c13…} is content-derived and survives edits elsewhere in the document. That gives an agent something a raw text dump can't: a way to point.

  • Read the markdown, decide "rewrite the indemnification clause", write back to that anchor.
  • Anchors are shared across the whole stack — the same id addresses a projection block, a rendered DOM node (data-anchor), a diff revision, and an edit target.
  • Resolve intent to anchors by text, regex, kind, bookmark, or annotation id — no re-walking the document.
  • Also exports to OpenContracts format with PAWLS page layout and token positions, for NLP and document-analysis pipelines.

Edit — programmatically, or in a browser

DocxSession is a stateful, anchor-addressed editor over the live document. Every mutation returns a typed result envelope — no exceptions across the API boundary — and the document stays a real, valid .docx the whole time.

Text and structure (replace, split, merge, insert, delete), tables (insert/delete rows and columns), formatting (character ranges, paragraph styles, lists, borders), headers and footers, page numbering, footnotes and endnotes, annotations, bounded undo/redo, and a raw-OOXML escape hatch for anything the markdown subset can't express. Set TrackedChanges = RenderInline and every edit lands as w:ins/w:del instead of an accepted change.

DocxEditor is the browser editor built on top of it — framework-agnostic TypeScript, WASM engine, no server:

The in-browser DOCX editor

The document you see is the document you get: edits go through the session, and only the changed block re-renders — so a structural op costs ~90–360 ms on a 346-block, 94-footnote filing template, not the ~6 s a full remount used to take. save() returns lossless bytes.

Insert tab Contextual table tab

More of the surface — ribbon anatomy, header/footer bands, paginated mode, per-operation costs — is in docs/architecture/editor_ui_surface.md.


Get started

.NETBrowser / Node
dotnet add package Docxodus
using Docxodus;

var redline = DocxDiff.Compare(
    new WmlDocument("v1.docx"),
    new WmlDocument("v2.docx"));

redline.SaveAs("redline.docx");
npm install docxodus
import { initialize, compareDocuments } from 'docxodus';

await initialize();
const redline = await compareDocuments(v1, v2);
PythonCLI
pip install docx-scalpel
from docx_scalpel import open_session

with open_session(docx_bytes) as s:
    s.replace_text(anchor, "new text")
    out = s.save()
dotnet tool install -g Redline
redline old.docx new.docx out.docx

Also Docx2Html and Docx2OC, plus standalone binaries for Windows, Linux and macOS.

Opening an editor in a page is a few lines more — see npm/examples/editor.html for a complete ribbon implementation, and docs/npm-package.md for the TypeScript API and React hooks.


Where it runs

Surface Package Notes
.NET 10 library Docxodus (NuGet) The engine. Everything else wraps it.
Browser / Node docxodus (npm) .NET WASM + TypeScript. Runs fully client-side; Web Worker and React hooks included.
Python docx-scalpel (PyPI) Long-running host process, so an agent can issue dozens of edits against one open session. Alpha; linux-x64 wheels.
CLI Redline, Docx2Html, Docx2OC dotnet tool install -g, or download a self-contained binary.

What else is in the box

DocumentBuilder Merge and split DOCX files, with section and style fidelity
DocumentAssembler Populate templates from XML data via content controls
PresentationBuilder Merge and split PPTX
SpreadsheetWriter Streaming XLSX creation
OpenXmlRegex Regex search/replace across DOCX and PPTX
RevisionProcessor Accept and reject tracked revisions, byte-to-byte
FormattingAssembler Resolve and flatten inherited formatting
MetricsGetter Extract document metrics — styles, fonts, languages
ExternalAnnotationProjector Overlay annotations onto rendered HTML without touching the DOCX

Documentation

Design docs for every subsystem live in docs/architecture/. The ones worth reading first:

Doc What it covers
ir_diff_engine.md DocxDiff — pipeline, edit script, settings, parity with Word
docx_mutation_api.md DocxSession — full surface, anchor lifecycle, error catalog, markdown subset
markdown_projection.md The projection spec and anchor format
docx_converter.md WmlToHtmlConverter internals
editor_ui_surface.md The browser editor, control by control
ooxml_corner_cases.md Where Word disagrees with the spec — and what we do about it

Build and test

dotnet build Docxodus.sln            # build
dotnet test Docxodus.Tests/Docxodus.Tests.csproj   # 1,900+ tests

cd npm && npm install && npx playwright install chromium
npm run build && npm test           # WASM + Playwright browser tests

npm run build compiles the library to WebAssembly (scripts/build-wasm.sh) and bundles the TypeScript — re-run it after touching C#, TypeScript, or the test harness, or the browser tests will run against stale artifacts. Release builds treat warnings as errors. See CLAUDE.md for the full development workflow and repository layout.

Requirements

The .NET 10.0 SDK, to build from source. Consumers of the npm and PyPI packages need no .NET install of their own.

License

MIT — see LICENSE.


Built on the shoulders of Open-Xml-PowerTools. Thanks to Eric White, Thomas Barnekow, and all original contributors.

About

Swiss-army toolkit for .docx — faithful DOCX→HTML rendering, an in-browser block editor, Word-grade redlines with native tracked changes, and anchor-addressed markdown for LLM agents. .NET, WASM/TypeScript, Python, CLI.

Topics

Resources

Stars

54 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages