Adeu: Python Toolchain & MCP Server
This directory contains the core Python implementation of Adeu. It provides the core Redline Engine, the developer SDK, the command-line interface (CLI), and the FastMCP server backend.
Adeu acts as a "Virtual DOM" for Microsoft Word. It translates complex DOCX XML into token-efficient CriticMarkup for LLMs, validates structural edits, and patches the XML safely to preserve document formatting, metadata, and styles. On Windows, it also interfaces directly with live Microsoft Word instances via COM.
Local Development Setup
Adeu is managed using uv and packaged via hatchling. It requires Python 3.12 or higher.
# Clone and enter the directory
cd python
# Install dependencies and sync the virtual environment
uv sync
# Run the test suite
uv run pytest
The Command Line Interface (CLI)
The adeu CLI provides a powerful suite of tools for interacting with documents locally.
Extraction & Reading
Extract text as CriticMarkup. Use --clean-view to simulate "Accept All Changes".
# Extract full text
uvx adeu extract contract.docx -o output.md
# Extract only the structural heading outline
uvx adeu extract contract.docx --mode outline
# Strip navigation prose and headers for raw token efficiency
uvx adeu extract contract.docx --no-chrome
# Windows Only: Extract text from the actively open Word document
uvx adeu extract --live
Diffing
Generate a word-level patch diff between two document versions.
# Compare two DOCX files
uvx adeu diff original.docx modified.docx
# Output raw JSON edits for programmatic use
uvx adeu diff original.docx modified.docx --json
Applying Edits
Apply a JSON array of DocumentChange objects (or a modified markdown file) back to the DOCX.
# Apply a JSON batch of edits to a file
uvx adeu apply original.docx edits.json --author "AI Reviewer" -o redlined.docx
# Emit the batch result as machine-readable JSON on stdout (for agents/scripts)
uvx adeu apply original.docx edits.json --json
# Partial salvage mode: apply valid edits while reporting failing edits
uvx adeu apply original.docx edits.json --partial
# Terse error context: produce compact error messages
uvx adeu apply original.docx edits.json --terse-errors
# Windows Only: Apply edits directly to the live, open Word canvas
uvx adeu apply edits.json --live
Accepting All Changes
Accept every tracked change in one operation, producing a finalized clean document. Mirrors the accept_all_changes MCP tool — including its default.
Comment removal is ON by default (--remove-comments): the output is meant to be distributable, and comments are internal review notes that must not travel to a counterparty. Use --no-remove-comments when the review conversation is still live.
# Writes contract_clean.docx next to the input; comments are DELETED
uvx adeu accept-all contract.docx
# Accept the tracked changes but keep the comments
uvx adeu accept-all contract.docx --no-remove-comments
# Explicit output path, machine-readable result on stdout
uvx adeu accept-all contract.docx -o final.docx --json
Every deleted comment is reported by id and author (removed_comment_details under --json). A comment whose anchored text an accepted deletion consumes is removed either way — Word does the same.
The library API is the other way round:
RedlineEngine.accept_all_revisions()defaults toremove_comments=False, because an SDK caller composing their own pipeline should not lose annotations implicitly.
Sanitization
Strip sensitive metadata, hidden text, and author names before external distribution.
# Full scrub (fails if unresolved track changes exist unless --accept-all is passed)
uvx adeu sanitize contract.docx --accept-all -o clean.docx
# Keep your redlines/comments, but anonymize the author and strip metadata
uvx adeu sanitize redline.docx --keep-markup --author "My Firm"
JSON-Lines Daemon (adeu serve)
For high-throughput local agent drivers or CI harnesses, run adeu serve to maintain a warm process and document cache over stdin/stdout JSON-Lines:
uv run adeu serve
Agentic / Headless Usage (the CLI as an API)
When an agent operates in a closed sandbox (a CI pipeline, a containerized coding agent) it cannot reach an MCP server. The CLI is the fallback: a strictly local, air-gapped command-line API that accepts the same JSON change schema as the MCP tools. The mapping is 1:1:
| MCP tool | CLI equivalent |
|---|---|
read_docx |
adeu extract <doc> [--json] |
diff_docx_files |
adeu diff <orig> <mod> [--json] |
process_document_batch |
adeu apply <doc> <changes.json> [--json] |
accept_all_changes |
adeu accept-all <doc> [--json] |
The I/O contract (see docs/cli-agent-spec.md for the full specification):
- stdout carries only document data (Markdown/CriticMarkup) or, with
--json, a machine-readable JSON result.uvx adeu extract doc.docx > out.mdalways produces a clean file, even with--debug. - stderr carries all logs, progress messages, warnings, and errors.
- Exit codes:
0= success (in--partialmode, at least one edit applied; checkedits_skippedin JSON stats to detect skipped edits)1= failure (in atomic mode, if any edit fails; in--partialmode, if all edits fail)
adeu apply --json prints the engine's raw stats object — edits_applied, edits_skipped, per-edit reports with CriticMarkup previews, plus output_path — and suppresses the human-readable logs. A batch that fails validation prints {"error": "batch_validation_failed", "errors": [...]} and exits 1.
The Python SDK
The SDK allows you to embed Adeu's Redline Engine directly into your own Python applications.
Applying Tracked Changes
The engine processes a flat list of DocumentChange objects (ModifyText, AcceptChange, RejectChange, ReplyComment, InsertTableRow, DeleteTableRow).
from io import BytesIO
from adeu import RedlineEngine, ModifyText, AcceptChange
# 1. Load the document stream
with open("contract.docx", "rb") as f:
stream = BytesIO(f.read())
# 2. Define your edits
changes = [
ModifyText(
target_text="State of New York",
new_text="State of Delaware",
comment="Standardized jurisdiction.",
match_mode="all"
),
AcceptChange(target_id="Chg:12")
]
# 3. Initialize the engine and apply
engine = RedlineEngine(stream, author="AI Copilot")
stats = engine.process_batch(changes)
# 4. Save the result
with open("contract_redlined.docx", "wb") as f:
f.write(engine.save_to_stream().getvalue())
Extracting Text
Read a document into CriticMarkup representation.
from io import BytesIO
from adeu import extract_text_from_stream
with open("contract.docx", "rb") as f:
stream = BytesIO(f.read())
# Extract raw text with {++ ++} and {-- --} tags intact
markdown_text = extract_text_from_stream(stream)
# Extract clean text simulating "Accept All Changes"
clean_text = extract_text_from_stream(stream, clean_view=True)
Sanitizing Documents
Run the metadata scrubber programmatically.
from adeu.sanitize import sanitize_docx
result = sanitize_docx(
input_path="draft.docx",
output_path="final.docx",
keep_markup=True,
author="Legal Team"
)
print(result.report_text)
The MCP Server
The Python backend exposes Adeu's capabilities to AI agents via the Model Context Protocol (MCP), powered by FastMCP.
Running the Server
You can boot the server over stdio for agent consumption:
uvx --from adeu adeu-server
Claude Desktop Integration
Adeu provides an initialization command to automatically inject the MCP server into your local Claude Desktop configuration.
# Installs to Claude Desktop using the global uvx path
uvx adeu init
# Local Developer Mode: Configures Claude to run the server from your current source tree
uv run adeu init --local
Live Word Interop (Windows COM)
When the MCP server runs on Windows (sys.platform == 'win32'), it automatically enables the live_word.py tools. These tools utilize pywin32 to hijack the active Microsoft Word COM object.
If an agent leaves the file_path argument empty when calling read_docx or process_document_batch, the server will automatically target the document that the user currently has open on their screen.
Testing & Architectural Constraints
When developing inside the python/ directory, please note the following invariants:
- Surgical Mode: The
RedlineEnginenever performs global document normalization on load or save. This strict behavior prevents the silent destruction of unrelated metadata (like<w:proofErr>) and minimizes XML diff noise. - COM Teardown: In
live_word.pyand its associated tests, we intentionally omitpythoncom.CoUninitialize()andapp.Quit()during teardown. FastMCP andpytesthold proxies unpredictably: forcing teardown causes fatal RPC Access Violations (0x800706be). We let the OS handle the apartment lifecycle. - Testing Asserts: Native
python-docxParagraph.textproperties silently ignore text inside<w:ins>tags. When writing tests to verify redlines, strictly useextract_text_from_stream(clean_view=True)to accurately evaluate the accepted text state.
Environment Variables
| Variable | Description | Default |
|---|---|---|
ADEU_DOC_CACHE_ENTRIES |
Capacity for in-memory parsed document LRU cache | 3 |
ADEU_NO_CACHE |
Set to 1 or true to disable disk-level projection caching |
0 |
ADEU_CACHE_DIR |
Custom storage directory for disk projection cache | OS cache dir |
ADEU_AUTHOR |
Fallback author name for tracked changes when unspecified | OS username (fallback: Adeu AI) |
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file adeu-2.4.1.tar.gz.
File metadata
- Download URL: adeu-2.4.1.tar.gz
- Upload date:
- Size: 858.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d5b5396f7194f7b5545aad1613f605f91622a6011cc73b66d0c8b9a9c1544a57
|
|
| MD5 |
6070feee73c2a5a074ee92c0d51706b8
|
|
| BLAKE2b-256 |
d51fd0bc1a953584617b58eb47681fdca703e7940d2aa8020094a03be31b8595
|
Provenance
The following attestation bundles were made for adeu-2.4.1.tar.gz:
Publisher:
release.yml on dealfluence/adeu
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
adeu-2.4.1.tar.gz -
Subject digest:
d5b5396f7194f7b5545aad1613f605f91622a6011cc73b66d0c8b9a9c1544a57 - Sigstore transparency entry: 2501175728
- Sigstore integration time:
-
Permalink:
dealfluence/adeu@b75a13004e2bec0cf2d7ac19772f7366161f257a -
Branch / Tag:
refs/tags/v2.4.1 - Owner: https://github.com/dealfluence
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b75a13004e2bec0cf2d7ac19772f7366161f257a -
Trigger Event:
release
-
Statement type:
File details
Details for the file adeu-2.4.1-py3-none-any.whl.
File metadata
- Download URL: adeu-2.4.1-py3-none-any.whl
- Upload date:
- Size: 363.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c7459e6524ae5c3622a5393700316f80bc4dcbeac5339d0571591ee898a6c530
|
|
| MD5 |
68fee3342f78a7e4e4c2318d581ffb95
|
|
| BLAKE2b-256 |
a1ff14d21b1a1a152890636f9772e4f67061b048c5b64d22c5ca66298d1a5044
|
Provenance
The following attestation bundles were made for adeu-2.4.1-py3-none-any.whl:
Publisher:
release.yml on dealfluence/adeu
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
adeu-2.4.1-py3-none-any.whl -
Subject digest:
c7459e6524ae5c3622a5393700316f80bc4dcbeac5339d0571591ee898a6c530 - Sigstore transparency entry: 2501175731
- Sigstore integration time:
-
Permalink:
dealfluence/adeu@b75a13004e2bec0cf2d7ac19772f7366161f257a -
Branch / Tag:
refs/tags/v2.4.1 - Owner: https://github.com/dealfluence
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b75a13004e2bec0cf2d7ac19772f7366161f257a -
Trigger Event:
release
-
Statement type: