Skip to main content

Markdown → DOCX/PPTX/PDF bridge built on Pandoc, with curated styling, Mermaid rendering, and bibliography support.

Project description

md2star

PyPI CI Python License: BSD-3-Clause Status: beta

Convert Markdown into professional DOCX, PPTX and PDF documents using Pandoc, branded templates, and practical automation.

logo

md2star is a cross-platform command-line tool that wraps Pandoc with a curated styling layer. It handles the parts Pandoc alone gets wrong — list spacing, bibliography injection, LaTeX math, Mermaid diagrams, image embedding, table widths, PPTX slide isolation — so you stay in Markdown and never open Word to fix layout.

DOCX mode — Musk's five-step engineering algorithm rendered live:

Light Dark
md2star DOCX — light md2star DOCX — dark

PPTX mode — Kawasaki's 10/20/30 pitch deck rendered live:

Light Dark
md2star PPTX — light md2star PPTX — dark

Why md2star?

Pandoc by itself is powerful but unopinionated: it gives you a plain-vanilla DOCX with no template, no localized dates, no sensible table widths, no Mermaid rendering. The result needs hand- editing in Word before it's shareable.

md2star sits between you and Pandoc. You write Markdown; you get a DOCX / PPTX / PDF that looks like a deliberate document.

Quick start

pipx install md2star          # one line, gets you the four CLIs
md2star doctor                # confirm the environment is healthy
md2docx report.md             # markdown → DOCX
md2pptx slides.md             # markdown → PPTX
md2pdf  paper.md              # markdown → PDF (needs LibreOffice)

Prefer HTTP or MCP? md2star also ships a FastAPI surface and an MCP server:

pip install 'md2star[api,mcp]'

md2star-api                    # FastAPI: /health, /doctor, /convert — docs at /docs
curl -F 'file=@report.md' 'http://localhost:8000/convert?fmt=docx' -o report.docx

md2star-mcp                    # same tools (doctor / convert) over MCP

See docs/installation.md for the full per-OS matrix (macOS / Ubuntu / Fedora / Arch / Windows), feature- by-feature dependency table, verification recipe, and the troubleshooting guide.

Supported outputs

Format Status Requires CLI
DOCX Beta Pandoc md2docx file.md
PPTX Beta Pandoc md2pptx file.md
PDF Beta Pandoc + LibreOffice (soffice) md2pdf file.md

"Beta" means: the format works for the common cases, has automated test coverage, and has been used to ship real documents. The table-render bug that haunted v1.x's PDF pipeline (cells leaking out of the table as a vertical paragraph dump) is fixed in v2.0.0 — the bundled template was rebuilt from a Pandoc-clean baseline.

Examples (the punchy ones)

1. Plain markdown → branded DOCX

md2docx report.md --author "Ada Lovelace"

Gives you report.docx with the bundled template's fonts / margins / heading styles, the first # Heading lifted to the document title, today's date localized to the document language, and the author rendered in the subtitle.

2. Scientific paper with bibliography

md2docx paper.md --author "Dr. Renegade Researcher" \
                 --bib references.bib \
                 --bibliography-name "References"

Pandoc's citeproc resolves [@einstein1905] references against the BibTeX file and appends a "References" section at the end.

3. PDF that matches the DOCX 1:1

md2pdf paper.md --author "Dr. Renegade Researcher" --bib references.bib

Renders the DOCX through headless LibreOffice so the PDF inherits every md2star polish — branded template, Mermaid PNGs, table styles, localized dates.

A self-contained cookbook with more recipes lives at EXAMPLES.md.


Features

  • Frictionless Conversion: Write in Markdown with your favorite editor (emacs, vim, Sublime Text, Obsidian, …) and produce styled .docx, .pptx, and .pdf files.
  • LaTeX Math Support: Robust rendering of complex formulas in both documents and slides.
  • Mermaid Diagrams: ```mermaid blocks are rendered locally to PNG via the official Mermaid CLI and embedded automatically (requires Node.js ≥16).
  • Intelligent Metadata:
    • Automatic Title Extraction from your first # Heading.
    • Smart Subtitle Injection combining Author and localized Date.
    • Language Detection via langdetect: date formats ship for 10 languages (English, French, Spanish, German, Italian, Portuguese, Dutch, Russian, Japanese, Chinese), with translated weekday/month names in 7 (fr, es, de, it, pt, nl, ru).
  • Scientific-Ready: Native BibTeX integration via Pandoc's citeproc, for documents with managed reference libraries.
  • Automatic Cleanups (quiet quality-of-life): remote http(s):// images downloaded for embedding (opt-in), HTML <table> blocks converted to Pandoc pipe-tables, and standalone images split off PPTX slides that contain a table (Pandoc otherwise drops them).
  • Reversible by Design: md2star's DOCX output is a faithful, recoverable rendering, not a one-way dead end. Read it straight back to Markdown with any DOCX reader (Pandoc, kreuzberg) and your headings, **bold**/*italic*/`code` emphasis, tables, and lists come back intact — and repeated conversions converge to a stable fixed point rather than drifting. See Round-trip fidelity.
  • Graceful Image Path Resolution: URLs, absolute paths, and relative paths all "just work". Relative ![](images/foo.png) references resolve against the input file's directory — so md2docx subdir/file.md from any cwd still finds the image. No need to cd into the source folder first.
  • Zero-Config Branding: drop a template.docx / template.pptx next to your Markdown and md2star will pick it up automatically as --reference-doc. If neither exists, the bundled default is used (offline-safe). Pass --allow-remote-templates to opt into the one-time deraison.ai fetch.
  • Discoverable CLI: every wrapper supports --help / -h and prints the md2star-specific flags followed by pandoc --help, so the full conversion surface is one command away. Try md2docx --help, md2pptx --help, or md2star --help.
  • Opt-in LLM Linter: a local Ollama pass fixes syntax-level mistakes (broken image links, unclosed fences, malformed pipes) before Pandoc parses the file. Off by default so conversions stay deterministic; pass --lint to opt in. The wrapper then spawns ollama serve and ollama pulls the default model on demand — gemma4:e2b-mlx on macOS (Apple-Silicon-optimized MLX build) or gemma4:e2b on Linux/Windows.
  • AI-Drafted Alt-Text: with --lint, every empty ![](src) reference gets a vision-model-drafted alt text (same gemma4:e2b model, cached per image). Override the model with MD2STAR_ALT_TEXT_MODEL.
  • Companion: AI Template Adapter: when you need to brand a corporate PPTX template that doesn't follow Pandoc's standard layout names, use the sibling md2star-adapt tool to build a compatible reference doc from the template + its PDF export.

Installation

md2star is a Python package distributed on PyPI. Installation via pipx is recommended — it isolates the package in its own venv and puts the four CLIs (md2star, md2docx, md2pptx, md2pdf) on your PATH. Pandoc is the only hard system dependency; LibreOffice is needed for md2pdf; Node.js is needed for Mermaid; Ollama is needed for --lint.

  • macOS 🍎 : brew install pandoc pipx (install brew thanks to brew.sh)

    pipx ensurepath          # one-time: add ~/.local/bin to PATH
    pipx install md2star
    
    # Optional: PDF output needs LibreOffice
    brew install --cask libreoffice
    # Optional: Mermaid diagrams need Node.js
    brew install node
    # Optional: --lint and AI alt-text need Ollama
    brew install ollama
    
  • Ubuntu 🐧 : sudo apt-get install pandoc pipx

    pipx ensurepath
    pipx install md2star
    
    # Optional dependencies
    sudo apt-get install libreoffice nodejs
    curl -fsSL https://ollama.com/install.sh | sh   # ollama
    
  • Windows 🪟 : winget install --id JohnMacFarlane.Pandoc

    python -m pip install --user pipx
    python -m pipx ensurepath
    pipx install md2star
    
    # Optional dependencies
    winget install --id TheDocumentFoundation.LibreOffice
    winget install --id OpenJS.NodeJS
    winget install --id Ollama.Ollama
    

Install from source (development path)

git clone https://github.com/warith-harchaoui/md2star.git
cd md2star
make install            # checks deps, runs `pipx install .`

Updating

Platform Command
Any (PyPI install) pipx upgrade md2star
macOS / Linux from source make update (git pull + pipx install --force .)
Windows from source powershell -ExecutionPolicy Bypass -File scripts\update.ps1

For development

make dev                # creates .venv/ with `pip install -e .[dev]`
source .venv/bin/activate
python -m pytest tests/ -v

Usage Guide

1. Simple Export

md2docx myfile.md

Generates myfile.docx.

2. Scientific Paper (with Citations and Math Formulas)

md2docx work.md --author "Dr. Renegade Researcher" --bib references.bib --bibliography-name "References" --lang en-US

Generates work.docx.

3. Presentation Slides

md2pptx slides.md --author "Speaker Name"

Generates slides.pptx.

4. Branded Slides with Custom Template

md2pptx slides.md --reference-doc my_branded_template.pptx

5. PDF Output

md2pdf paper.md --author "Dr. Renegade Researcher" --bib references.bib

Generates paper.pdf (via headless LibreOffice; requires soffice on PATH).

6. Opt-in LLM Syntax Lint

# default: lint is OFF, conversions are deterministic
md2docx draft.md

# opt in (spawns `ollama serve` and pulls the default model on demand)
md2docx draft.md --lint

# explicit no-op (same as the default; kept for unambiguous scripting)
md2docx draft.md --no-lint

When you pass --lint, a local Ollama pass (text-only gemma4:e2b-mlx on macOS, gemma4:e2b on Linux/Windows) fixes broken image links, unclosed code fences, and malformed table pipes before Pandoc sees the file. The same --lint flag also fills empty ![](src) alt text via a local vision model (override the model with MD2STAR_ALT_TEXT_MODEL). The wrapper starts the daemon on demand (ollama serve) and pulls the default model on first use (ollama pull gemma4:e2b…) — a one-time download, narrated on stderr. If --lint is passed but Ollama isn't installed, md2star prints a one-line warning on stderr and falls back to the original Markdown so the conversion still succeeds.


Template Adapter (separate repo)

For branded PPTX templates whose layout names don't follow Pandoc's defaults, use the companion tool md2star-adapt. It runs a three-phase pipeline — extract theme/logo/shapes from the PPTX, classify each layout with a local VLM (Ollama) against the matching PDF, then assemble a Pandoc-compatible reference doc — and produces a branded_ref.pptx you feed back to md2star via --reference-doc.

It lives in its own repo because its dependencies (PyMuPDF, lxml, python-pptx, requests + a running Ollama VLM) are much heavier than the core conversion pipeline needs, and the correctness profile (VLM-driven) is different in kind from md2star's deterministic core.


Examples

A self-contained cookbook lives at EXAMPLES.md.

You can also find more complex examples inside the tests/examples/ directory. To natively batch-compile all documents inside the folder, execute the bash runner:

cd tests/examples
./run.sh

Below are basic .docx and .pptx files generated dynamically during our test suite from sample Markdown files:

Word Documents Examples

PowerPoint Slides Examples


Quality & Reliability

md2star is built for reliability. Our automated test suite covers:

  • Metadata accuracy: title extraction, author injection, and subtitle composition.
  • Bibliography rendering: citeproc pipeline against the curated references.bib snapshot.
  • Date localization: French weekday/month rendering and date-format injection.
  • Preprocessor invariants: list spacing, code-block preservation, HTML-table conversion, pipe-table separator normalization, image width injection, language detection, mermaid fallback, math-in-code unwrapping, PPTX slide isolation.
  • Offline-mode enforcement: every network-touching phase refuses to run with --offline.

Integration tests (shell)

Requires Pandoc installed:

make test

Unit tests (Python)

Requires pytest and your generated virtual environment:

python -m pytest tests/ -v

For more details, see tests/README.md.


Round-trip fidelity

Converting to .docx doesn't trap your content in a binary format. md2star's output is a faithful, reversible rendering of your Markdown: read the .docx back with any DOCX reader and the source content comes home.

What survives md → docx → md:

Construct Recovered?
Headings (section levels)
**bold** / *italic*
Inline `code` spans ✅ (via Pandoc)
Pipe tables (every cell)
Bullet & numbered lists
Paragraph text

It reaches a fixed point. The round-trip is idempotent in the mathematical sense — running it twice yields the same document as running it once (g(g(x)) == g(x)), so repeated conversions converge instead of accumulating cruft. This is enforced in CI by tests/test_roundtrip.py, which converts a fixture to DOCX, reads it back with Pandoc's native reader, and asserts both content survival and the fixed-point property.

The one thing md2star adds on each run — by design — is a localized date subtitle re-stamped with today's date; that (and cosmetic details like line wrapping and the exact dash count in a table separator, which carry no meaning) is normalized out before the idempotence check. Nothing else drifts.

Reproduce it yourself (any DOCX reader works; the built-in Pandoc path needs no extra install):

md2docx report.md --offline            # report.md → report.docx
pandoc report.docx -t gfm --wrap=none  # report.docx → Markdown on stdout

Prefer an OCR-based reader that also covers the pdf → md direction? The same property holds with kreuzberg (extract_file_sync(path, config=ExtractionConfig(output_format=OutputFormat.MARKDOWN))), which recovered 100 % of heading text and body words from the DOCX and 94–99 % from the LibreOffice-rendered PDF in our measurements.


Customization

Metadata Defaults

Adjust your global defaults in md2star/data/metadata.yaml:

author: "Your Default Name"
date_format: "%A, %e %B %Y"
lang: "en-US"

Chosen conventions:

Styling Templates

Two levels of customization, from project-local to global:

Per-project (recommended): drop a template.docx or template.pptx next to your Markdown file. Every md2star wrapper auto-detects it and passes it as --reference-doc. Commit it alongside your source so collaborators and CI produce identical branded output.

If neither template.docx (preferred) nor the legacy .pandoc-reference.docx (still honored with a deprecation notice) exists, md2star falls back to the bundled default shipped inside the wheel. Pass --allow-remote-templates to opt into a one-time download from deraison.ai:

https://deraison.ai/template.docx
https://deraison.ai/template.pptx

You then edit that local copy in Word / PowerPoint / LibreOffice and commit it whenever you're happy with the styling.

Global (changes the bundled default for every project that hasn't pinned its own): modify the master templates in md2star/data/ to change fonts, margins, or logos:

  • md2star/data/template.docx
  • md2star/data/template.pptx

These are shipped inside the wheel and used as the offline fallback when no template.{docx,pptx} is found next to your Markdown. After editing, run make reinstall so the changes take effect for already-installed CLIs.


Developer Documentation

For contributors and advanced users interested in the inner workings of our Python logic and AST parsing hooks, check our internal API guides:


Related Projects

  • Pandoc: The engine that makes document conversion universal.
  • MarkItDown: A utility by Microsoft that performs the reverse operation, converting Office documents and other formats into Markdown.
  • Obsidian: Our recommended environment for writing high-fidelity Markdown.
  • Zotero: The ideal research companion for managing your .bib bibliographies.

Troubleshooting

Issue Solution
md2docx: command not found Add ~/.local/bin to your PATH (pipx ensurepath) and restart your shell.
pandoc: command not found Install Pandoc.
mmdc errors / mermaid blocks left as code Install Node.js ≥16 so npx can fetch @mermaid-js/mermaid-cli.
Want the LLM linter to run Pass --lint. It is off by default; with --lint, the wrapper starts the Ollama daemon and pulls the model on demand. Requires ollama on PATH; otherwise it silently no-ops.
--lint printed a model-pull error The first run downloads gemma4:e2b-mlx (macOS) or gemma4:e2b (Linux/Windows). If the pull failed (e.g. offline), md2star falls back to the original Markdown silently — fix your network and re-run.
md2pdf: LibreOffice not found Install LibreOffice (brew install --cask libreoffice / apt-get install libreoffice / winget).
PPTX template layout warnings Normal if a template lacks standard slide-layout names; output is still valid.
Remote image not embedded Pass --allow-remote-images to opt into the download (md2star is offline-by-default).

Security model & offline mode

md2star is offline by default. No .md file you process can make a network call on its own. The --allow-remote-images / --allow-remote-templates flags opt in to specific network use cases; --offline makes the refusal explicit in scripts. Full security model: SECURITY.md.

Roadmap & status

  • See ROADMAP.md for what's coming and what's explicitly NOT in scope.
  • See CHANGELOG.md for the per-release diff.
  • See docs/audit.md for the latest honest engineering audit (forces, risks, priorities).

Contributing

See CONTRIBUTING.md for the quickstart, project layout, and PR checklist. The TL;DR is make dev + python -m pytest tests/ + ruff check md2star/ tests/.


License

Distributed under the BSD 3-Clause License — the same permissive license used by scikit-learn and other major scientific Python projects.

Author: Warith HARCHAOUI

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

md2star-2.3.0.tar.gz (4.2 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

md2star-2.3.0-py3-none-any.whl (147.2 kB view details)

Uploaded Python 3

File details

Details for the file md2star-2.3.0.tar.gz.

File metadata

  • Download URL: md2star-2.3.0.tar.gz
  • Upload date:
  • Size: 4.2 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for md2star-2.3.0.tar.gz
Algorithm Hash digest
SHA256 772ec71340e25aede72f8d3e6901c2af0fe247c995f916815960b0277b1e7a91
MD5 3715d26338da93b8b40b6fe6be2f96e3
BLAKE2b-256 e37b476775cf97b946e50e1d823a5c1a2e5e65332085edc13f2690204e7de4f7

See more details on using hashes here.

File details

Details for the file md2star-2.3.0-py3-none-any.whl.

File metadata

  • Download URL: md2star-2.3.0-py3-none-any.whl
  • Upload date:
  • Size: 147.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for md2star-2.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 12033573467a88da162d6345f6ee77ece988140e228ea17b0540349aff521164
MD5 cc221c79bacc83236cd5fdc4e378348e
BLAKE2b-256 dad7cd757b3209f7103171f6cfe5351b348e52303ce5e1e4f97a24fe5d69ed0d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page