Lightweight, themeable Markdown to Documents converter. CLI, SDK, and API.
Project description
mtd
Yet another Markdown to Documents converter. Lightweight, themeable, and API-ready.
Convert your Markdown files to DOCX and ODT with custom themes. Available as a CLI tool, a Python SDK, or a local HTTP microservice for integration with other systems.
Features
- 📄 Convert Markdown to
.docxand.odt - 🎨 Built-in themes:
default,academic,modern - 🧩 Custom themes via simple YAML files
- 📝 YAML frontmatter support (title, author, date, theme)
- 📑 Title page and headers/footers support
- 🐍 Python SDK for programmatic use
- 🌐 HTTP API microservice (FastAPI) for system integration
- ⚡ Fast and lightweight with minimal dependencies
- 🛠️ CLI, SDK, and API: three ways to use it
Install
# Global install with uv (recommended)
uv tool install yamtd
# With the HTTP API included
uv tool install "yamtd[api]"
# With pipx
pipx install yamtd
# With pip (in a venv)
pip install yamtd
Or install directly from the repository:
uv tool install git+https://github.com/Dxsk/mtd.git
Quick Start
# Scaffold a template in the current directory
mtd init
mtd init -o my-report.md
# Convert to DOCX
mtd convert README.md -o output.docx
# Convert to ODT with a theme
mtd convert README.md -o output.odt --theme modern
# List available themes
mtd themes list
# Show theme details
mtd themes show academic
SDK / Python API
Use mtd as a library in your own Python projects.
Install
pip install yamtd
Quick Convert
from mtd import convert
# Markdown file to DOCX
convert("report.md", "report.docx")
# With a theme
convert("report.md", "report.docx", theme="academic")
# To ODT
convert("report.md", "report.odt", theme="modern")
Convert from String
from mtd import convert_string
markdown = """
---
title: Generated Report
author: Automation Bot
---
# Results
Processing completed successfully.
"""
convert_string(markdown, "report.docx", theme="modern")
Granular API
For more control, use the lower-level functions:
from mtd import parse_markdown, write_docx, write_odt, load_theme, Document
# Parse
doc = parse_markdown("report.md")
print(doc.title) # from frontmatter
print(doc.author)
print(doc.theme) # "default" if not set
print(doc.titlepage) # HTML of titlepage block, or None
print(doc.header) # header config dict, or None
print(doc.footer) # footer config dict, or None
# Load a theme
theme = load_theme("academic")
# Or from a custom YAML file
theme = load_theme("path/to/custom.yaml")
# Write to DOCX
write_docx(doc, "output.docx", theme)
# Write to ODT
write_odt(doc, "output.odt", theme)
Available Exports
| Import | Description |
|---|---|
convert(input, output, theme=) |
High-level one-liner conversion |
convert_string(markdown, output, theme=) |
Convert from a Markdown string |
parse_markdown(source) |
Parse a file or string into a Document |
Document |
Parsed document dataclass |
write_docx(doc, output, theme=) |
Write Document to DOCX |
write_odt(doc, output, theme=) |
Write Document to ODT |
load_theme(name_or_path) |
Load a theme by name or YAML path |
list_themes() |
List available built-in theme names |
Theme |
Theme configuration dataclass |
HTTP API
mtd includes an optional HTTP API server for integration with other systems.
WARNING: This API is for local/internal use only. It has no authentication or security hardening. Do not expose it to the public internet. Use it behind a reverse proxy or within a private network.
Install
pip install "yamtd[api]"
Start the Server
# Via CLI
mtd serve --port 8484
# Or directly with uvicorn
uvicorn mtd.server:app --host 127.0.0.1 --port 8484
API documentation is available at http://127.0.0.1:8484/docs (Swagger UI).
Endpoints
| Method | Endpoint | Description |
|---|---|---|
GET |
/health |
Health check |
GET |
/themes |
List available themes |
GET |
/themes/{name} |
Get theme details |
POST |
/convert |
Convert Markdown text (form data) |
POST |
/convert/file |
Convert uploaded Markdown file |
Examples
# Health check
curl http://127.0.0.1:8484/health
# List themes
curl http://127.0.0.1:8484/themes
# Convert Markdown text to DOCX
curl -X POST http://127.0.0.1:8484/convert \
-F "markdown=# Hello World" \
-F "format=docx" \
-F "theme=modern" \
-o output.docx
# Upload and convert a file
curl -X POST http://127.0.0.1:8484/convert/file \
-F "file=@document.md" \
-F "format=odt" \
-F "theme=academic" \
-o output.odt
Themes
mtd ships with 3 built-in themes:
| Theme | Description |
|---|---|
default |
Clean and neutral. Serif body, sans-serif headings |
academic |
Formal. Times New Roman, wide margins, double spacing |
modern |
Contemporary. Sans-serif, tight spacing, accent colors |
Custom Themes
Create a YAML file with your style preferences:
name: my-theme
fonts:
heading: Helvetica
body: Georgia
code: Fira Code
colors:
primary: "#2563eb"
text: "#1f2937"
page:
margin_top: 2.5cm
margin_bottom: 2.5cm
Then use it:
mtd convert doc.md -o doc.docx --theme path/to/my-theme.yaml
Markdown Template
mtd extends standard Markdown with special blocks for professional document generation. A complete example is available in examples/template.md.
Full Example
---
title: Quarterly Report
subtitle: Q1 2026 Results
author: Jane Doe
date: 2026-03-20
theme: modern
header:
left: "Quarterly Report"
center: ""
right: "{page}"
footer:
left: "Jane Doe"
center: "Confidential"
right: "{date}"
---
:::titlepage
# Quarterly Report
## Q1 2026 Results
Jane Doe
ACME Corp.
March 2026
:::
# Introduction
Document content starts here...
Frontmatter Reference
The YAML frontmatter block (---) at the top of the file controls all document metadata and layout.
| Field | Type | Description |
|---|---|---|
title |
string | Document title (used in metadata and {title} placeholder) |
subtitle |
string | Subtitle (displayed on title page) |
author |
string | Author name (used in metadata and {author} placeholder) |
date |
string | Date in YYYY-MM-DD format (used in metadata and {date} placeholder) |
theme |
string | Theme name or path to a .yaml file. Defaults to default |
header |
object | Header configuration (see below) |
footer |
object | Footer configuration (see below) |
Headers and Footers
Headers and footers support three zones: left, center, and right. Each zone is optional and defaults to empty.
header:
left: "Company Name"
center: ""
right: "{page}"
footer:
left: "{author}"
center: "Draft"
right: "{date}"
Available placeholders:
| Placeholder | Replaced with |
|---|---|
{page} |
Current page number (auto-incremented) |
{date} |
Document date from frontmatter |
{title} |
Document title from frontmatter |
Headers and footers are repeated on every page. When a title page is present, it is excluded from headers/footers automatically.
Title Page Block
The :::titlepage block generates a dedicated cover page before the document content. Content inside the block is centered with larger fonts.
:::titlepage
# Main Title
## Subtitle
Author Name
Organization
Date or other info
:::
Rendering rules:
| Element | Style |
|---|---|
# Heading 1 |
Large bold title (28pt by default, configurable via theme) |
## Heading 2 |
Subtitle (20pt by default) |
| Plain text | Info lines (14pt by default, centered) |
The title page sizes are controlled by the theme:
titlepage:
title_size: 28 # H1 font size in pt
subtitle_size: 20 # H2 font size in pt
info_size: 14 # Plain text font size in pt
spacing_top: "7cm" # Top margin before content
A page break is automatically inserted after the title page.
Supported Markdown Elements
| Element | Syntax | DOCX | ODT |
|---|---|---|---|
| Headings | # H1 to ###### H6 |
Yes | Yes |
| Bold | **text** |
Yes | Yes |
| Italic | *text* |
Yes | Yes |
| Bold + Italic | ***text*** |
Yes | Yes |
| Strikethrough | ~~text~~ |
Yes | Yes |
| Inline code | `code` |
Yes | Yes |
| Fenced code blocks | ```python |
Yes | Yes |
| Unordered lists | - item (supports nesting) |
Yes | Yes |
| Ordered lists | 1. item (supports nesting) |
Yes | Yes |
| Task lists | - [x] done / - [ ] todo |
Yes | Yes |
| Tables | Pipe syntax with alignment | Yes | Yes |
| Blockquotes | > quote (supports nesting) |
Yes | Yes |
| Links | [text](url) |
Yes | Yes |
| Images |  |
Yes | Yes |
| Horizontal rules | --- |
Yes | Yes |
| Footnotes | text[^1] / [^1]: note |
Yes | Yes |
Minimal Template
The simplest valid mtd document:
---
title: My Document
author: Your Name
---
# Hello World
This is a paragraph.
Full-Featured Template
For a production-ready template with all features, copy the example:
cp examples/template.md my-document.md
mtd convert my-document.md -o my-document.docx --theme academic
License
MIT
Project details
Release history Release notifications | RSS feed
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 yamtd-0.1.1.tar.gz.
File metadata
- Download URL: yamtd-0.1.1.tar.gz
- Upload date:
- Size: 100.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.10.12 {"installer":{"name":"uv","version":"0.10.12","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
519f722d9144dbf420b4645597ec0ee666689089b2df1f211fca964e229efe94
|
|
| MD5 |
35415f41f5b03bce3882882cd7c07e19
|
|
| BLAKE2b-256 |
9c2bfff2fa425aeae315731de3ecda15df4f415e6f5a3cf378a2f47ddb5477d7
|
File details
Details for the file yamtd-0.1.1-py3-none-any.whl.
File metadata
- Download URL: yamtd-0.1.1-py3-none-any.whl
- Upload date:
- Size: 30.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.10.12 {"installer":{"name":"uv","version":"0.10.12","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4f9042f5194c1cb170f742317fe53cb5e1fd72ec3ce43a003b8706da2ac40b1b
|
|
| MD5 |
08e6e109d7bcb4b24d5d72a923133eaa
|
|
| BLAKE2b-256 |
6bd11bc0569cbb5bb9369c00508bb6d564061e4f6f0ed364242ec07ad9fec837
|