| name | md-to-docx-converter |
| description | Convert markdown documents to professionally formatted Word (.docx) files using Python and python-docx. The skill parses the markdown into sections, creates a JSON file with all section values, then substitutes {{Placeholder}} tokens in a Word (.docx/.dotx) template with the JSON values. Use when user requests to convert markdown to Word, create a docx from markdown, generate a release note document, export markdown as Word, or apply template to markdown conversion. Trigger phrases include "convert markdown to docx", "export md to Word", "generate release note from markdown", "create Word document from markdown", "convert to docx with template", "apply template to markdown", or when working with markdown files that need to be delivered as formatted Word documents. |
Markdown to DOCX Converter with Template (Python)
Overview
Converts markdown (.md) files to professionally formatted Word documents (.docx) using Python and the python-docx library. The conversion pipeline works in three stages:
- Parse the markdown file into named sections (metadata fields + H2 body sections)
- Generate a JSON file containing all extracted sections as key-value pairs
- Substitute
{{Placeholder}} tokens in the Word template with the corresponding JSON values
The conversion is only considered complete when the custom template is applied and all placeholders are substituted. The template ensures consistent branding, styles, headers, footers, and formatting across all generated documents.
Prerequisites
Quick Start
Step 0: Install Python Dependencies
pip install -r .github\skills\md-to-docx-converter\scripts\requirements.txt
Step 1: List Available Templates
python .github\skills\md-to-docx-converter\scripts\convert_md_to_docx.py --list-templates
This will display all available templates in the examples/ folder with their index numbers.
Step 2: Run the Converter with a Selected Template
python .github\skills\md-to-docx-converter\scripts\convert_md_to_docx.py "docs\releasenotesmd\Release_Note_DSD-1234_Test_Customer_123456.md" --template 1
This will:
- Parse the markdown into sections
- Create a
.json file alongside the output with all section values
- Open the selected template, replace all
{{Placeholder}} tokens, and save the .docx
How the Pipeline Works
Field Map Configuration
The converter uses a shared field map configuration at:
.github/skills/shared/field-map.json
This JSON file is the single source of truth for all field mappings between the markdown, JSON, and Word template. It defines:
header — The H1 field (e.g., ClientName from # Release Note – [value])
metadataFields — Array of metadata table fields with key, label, format, and default properties
sections — Array of H2 body sections with key and heading properties
The converter dynamically loads this config at runtime. If the config is not found, it falls back to built-in defaults.
To add new fields: Simply add an entry to field-map.json — no code changes required. See Adding New Fields below.
Stage 1: Parse Markdown → Sections Dict
The script reads the markdown and extracts fields based on the field map:
| Source | JSON Key | Driven By |
|---|
# Release Note – [Client] (H1) | header.key | field-map.json → header |
Metadata table rows | **Label** | Value | | metadataFields[].key | field-map.json → metadataFields |
## Heading sections | PascalCase of heading | field-map.json → sections + auto-detected |
Any ## Heading in the markdown that is NOT in the field map is still captured automatically using a PascalCase key derived from the heading text.
Stage 2: Write JSON File
A JSON file is created next to the output .docx with the same base name:
{
"ClientName": "Test Customer 123456",
"CCNNr": "DSD-1234",
"IssueNr": "I5432",
"Version": "1.0.0.0",
"Date": "09/02/2026",
"Title": "BC Dataverse Integration Template",
"ReleasedBy": "Dynavics",
"ChangeRequestDetails": "Implementation of the BC Dataverse...",
"TestingSetup": "- Business Central SaaS sandbox...",
"TestingSteps": "1. Open the **CDS Countries** list page..."
}
Stage 3: Substitute Placeholders in Template
The script opens the .dotx/.docx template and searches for {{Key}} placeholders in:
- Body paragraphs (all runs are joined, substituted, then rewritten)
- Body tables (every cell in every row, including nested tables)
- Headers and footers (all section headers/footers including first-page and even-page variants)
Each {{Key}} token is replaced with the value from the JSON sections dict. If a key is not found in the JSON, the placeholder is left unchanged.
Placeholder Format
Placeholders in the template must use double curly braces with the exact PascalCase key name:
{{ClientName}} → "Test Customer 123456"
{{CCNNr}} → "DSD-1234"
{{IssueNr}} → "I5432"
{{Version}} → "1.0.0.0"
{{Date}} → "09/02/2026"
{{Title}} → "BC Dataverse Integration Template"
{{ReleasedBy}} → "Dynavics"
{{ChangeRequestDetails}} → Full section content
{{TestingSetup}} → Full section content
{{TestingSteps}} → Full section content
CRITICAL: Template Selection Requirement
A conversion without the template applied is NOT a finished conversion.
Multiple template files can exist in the skill's examples/ folder at:
.github/skills/md-to-docx-converter/examples/
Before running the conversion, the AI agent MUST:
- List available templates by running:
python .github\skills\md-to-docx-converter\scripts\convert_md_to_docx.py --list-templates
- Ask the user which template to use — present the available templates as options and let the user select one
- Run the conversion with the selected template using
--template <number> or --template "<name>"
If only one template exists, the script auto-selects it and no prompt is needed.
Each template must contain {{Placeholder}} tokens that match the keys extracted from the markdown. Templates provide:
- Corporate heading styles and fonts
- Page layout, margins, and orientation
- Header and footer formatting
- Table styles and list formatting
- Cover page and section break styles
- Pre-positioned
{{Placeholder}} tokens for dynamic content
Without a template, the conversion will fail.
Markdown Structure Requirements
The markdown must follow this structure for proper conversion:
# Release Note – [Client Name]
| Field | Value |
|-------|-------|
| **CCN Nr.** | DSD-XXXX |
| **Issue Nr.** | IXXXX |
| **Version** | X.X.X.X |
| **Date** | DD/MM/YYYY |
| **Title** | Description |
| **Released By** | Author |
---
## Change Request Details
Content here...
---
## Testing Setup
Content here...
---
## Testing Steps
Content here...
Core Workflow
The conversion follows these steps:
Step 1: Validate Inputs
Step 2: Parse Markdown and Generate JSON
- Parse the markdown file extracting H1 client name, metadata table fields, and H2 section bodies
- Write the sections dict to a
.json file alongside the output
Step 3: Substitute Placeholders in Template
- Open the template with
python-docx
- Walk all paragraphs, tables, headers, and footers
- Replace every
{{Key}} placeholder with the corresponding value from the JSON
- Save the result as
.docx
Step 4: Verify Output
- Confirm the
.docx file was created
- Confirm file size is reasonable (template-styled docs are larger than empty documents)
- Report output file location to the user
Step 5: Report Completion
Only report the conversion as complete after confirming:
- The
.docx file exists
- The
.json file was created with all sections
- Template placeholders were substituted
- No errors occurred during conversion
Usage Examples
Example 1: List available templates
python .github\skills\md-to-docx-converter\scripts\convert_md_to_docx.py --list-templates
Output:
Available templates:
1. TEMPLATE_1_Release Note_DSD-xxx.docx (58.8 KB)
2. TEMPLATE_2_Release Note_DSD-xxx.docx (60.2 KB)
Use --template <number> or --template "<name>" to select a template.
Example 2: Convert using a template by number
python .github\skills\md-to-docx-converter\scripts\convert_md_to_docx.py ^
"docs\releasenotesmd\ReleaseNote_v2.0.md" ^
--template 1
Example 3: Convert using a template by name
python .github\skills\md-to-docx-converter\scripts\convert_md_to_docx.py ^
"docs\releasenotesmd\ReleaseNote_v2.0.md" ^
--template "TEMPLATE_1_Release Note_DSD-xxx.docx"
Example 4: Convert with explicit template path
python .github\skills\md-to-docx-converter\scripts\convert_md_to_docx.py ^
"docs\releasenotesmd\ReleaseNote_v2.0.md" ^
--template "path\to\custom_template.dotx"
Example 5: Convert with custom output path
python .github\skills\md-to-docx-converter\scripts\convert_md_to_docx.py ^
"README.md" ^
--template 1 ^
--output "docs\README_formatted.docx"
Example 6: Convert and open automatically
python .github\skills\md-to-docx-converter\scripts\convert_md_to_docx.py ^
"docs\releasenotesmd\ReleaseNote_v2.0.md" ^
--template 1 --open
Example 7: Batch convert all markdown files in a folder
Get-ChildItem ".\docs\releasenotesmd\*.md" | ForEach-Object {
python ".github\skills\md-to-docx-converter\scripts\convert_md_to_docx.py" $_.FullName --template 1
}
Script Parameters
markdown_path (positional, required for conversion)
Path to the markdown file to convert.
Not required when using --list-templates.
--template <path|number|name>
Template to use for conversion. Accepts:
- A number (1, 2, ...) matching the index from --list-templates
- A template file name from the examples folder
- A full file path to any .dotx/.docx template
Default: Auto-selected if only one template exists in the examples folder.
--output <path>
Custom output .docx file path (optional).
Default: Same folder and name as input with .docx extension.
Special: If input is in a "releasenotesmd" folder, output goes to a "releasenotesdocx" sibling folder.
--open
Open the generated .docx file after conversion.
Default: false
--list-templates
List all available templates in the examples folder and exit.
Does not require markdown_path.
Generated Files
For each conversion, two output files are produced:
| File | Description |
|---|
<name>.docx | The final Word document with template styles and substituted content |
<name>.json | The intermediate JSON file with all parsed sections (useful for debugging or re-processing) |
Adding New Fields
To add new fields to the entire pipeline (markdown → JSON → DOCX), update these three files:
1. Update the shared field map
Edit .github/skills/shared/field-map.json:
For a new metadata table field (appears in the | Field | Value | table):
{
"key": "ApprovedBy",
"label": "Approved By",
"required": true,
"format": "text",
"default": null,
"autoPopulate": null
}
Add this to the metadataFields array.
For a new body section (appears as a ## Heading):
{
"key": "DeploymentNotes",
"heading": "Deployment Notes",
"required": false,
"description": "Special deployment instructions"
}
Add this to the sections array.
2. Update the markdown template
Edit .github/skills/bc-release-note-generator/assets/release-note-template.md:
For metadata fields: Add a row to the table:
| **Approved By** | {{APPROVED_BY}} |
For body sections: Add a new section:
---
## Deployment Notes
{{DEPLOYMENT_NOTES}}
3. Update the Word template(s)
Add a {{ApprovedBy}} or {{DeploymentNotes}} placeholder in the Word template(s) at .github/skills/md-to-docx-converter/examples/.
No code changes are required in either skill. The converter dynamically loads the field map and the release note generator references it through the SKILL.md instructions.
Adding New Metadata Fields
See Adding New Fields above. The process is:
- Add the field to
field-map.json → metadataFields
- Add the row to the markdown template
- Add the
{{Key}} placeholder to the Word template
Error Handling
| Error | Cause | Solution |
|---|
| "python-docx is not installed" | python-docx library not available | Run pip install python-docx or pip install -r .github\skills\md-to-docx-converter\scripts\requirements.txt |
| "Template file not found" | Template missing from skill examples folder | Ensure TEMPLATE_Release Note_DSD-xxx.dotx exists in .github/skills/md-to-docx-converter/examples/ |
| "Markdown file not found" | Invalid input path | Check the file path and try again |
Troubleshooting
python-docx is not installed
If you receive the error "python-docx is not installed":
-
Install the dependency:
pip install -r .github\skills\md-to-docx-converter\scripts\requirements.txt
or directly:
pip install python-docx
-
Verify the installation:
python -c "import docx; print('python-docx is installed')"
-
Retry the conversion
Template path has spaces
Ensure the path is quoted. The template filename contains spaces, so always wrap it in quotes when passing as an argument.
Integration with Other Skills
Common workflow - Release Note generation:
- Write release notes in markdown format
- Use
md-to-docx-converter to produce the formatted Word document with corporate template
- Result: Professional, template-styled
.docx ready for distribution
PDF text to formatted Word:
- Use
pdf-text-extractor to extract PDF content to markdown
- Use
md-to-docx-converter to convert to styled Word document