jubarte-redlines
Lossless DOCX redline engine for Rust. Compare two Word documents and get a
tracked-changes .docx that opens cleanly in Microsoft Word — insertions,
deletions, moves, and format changes on top of the original package.
Also list, accept, or reject tracked revisions — and render any DOCX to PDF (Word-style layout, embedded fonts, no LibreOffice).
Ships as a Rust crate + CLI, a Python package, and an npm / WebAssembly package (Node + browser) — the same engine and output model everywhere.
- Repo: jandira-tech/jubarte-redlines
- crates.io:
jubarte-redlines - docs: docs.rs/jubarte-redlines
- PyPI:
jubarte-redlines(abi3 wheels, CPython ≥ 3.10) - npm:
jubarte-wasm(Node ≥ 18 + browsers, full and slim builds) - Maintainer: jandira.tech — we build legal tech.
Jandira Technologies is the studio behind Cicero (a
legal workbench that turns messy inputs into redlines, issue lists, and memos),
PII redaction models for Brazilian Portuguese, and AI/contract-drafting
benchmarks.
jubarte-redlinesfalls out of that work: when a redline has to look like Microsoft Word, you need a Word-mode comparer, not a shallow text diff.
Independent engineering measurements against a Word oracle. Not affiliated with Microsoft. Trademarks remain their owners’.
Why this crate
| Need | What jubarte-redlines does |
|---|---|
| Word-valid output | Produces native w:ins / w:del / move / format-change markup that Word opens without repair |
| Lossless package | Keeps parts, relationships, headers/footers, footnotes, styles, and media from the original |
| Library + CLI + bindings | compare_documents in-process (Rust); jubarte binary for shell/CI; PyO3 wheels on PyPI; wasm-bindgen package on npm |
| DOCX → PDF | Independent Word-style PDF renderer (convert::docx_to_pdf) — no LibreOffice, no Word |
| Safety | #![forbid]-style policy: unsafe_code = "deny" at the crate root — 100% safe Rust today |
| Supply chain | CI runs cargo-deny, REUSE license compliance, fmt, clippy -D warnings, MSRV 1.88 |
Install
CLI
# binary name is still `jubarte`
Library (skip clap if you only need the API)
# Cargo.toml
= { = "0.7", = false }
Rust import path is jubarte::… (library crate name); the package/repo name is
jubarte-redlines.
use document_comparer;
let original = read?;
let modified = read?;
let redline = compare_documents?;
write?;
# Ok::
Python (PyPI — prebuilt abi3 wheels for macOS arm64/x86_64 and manylinux x86_64/aarch64, CPython ≥ 3.10; GIL released during compute)
=
= # list[dict], same shape as `jubarte revisions --json`
= # Word-style PDF bytes
JavaScript / WebAssembly (npm — Node ≥ 18 CJS + browser ESM)
const = require; // full build
const = require; // no PDF, ~2.4 MB wasm
// browser: import init, { compareDocuments } from "jubarte-wasm/web" (or "jubarte-wasm/web-slim")
CLI
jubarte contract.docx contract-rev2.docx
→ writes contract_v_contract-rev2.docx next to the original
jubarte -b old.docx -m new.docx -o redline.docx --author "Legal"
jubarte revisions redline.docx --json # list tracked revisions
jubarte accept redline.docx -o final.docx # accept every revision
jubarte reject redline.docx -o clean.docx # reject every revision
jubarte convert contract.docx # independent DOCX → PDF
Run jubarte --help for author/date stamping, --detail-threshold, and
--powertools-faithful (classic PowerTools-compatible mode).
Library surface
| API | Purpose |
|---|---|
document_comparer::compare_documents |
Base + next → redline bytes |
document_comparer::compare_documents_with_settings |
Same with WmlComparerSettings |
document_comparer::get_revisions |
Inspect tracked changes |
document_comparer::accept_revisions / reject_revisions |
Flatten a redline |
convert::docx_to_pdf |
Independent DOCX → PDF (not LibreOffice) |
Feature flags
| feature | default | effect |
|---|---|---|
cli |
yes | builds the jubarte binary (clap) |
fast-alloc |
yes | CLI uses mimalloc (performance only; no semantic change) |
perf-profile |
no | diagnostic stage timers — never for publishable wall-time claims |
MSRV: Rust 1.88 (edition 2024).
How it compares
Both documents are atomized (runs, paragraph marks, table cells, …), aligned
with an LCS pass, and re-expressed as Word revision markup on the original
package. Default mode adds Word-visual alignment on top of the PowerTools
algorithm; WmlComparerSettings::powertools_faithful() / --powertools-faithful
reproduces classic PowerTools behavior.
Benchmarks (Word oracle + large-N speed)
Independent measurements on
neurotic_docx_bench
(LibreOffice-rendered PDFs vs a committed Microsoft Word redline oracle).
Higher fidelity = closer to Word. Numbers below are the full 763-document
corpus (not a curated subset). Full tables: that repo’s RESULTS.md /
docs/SPEED.md. Snapshot: v0.7.0.
Fidelity — script_redlines (0–100 vs Word), full 763-doc corpus
Head-to-head against the strongest competitor, same corpus and renderer:
| vendor | mean | median | docs ≥ 90 | generation failures | n |
|---|---|---|---|---|---|
| jubarte-rust 0.7.0 (this engine) | 83.27 | 91.67 | 403 | 0 | 763 |
| docxodus 9.0.0 | 80.55 | 91.19 | 392 | 4 | 763 |
jubarte leads every headline fidelity metric on the whole corpus, with zero generation failures. Native ≡ WASM: builds from the same source commit produce identical per-document scores. (0.7.0’s performance changes are output-identical to 0.6.0 — see below — so the fidelity numbers are unchanged by the speed work.)
Speed — redline generation, warm inproc (fair algorithm lane)
As of 0.7.0, jubarte wins every speed measure against docxodus 9.0.0. Measured interleaved — both engines on the same document pair back-to-back, so concurrent machine load hits both equally (the only load-fair method) — over the 4880 pairs both engines complete:
| speed measure | jubarte 0.7.0 | docxodus 9.0.0 |
|---|---|---|
| median / doc | 5.3 ms | 7.2 ms |
| mean / doc | 22.2 ms | 24.1 ms |
| p95 / doc | 94.8 ms | 96.2 ms |
| p99 / doc | 139.7 ms | 179.9 ms |
| throughput | 45.0 /s | 41.4 /s |
| generation failures | 0 | 120 |
Six for six. Every one of 0.7.0’s speed changes is byte-for-byte output-identical to 0.6.0 (verified by LibreOffice render parity, XML c14n equivalence, and LCS fuzz/collision tests) — no fidelity was traded for speed.
Non-visual benches (same engine): accepted_changes mean 89.45 / median 99.75,
roundtrip 99.17 / 100.00.
In-repo microbenches
Criterion suites over representative pairs live in
benches/redline.rs:
See also docs/SPEED_REVIEW.md and
WASM_PERF_PLAN.md.
Safety, coverage, and supply chain
| check | how |
|---|---|
No unsafe |
[lints.rust] unsafe_code = "deny" in Cargo.toml — the library and CLI are safe Rust |
| Clippy | cargo clippy --all-targets --all-features -- -D warnings (CI) |
| fmt | cargo fmt --check (CI) |
| Tests | cargo test --all-features on Linux, macOS, Windows (CI) |
| MSRV | cargo check on 1.88 (CI) |
| cargo-deny | advisories + license allowlist (deny.toml) |
| REUSE | SPDX headers + REUSE.toml (CI workflow) |
| Coverage | Codecov on main (badge above); local: cargo llvm-cov --all-features |
| Publish dry-run | cargo publish --dry-run (CI) |
Security reports: prefer a private channel to contact@arthur.law or a GitHub
security advisory on this repository. Do not open public issues for unfixed
vulnerabilities.
Validity rings (Word-valid output)
| Ring | What | When |
|---|---|---|
| 1 | Rust-native package invariants (tests/common/validity.rs) |
every cargo test |
| 1½ | Schema-consistency oracle (tests/schema_consistency.rs) |
every cargo test |
| 2 | OpenXmlValidator sweep + ratchet (tools/validate-docx, tools/validity_baseline.tsv) |
before bench-pin promotion |
| 3 | Real Microsoft Word open probe (scripts/word-open-probe.sh) |
before release / pin promotion (macOS) |
A bench pin without validator: baseline-clean and word-probe: N/N OPENED is
not promotable. See VERSIONING.md and
docs/bench_classes.md.
Layout
src/
lib.rs — public crate root (`jubarte`)
document_comparer.rs — compare / accept / reject / get_revisions
comparer/ — atomize, LCS, produce, tables, notes, …
bin/jubarte.rs — CLI
benches/redline.rs — Criterion
jubarte-wasm/ — wasm-bindgen adapter → npm `jubarte-wasm` (full + slim builds)
jubarte-python/ — PyO3/maturin adapter → PyPI `jubarte-redlines`
jubarte-rust-inproc/ — long-lived stdin worker (fair speed lane)
tests/ — integration + goldens
tools/ — validate-docx, parity, perf harnesses
Known issues
Open engine defects and unresolved Word-behavior conflicts:
KNOWN_ISSUES.md. Covering tests are #[ignore] and run with
cargo test -- --ignored.
Provenance & attribution
The comparison engine is historically informed by the WmlComparer /
DocumentComparer path from Docxodus, itself
a fork of Microsoft’s
Open-Xml-PowerTools.
Original MIT texts are preserved as attribution records — see
LICENSES.md. They do not relicense this repository.
License
GNU Affero General Public License v3.0 (AGPL-3.0-only).
LICENSE is the repository’s only project license.
Copyright (c) 2026 Jandira Technologies, LLC for its contributions.
Find us
jandira.tech · arthur.law ·
Cicero · LinkedIn ·
contact@arthur.law