Preview local markdown files with mermaid diagram support.
Project description
Markdraft
Preview local markdown files in the browser with GitHub-flavored rendering, mermaid diagrams, math, syntax highlighting, and live reload. Zero runtime dependencies.
$ draft README.md
* Serving on http://localhost:6419/
Installation
From PyPI
pip install markdraft
Or with uv:
uv tool install markdraft
Standalone executable
Download markdraft.pyz from
Releases
and run it directly — no installation needed:
python markdraft.pyz README.md
Requires Python 3.10+. On first run, markdraft downloads about 3.5 MB
of JavaScript libraries from jsDelivr and
caches them in ~/.markdraft/.
Usage
Preview a file:
$ draft README.md
* Serving on http://localhost:6419/
Preview a directory (serves its README.md):
$ draft .
Open the browser automatically:
$ draft -b README.md
Specify host and port:
$ draft README.md 0.0.0.0:8080
Export to a self-contained HTML file:
$ draft --export README.md
Exporting to README.html
Export with CDN links instead of inlined assets:
$ draft --export --no-inline README.md
Dark mode:
$ draft --theme=dark README.md
The mdraft command is also available as an alias, for environments
where draft conflicts with Azure Draft.
Features
- Live reload — file changes are detected and the browser refreshes automatically via Server-Sent Events
- Mermaid diagrams —
```mermaidfenced code blocks rendered by mermaid.js - Math/LaTeX —
$inline$and$$display$$math rendered by KaTeX - Syntax highlighting — code blocks highlighted by highlight.js
- GitHub Alerts —
> [!NOTE],> [!TIP],> [!IMPORTANT],> [!WARNING],> [!CAUTION]styled callout boxes - GeoJSON maps —
```geojsonand```topojsonrendered as interactive maps by Leaflet - STL 3D models —
```stlrendered as rotating 3D views by Three.js - Task lists —
- [x]and- [ ]checkboxes - Emoji shortcodes —
:rocket:→ :rocket:, full gemoji set (1,800+ shortcodes) - GitHub styling — rendered with github-markdown-css
- Export — self-contained HTML files with all assets inlined or linked via CDN
- Zero dependencies — no pip runtime dependencies; rendering is done client-side by cached JavaScript libraries
- Auto/dark/light mode — follows OS preference by default
(
--theme=auto), or force with--theme=dark/--theme=light - Standalone executable — download a single
.pyzfile, no installation required
Rendering Showcase
The examples below exercise every client-side rendering feature.
Running draft README.md and checking that each one renders correctly
is a quick smoke test for a new installation.
Syntax highlighting
def fibonacci(n: int) -> int:
a, b = 0, 1
for _ in range(n):
a, b = b, a + b
return a
Mermaid diagrams
graph LR
A[Markdown file] --> B[HTTP Server]
B --> C[Browser]
C --> D[marked.js]
D --> E[Rendered HTML]
Math / LaTeX
Euler's identity: $e^{i\pi} + 1 = 0$
The Gaussian integral:
$$\int_{-\infty}^{\infty} e^{-x^2} , dx = \sqrt{\pi}$$
GitHub Alerts
[!NOTE] This is a note — useful for supplementary information.
[!TIP] This is a tip — helpful advice for the reader.
[!IMPORTANT] This is important — key information the reader should know.
[!WARNING] This is a warning — something that could cause problems.
[!CAUTION] This is a caution — potential for data loss or security risk.
GeoJSON maps
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [[
[-122.42, 37.78], [-122.42, 37.77], [-122.41, 37.77],
[-122.41, 37.78], [-122.42, 37.78]
]]
},
"properties": { "name": "San Francisco" }
}
]
}
Emoji shortcodes
:rocket: :sparkles: :warning: :bug: :white_check_mark: :x: :heart: :star: :fire: :eyes: :tada: :construction:
Task lists
- Syntax highlighting
- Mermaid diagrams
- Math / LaTeX
- GitHub Alerts
- GeoJSON maps
- Task lists
- Emoji shortcodes
Tables
| Library | Purpose | Size |
|---|---|---|
| marked.js | Markdown rendering | 40 KB |
| highlight.js | Syntax highlighting | 40 KB |
| KaTeX | Math rendering | 270 KB |
| mermaid.js | Diagrams | 2.9 MB |
CLI Reference
usage: draft [-h] [-V] [--user-content] [--wide] [--clear] [--export]
[--no-inline] [-b] [--title TITLE] [--norefresh] [--quiet]
[--theme THEME]
[path] [address]
| Flag | Description |
|---|---|
path |
File or directory to render (- for stdin) |
address |
host:port to listen on, or output file for --export |
-b, --browser |
Open browser tab after server starts |
--export |
Export to HTML file instead of serving |
--no-inline |
Use CDN links instead of inlining assets in export |
--title TITLE |
Override the page title |
--theme THEME |
Color theme: auto (default), light, or dark |
--user-content |
Render as GitHub issue/comment style |
--wide |
Wide layout (with --user-content) |
--norefresh |
Disable auto-refresh on file change |
--quiet |
Suppress terminal output |
--clear |
Clear the cached assets and exit |
-V |
Show version and exit |
Python API
from markdraft import serve, export, clear_cache
# Start a preview server
serve("README.md", port=8080, browser=True)
# Export to HTML
export("README.md", out_filename="preview.html")
# Clear cached CDN assets
clear_cache()
Configuration
Create ~/.markdraft/settings.py to override defaults:
HOST = "0.0.0.0"
PORT = 8080
AUTOREFRESH = True
QUIET = False
The MARKDRAFT_HOME environment variable overrides the config directory
(default ~/.markdraft).
Architecture
Markdraft is a thin HTTP server built on Python's http.server. It
serves raw markdown via a JSON API and lets the browser handle all
rendering:
sequenceDiagram
participant B as Browser
participant S as Server (http.server)
B->>S: GET /
S-->>B: HTML shell (template + script tags)
B->>S: GET /__/api/content
S-->>B: raw markdown as JSON
Note over B: marked.js renders markdown
Note over B: KaTeX renders math
Note over B: highlight.js highlights code
Note over B: mermaid.js renders diagrams
B->>S: GET /__/api/refresh (SSE)
S-->>B: file change notifications
Modules:
| Module | Purpose |
|---|---|
markdraft/server.py |
HTTP server with routing |
markdraft/readers.py |
File/directory/stdin reading |
markdraft/assets.py |
CDN asset downloading and caching |
markdraft/export.py |
Self-contained HTML export |
markdraft/watcher.py |
File change detection for auto-refresh |
markdraft/browser.py |
Browser tab opening |
markdraft/config.py |
Constants, CDN URLs, settings loader |
markdraft/command.py |
CLI argument parsing |
Development
git clone https://github.com/imofftoseethewizard/markdraft
cd markdraft
uv sync
uv run pytest # 148 tests, ~8s parallel
uv run pyright markdraft/ # type checking
uv run black markdraft/ tests/ # formatting
Acknowledgments
Markdraft began as a fork of Grip by Joe Esposito. Grip is a well-crafted tool for previewing GitHub-flavored markdown locally, and its reader abstractions and CLI design informed markdraft's architecture.
Major changes from Grip
- Zero runtime dependencies — Grip depends on Flask, Markdown, Pygments, requests, docopt, path-and-address, and Werkzeug. Markdraft has no pip dependencies; it uses only the Python standard library.
- Client-side rendering — Grip renders markdown server-side with Python. Markdraft serves raw markdown and renders it in the browser with marked.js, highlight.js, and mermaid.js.
- Math/LaTeX support —
$inline$and$$display$$math via KaTeX. - GitHub Alerts —
> [!NOTE],> [!WARNING], etc. rendered as styled callout boxes. - Mermaid diagram support —
```mermaidfenced code blocks rendered as diagrams. - GeoJSON maps and STL 3D models — interactive maps via Leaflet, rotating 3D model views via Three.js.
- stdlib HTTP server — replaces Flask with
http.server.ThreadingHTTPServer. - Modern Python — requires Python 3.10+, full type annotations, no Python 2 compatibility code.
- uv project management —
pyproject.tomlwith hatchling build backend, managed by uv. - Security hardening — path traversal protection via
Path.relative_to(), symlink escape prevention, case-insensitive</script>escaping in exports. - Standalone executable — downloadable
.pyzfile, no installation required. - GitHub API removed — Grip's primary mode was to POST markdown to the GitHub API for rendering. Markdraft renders entirely offline.
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 markdraft-1.0.3.tar.gz.
File metadata
- Download URL: markdraft-1.0.3.tar.gz
- Upload date:
- Size: 172.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
73127e5620e0417f240e3751df2c8c4bc4e83a6cb4782e4bd31a11277e4eba1d
|
|
| MD5 |
83c10b081cc4dc83f12e7facc7d0dd41
|
|
| BLAKE2b-256 |
de306944a441518e340a35e08c0466eba3af2aaf4da66aa9136580197dc81f1c
|
Provenance
The following attestation bundles were made for markdraft-1.0.3.tar.gz:
Publisher:
release.yml on imofftoseethewizard/markdraft
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
markdraft-1.0.3.tar.gz -
Subject digest:
73127e5620e0417f240e3751df2c8c4bc4e83a6cb4782e4bd31a11277e4eba1d - Sigstore transparency entry: 1201040155
- Sigstore integration time:
-
Permalink:
imofftoseethewizard/markdraft@8b642d4195ecfa697d231fbf6239403bc5eaa246 -
Branch / Tag:
refs/tags/v1.0.3 - Owner: https://github.com/imofftoseethewizard
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@8b642d4195ecfa697d231fbf6239403bc5eaa246 -
Trigger Event:
push
-
Statement type:
File details
Details for the file markdraft-1.0.3-py3-none-any.whl.
File metadata
- Download URL: markdraft-1.0.3-py3-none-any.whl
- Upload date:
- Size: 139.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
22b8dbe2c13c56984d3340a555b88d4180866665c07856349de760f8dc75fa3a
|
|
| MD5 |
0bf4900c47e57f116c91053d73535413
|
|
| BLAKE2b-256 |
87aa0655f5cadc8de20a1e20a288ca6916d59f2215fa49ca743b8be7b7e93648
|
Provenance
The following attestation bundles were made for markdraft-1.0.3-py3-none-any.whl:
Publisher:
release.yml on imofftoseethewizard/markdraft
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
markdraft-1.0.3-py3-none-any.whl -
Subject digest:
22b8dbe2c13c56984d3340a555b88d4180866665c07856349de760f8dc75fa3a - Sigstore transparency entry: 1201040190
- Sigstore integration time:
-
Permalink:
imofftoseethewizard/markdraft@8b642d4195ecfa697d231fbf6239403bc5eaa246 -
Branch / Tag:
refs/tags/v1.0.3 - Owner: https://github.com/imofftoseethewizard
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@8b642d4195ecfa697d231fbf6239403bc5eaa246 -
Trigger Event:
push
-
Statement type: