003 - convert command
Purpose: mdd convert recursively converts .docx files to Markdown (.docx.md) using Docling for body content and python-docx for metadata extraction.
Status: Implemented (2026-05-07)
Ported from lsimons-auto spec-019 (md action). See that spec for full algorithm detail.
Requirements
Section titled “Requirements”mdd convert <path>walks<path>, writes<original>.docx.mdin-place--dest-dir <dir>mirrors source tree into<dir>- Incremental: skip files whose
.mdis newer than the.docx(unless--force) --dry-runprints what would be converted without writing--file <path>converts a single file regardless of extension- Progress printed per file:
[N/M] Converting: <relpath> - Non-zero exit if any conversion fails; continues and reports all failures
Design Approach
Section titled “Design Approach”- Registered in
src/mdd/commands/convert.pyvia theregister(subparsers, parents)convention defined in S35; the pre-S35cmd_convert(args)shape has been superseded. extract_title,extract_metadatause python-docx;convert_bodyuses Docling- Docling
DocumentConverterinstantiated once per invocation (singleton) - Atomic write: write to
.md.tmp, then rename. The writer refuses to write through a symlink at the destination, at the.md.tmpsibling, or at the<name>-attachments/directory; the conversion fails instead of following the link. - The output base the operator names (
--dest-dir, or the source directory for in-place output) is trusted and may itself be a symlink. Every directory mdd creates or writes into below it (mirrored sub-directories,<name>-attachments/) must be a real directory; a symlink there fails that file’s conversion. Converters take the base as arootargument for this. - The directory walk skips symlinked entries with a warning, so a symlinked
.docx/.pptx/.pdfin the tree is not read. A file named directly (positional file argument or--file) is operator-chosen: it is followed even when it is a symlink, with a warning.
Implementation Notes
Section titled “Implementation Notes”- Dependencies:
docling>=2,python-docx>=1
House-template metadata output format
Section titled “House-template metadata output format”- Multi-person fields (Participants, Invitees, Absent): nested bullet list
- Single-value meeting fields (Location):
- **Key:** Value - Document-meta fields (For, Date, Author, Status):
- Key: Value(no bold)
Post-processing (in order)
Section titled “Post-processing (in order)”html.unescape()- Strip Word-generated TOC
- Strip empty/artifact headings
- Strip boilerplate sections (Meeting Logistics)
- Strip boilerplate lines (JIRA board bullet)
Site built 2026-10-26.