Convert Microsoft Word .docx files into near-1:1, human-readable Markdown
optimized for Azure DevOps wiki rendering.
- One primary
.mdoutput file per conversion - Optional sibling assets directory (only created when the document contains images)
- Relative asset references — output is portable into a wiki repo as-is
- Standard Markdown preferred; selective embedded HTML only where Markdown cannot represent the structure (complex tables, underline, sub/superscript)
- Deterministic: same input + options → byte-identical output
- Fully local; no network access during conversion
Requires Python 3.10+. No system Pandoc install needed — the
pypandoc-binary dependency bundles a pandoc executable.
pip install . # from a clone of this repository
# development (tests + fixture generation):
pip install -e .[dev]docx2md input.docx # writes input.md next to the source
docx2md input.docx -o wiki/Page.md # explicit output path
docx2md input.docx -o Page.md --assets-dir Page-images
docx2md input.docx --verbose # diagnostic mode
docx2md --helpExit codes: 0 success (including success with warnings), 1 invalid
invocation (missing/unsupported input, bad options), 2 hard conversion
failure (corrupt document, engine failure).
Warnings are printed to stderr only when conversion loss materially affects readability or meaning; minor formatting (colors, highlights, image sizing, page breaks) degrades quietly.
| Word construct | Markdown output |
|---|---|
| Title style | # H1 heading |
| Heading 1–6 | #–###### |
| Automatic section numbering on headings | literal numbers injected (## 1.2 Scope) |
| Bold / italic / strikethrough | ** / * / ~~ |
| Underline, superscript, subscript | <u>, <sup>, <sub> (rendered by ADO) |
| Hyperlinks | [text](url) |
| Ordered/unordered lists incl. nesting | nested Markdown lists |
| Simple tables | pipe tables |
| Tables with merged cells / multi-paragraph cells | embedded HTML <table> |
| Images | extracted to <output>-assets/, referenced relatively |
| Image captions | image + italic caption line |
| Monospace-font paragraphs (Consolas, Courier New, …) | code blocks, indentation preserved |
| Monospace runs inside text | `inline code` |
| "Source Code" / "Verbatim Char" styled content | code blocks / inline code (native pandoc) |
- Style-only lists: lists built purely from "List Bullet 2"-type styles with no Word numbering definitions do not recover nesting (real Word documents use numbering definitions, which convert correctly).
- Image sizing is dropped; images render at natural size.
- Highlighting, font colors, alignment, page breaks degrade quietly to plain text/flow.
- Tracked changes, comments, text boxes, floating layout objects, headers/ footers, and footnote-heavy layouts are out of scope per the SRS exclusions.
- No legacy
.docinput;.docxonly. - Local CLI only; no hosted service, no Markdown→Word reverse conversion.
Engineering records (implementation plan, decision log, verification evidence, requirements coverage): docs/engineering/
pip install -e .[dev]
python scripts/make_fixtures.py # regenerate deterministic .docx fixtures
pytest # 51 tests: unit + integration + goldenGolden outputs live in tests/golden/. If an intentional output change
occurs, regenerate them with the CLI and review the diff.