Command-line tool for converting CommonMark markdown files to Microsoft Word (.docx) documents with syntax highlighting and Mermaid diagram support. Part of the MarkMyWord library suite.
$ dotnet add package SpecWorks.MarkMyWord.CLIA .NET 9 library for bidirectional conversion between CommonMark/GitHub Flavored Markdown and Microsoft Word (.docx) documents.
MarkMyWord provides bidirectional conversion between Markdown and Word:
✅ Block Elements
# H1 through ###### H6, Setext: underlined)>)---, ***, ___)✅ Inline Elements
**text** or __text__)*text* or _text_)***text***)`code`)[text](url)) - supports local files and URLs with fallback)\ at end of line)✅ Styling
✅ Supported Elements
# through ######)**bold**, *italic*)`code`)[text](url) syntax with optional extraction```> prefix✅ Conversion Options
dotnet add package MarkMyWord
using MarkMyWord;
// Convert markdown string to .docx file
string markdown = "# Hello World\n\nThis is **bold** text.";
MarkdownConverter.ConvertToDocx(markdown, "output.docx");
using MarkMyWord;
using MarkMyWord.Configuration;
// Convert Word document to markdown file
WordConverter.ConvertToMarkdown("input.docx", "output.md");
// With options for LLM grounding
var options = new WordToMarkdownOptions
{
Flavor = MarkdownFlavor.GitHubFlavoredMarkdown,
OptimizeForLLM = true,
ExtractImages = true,
IncludeMetadata = false
};
WordConverter.ConvertToMarkdown("document.docx", "output.md", options);
// Convert to string
string markdown = WordConverter.ConvertToMarkdownString("document.docx");
// Get the document as a byte array (useful for web scenarios)
byte[] docxBytes = MarkdownConverter.ConvertToDocxBytes(markdown);
// Convert from stream to stream
using var inputStream = File.OpenRead("input.md");
using var outputStream = File.Create("output.docx");
MarkdownConverter.ConvertToDocx(inputStream, outputStream);
// Async conversion
await MarkdownConverter.ConvertToDocxAsync(markdown, "output.docx");
// Unordered list
string unorderedList = @"
# Shopping List
- Apples
- Bananas
- Oranges
- Naval oranges
- Blood oranges
";
MarkdownConverter.ConvertToDocx(unorderedList, "shopping.docx");
// Ordered list
string orderedList = @"
# Instructions
1. Preheat oven to 350°F
2. Mix ingredients
3. Bake for 30 minutes
1. Check at 25 minutes
2. Test with toothpick
4. Let cool
";
MarkdownConverter.ConvertToDocx(orderedList, "instructions.docx");
MarkMyWord includes a powerful CLI for converting markdown files from the command line.
dotnet tool install --global SpecWorks.MarkMyWord.CLI
Or run directly from the project:
dotnet run --project src/MarkMyWord.CLI/MarkMyWord.CLI.csproj -- [command] [options]
The CLI automatically detects the conversion direction based on file extension:
.md or .markdown input → converts to Word (.docx).docx input → converts to Markdown (.md)Markdown to Word:
markmyword convert -i README.md
markmyword convert -i input.md -o output.docx
Word to Markdown:
markmyword convert -i document.docx
markmyword convert -i input.docx -o output.md
Specify output file:
markmyword convert -i input.md -o output.docx
Custom font and size:
markmyword convert -i document.md --font "Times New Roman" --font-size 12
Use custom style configuration:
markmyword convert -i document.md --style custom-style.json
Verbose output:
markmyword convert -i document.md -v
Force overwrite:
markmyword convert -i document.md --force
Word to Markdown with options:
# Convert Word to GitHub Flavored Markdown (default)
markmyword convert -i document.docx -o output.md
# Convert to strict CommonMark
markmyword convert -i document.docx --commonmark
# Optimize for LLM grounding (clean, semantic output)
markmyword convert -i document.docx --optimize-llm
# Include document metadata as YAML frontmatter
markmyword convert -i document.docx --include-metadata
# Don't extract images
markmyword convert -i document.docx --extract-images false
View version:
markmyword version
Get help:
markmyword --help
markmyword convert --help
| Option | Alias | Description |
|---|---|---|
--input | -i | Input file path (.md or .docx) (required) |
--output | -o | Output file path (auto-detects extension) |
--verbose | -v | Enable verbose output |
--force | - | Overwrite output file if it exists |
| Option | Alias | Description |
|---|---|---|
--font | -f | Default font name (e.g., 'Calibri') |
--font-size | -s | Default font size (6-72 points) |
--style | - | Path to JSON style configuration file |
| Option | Description | Default |
|---|---|---|
--to-markdown | Explicitly convert to Markdown (auto-detected) | false |
--extract-images | Extract and save embedded images | true |
--optimize-llm | Optimize output for LLM grounding | true |
--commonmark | Use strict CommonMark instead of GFM | false |
--include-metadata | Include document metadata as YAML frontmatter | false |
using MarkMyWord;
using MarkMyWord.Configuration;
// Configure Word to Markdown conversion
var options = new WordToMarkdownOptions
{
// Use GitHub Flavored Markdown (supports tables, strikethrough, etc.)
Flavor = MarkdownFlavor.GitHubFlavoredMarkdown,
// Optimize for LLM grounding (clean, semantic content)
OptimizeForLLM = true,
// Extract embedded images to files
ExtractImages = true,
// Directory for extracted images (default: same as output file)
ImageOutputDirectory = "./images",
// URL prefix for image links in markdown
ImageUrlPrefix = "https://example.com/images/",
// Include document metadata as YAML frontmatter
IncludeMetadata = true,
// Preserve formatting metadata for roundtripping
PreserveFormattingMetadata = false,
// Use HTML for complex formatting when no markdown equivalent exists
UseHtmlForComplexFormatting = false,
// Line ending style
LineEndings = LineEndingStyle.LF
};
WordConverter.ConvertToMarkdown("document.docx", "output.md", options);
using MarkMyWord.Configuration;
var options = new ConversionOptions
{
Styles = new StyleConfiguration
{
DefaultFontName = "Georgia",
DefaultFontSize = 12,
CodeFontName = "Fira Code",
CodeFontSize = 10,
CodeBackgroundColor = "F5F5F5",
QuoteLeftBorderColor = "4A90E2",
QuoteBackgroundColor = "EEF7FF"
}
};
MarkdownConverter.ConvertToDocx(markdown, "output.docx", options);
var options = new ConversionOptions
{
Styles = new StyleConfiguration
{
HeadingStyles = new[]
{
new HeadingStyle
{
Level = 1,
FontSize = 24,
Bold = true,
Color = "2E74B5",
SpacingBeforeTwips = 480, // 1/3 inch
SpacingAfterTwips = 240 // 1/6 inch
},
// ... configure levels 2-6
}
}
};
You can define styles in a JSON file and load them using the CLI or programmatically:
custom-style.json:
{
"styles": {
"defaultFontName": "Georgia",
"defaultFontSize": 12,
"headingStyles": [
{
"level": 1,
"fontSize": 28,
"bold": true,
"color": "2E74B5",
"spacingBeforeTwips": 480,
"spacingAfterTwips": 240
},
{
"level": 2,
"fontSize": 20,
"bold": true,
"color": "2E74B5",
"spacingBeforeTwips": 400,
"spacingAfterTwips": 200
},
{
"level": 3,
"fontSize": 16,
"bold": true,
"color": "1F4D78",
"spacingBeforeTwips": 320,
"spacingAfterTwips": 160
}
],
"codeFontName": "Fira Code",
"codeFontSize": 10,
"codeBackgroundColor": "282C34",
"quoteLeftBorderColor": "4A90E2",
"quoteLeftBorderWidth": 4,
"quoteBackgroundColor": "EEF7FF",
"listIndentationTwips": 720
}
}
Use with CLI:
markmyword convert -i document.md --style custom-style.json
Load programmatically:
using System.Text.Json;
var json = File.ReadAllText("custom-style.json");
var config = JsonSerializer.Deserialize<ConversionOptions>(json);
MarkdownConverter.ConvertToDocx(markdown, "output.docx", config);
Notes:
# prefixvar options = new ConversionOptions
{
DocumentTitle = "My Document",
Author = "John Doe",
Subject = "Technical Documentation"
};
MarkdownConverter.ConvertToDocx(markdown, "output.docx", options);
MarkMyWord uses a three-stage conversion pipeline:
Markdown Text
↓
Markdig Parser
↓
AST (Syntax Tree)
↓
OpenXmlRenderer
↓
OpenXML Elements
↓
Word Document (.docx)
MarkMyWord/
├── src/
│ ├── MarkMyWord/ # Core library
│ │ ├── MarkdownConverter.cs # Public API
│ │ ├── Converters/
│ │ │ ├── OpenXmlRenderer.cs # Main renderer
│ │ │ ├── BlockRenderers/ # Block element renderers
│ │ │ │ ├── CodeBlockRenderer.cs # Code block rendering
│ │ │ │ ├── ListRenderer.cs # List rendering
│ │ │ │ └── TableRenderer.cs # Table rendering
│ │ │ └── InlineRenderers/ # Inline element renderers
│ │ │ └── LinkInlineRenderer.cs # Links & images
│ │ ├── SyntaxHighlighting/ # Syntax highlighting
│ │ │ ├── ISyntaxHighlighter.cs # Highlighter interface
│ │ │ ├── ColorCodeHighlighter.cs # JSON highlighting
│ │ │ ├── TypeSpecHighlighter.cs # TypeSpec highlighting
│ │ │ ├── BashHighlighter.cs # Bash/Shell highlighting
│ │ │ └── SyntaxHighlighterFactory.cs
│ │ ├── OpenXml/
│ │ │ ├── DocumentBuilder.cs # OpenXML document builder
│ │ │ ├── StyleManager.cs # Style management
│ │ │ └── ListManager.cs # List numbering management
│ │ └── Configuration/ # Configuration classes
│ └── MarkMyWord.CLI/ # Command-line tool
└── tests/
└── MarkMyWord.Tests/ # Unit tests (29 tests)
git clone https://github.com/yourusername/MarkMyWord.git
cd MarkMyWord
dotnet build
dotnet test
var markdown = File.ReadAllText("README.md");
MarkdownConverter.ConvertToDocx(markdown, "README.docx");
string markdown = @"
# Shopping List
## Groceries
- Milk
- Eggs
- Bread
## Tasks
1. Buy groceries
2. Clean house
3. Do laundry
- Whites
- Colors
";
MarkdownConverter.ConvertToDocx(markdown, "shopping-list.docx");
string markdown = @"
# Product Documentation

Our product features:


";
MarkdownConverter.ConvertToDocx(markdown, "product-doc.docx");
string markdown = @"
# Sales Report
| Product | Q1 Sales | Q2 Sales | Total |
|---------|----------|----------|-------|
| Widget A | $1,000 | $1,200 | $2,200 |
| Widget B | $850 | $900 | $1,750 |
| Widget C | $1,500 | $1,600 | $3,100 |
";
MarkdownConverter.ConvertToDocx(markdown, "sales-report.docx");
MarkMyWord supports syntax highlighting for code blocks, making code more readable in Word documents:
Supported Languages:
Example:
string markdown = @"
# API Response
```json
{
""name"": ""MarkMyWord"",
""version"": ""0.2.0"",
""enabled"": true
}
#!/bin/bash
echo ""Converting files...""
for file in *.md; do
markmyword convert -i ""$file""
done
";
MarkdownConverter.ConvertToDocx(markdown, "highlighted.docx");
**Features:**
- Colors optimized for grey code block backgrounds
- Automatic spell/grammar check suppression (no red squiggles!)
- Trailing empty lines automatically removed
- Property names vs values distinguished in JSON
**Disable syntax highlighting:**
```csharp
var options = new ConversionOptions
{
EnableSyntaxHighlighting = false
};
MarkdownConverter.ConvertToDocx(markdown, "plain-code.docx", options);
Custom syntax colors:
var options = new ConversionOptions
{
Styles = new StyleConfiguration
{
SyntaxColorScheme = new SyntaxColorScheme
{
KeywordColor = "0000FF", // Blue
StringColor = "A31515", // Red
NumberColor = "098658", // Green
CommentColor = "6A9955", // Green
TypeColor = "4EC9B0", // Cyan
FunctionColor = "C4A000" // Gold
}
}
};
var options = new ConversionOptions
{
Styles = new StyleConfiguration
{
CodeFontName = "Consolas",
CodeFontSize = 9,
CodeBackgroundColor = "F5F5F5" // Light grey
}
};
string code = @"
# Code Example
```json
{
""message"": ""Hello, World!""
}
";
MarkdownConverter.ConvertToDocx(code, "code.docx", options);
## Testing
The library includes comprehensive unit tests covering all supported markdown syntax:
```bash
dotnet test
Current test coverage (29 tests):
MarkMyWord implements:
Contributions are welcome! Areas for contribution:
MIT License - See LICENSE file for details
🚀 Beta - Core functionality and CLI are fully working with comprehensive CommonMark support.
Fully supported:
Coming soon: Task lists, footnotes, definition lists
Generated with ❤️ using Claude Code