Skip to main content

mdvw

Fast, portable, fully offline Markdown viewer and editor for Windows.

PyPI Python CI License: MIT

mdvw rendering its README in Read mode


What it is

A small Windows desktop app for local Markdown notes and wikis. It opens a .md file and renders it beautifully — with KaTeX math, Mermaid diagrams, syntax-highlighted code, live reload when the file changes on disk, wiki links, a graph view, workspace search, and a three-mode Read / Edit / Source view. Everything needed to render is vendored into the package: no network request is made to open or view a document.

Why

Most Markdown viewers either need a browser tab, a heavy IDE, or pull fonts and scripts from a CDN at render time. mdvw is a single pip install away, opens fast, and works without internet — everything needed to render ships inside the wheel.

Features

  • Three modes — Read, Edit (live split), Source (raw .md in a dark editor). Switch with Ctrl+1/2/3 or cycle with E.
  • Offline first — KaTeX (math), Mermaid (diagrams), highlight.js (20 languages), and webfonts all ship inside the wheel, SHA256-pinned via a manifest.
  • GFM + extensions — tables, task lists, footnotes, strikethrough. Plus ==highlight==, ++underline++, and {color:red}…{/color} / {color:#hex}…{/color}.
  • Wiki links + embeds — [[Note]], [[Note|alias]], [[Note#Heading]], [[#Heading]], plus block embeds like ![[Note]] and ![[Note#Heading]]. Click to navigate, type [[ for filename autocomplete, hover for a preview, click an unresolved link to create the note. Backlinks live in the Incoming sidebar pane; Diagnostics flags ambiguous and missing-heading targets.
  • Fast note workflows — create a note with Ctrl+N, create from a template, open today's daily note, and rename or move the current note while updating wiki links and relative Markdown links across the workspace.
  • YAML frontmatter card — ----fenced metadata renders as a styled card at the top of the preview; invalid YAML shows an error card without breaking the body.
  • Live reload — external changes on disk re-render instantly; unsaved edits get a conflict prompt rather than being silently overwritten.
  • Command palette — Ctrl+P blends app commands with filename matches from the workspace into one fuzzy-searchable input.
  • Workspace search + tasks — Ctrl+Shift+F greps every .md under the open workspace and jumps to the match. The Tasks pane aggregates - [ ] items across the workspace, groups them by note/heading, and lets you toggle them in place.
  • Outline, files, recent, graph, diagnostics — switchable left-pane sections. The outline supports per-heading collapse plus ▲ All / ▼ All / ▶ Auto. Graph view shows local or workspace note links. Diagnostics flag invalid frontmatter, broken relative links, and blocked remote refs.
  • Inspector + status bar — right-pane inspector shows parsed frontmatter and document stats (words, headings, reading time); footer status bar tracks mode, dirty state, word count, cursor position, and the mdvw version.
  • Image paste — pasting an image in the editor saves it next to the document and inserts a relative ![](…) reference.
  • Export + print — Export HTML… writes a single self-contained file (inlined CSS, fonts, and image data URIs); Print… hands off to the system print dialog for print-to-PDF.
  • Native feel — system tray with close-to-tray, single-instance file handoff, follow-system dark/light theme (title bar included), taskbar icon (M↓), .md file association via mdvw --register.

Install

pip install mdvw

Requires Python 3.13+, Windows 10/11.

Or grab the standalone onedir build from the Releases page — unzip mdvw-win-x64.zip and run mdvw.exe. No Python needed.

Usage

mdvw notes.md              # open a file
mdvw                       # open with the bundled welcome doc
mdvw --edit notes.md       # start in split-edit mode
mdvw --no-tray             # skip the system tray icon
mdvw --register            # associate .md with mdvw (HKCU, no admin)
mdvw --unregister          # remove the association

Keyboard shortcuts

Key Action
Ctrl+P Command palette (commands + workspace filenames)
Ctrl+1 / Ctrl+2 / Ctrl+3 Read / Edit (split) / Source
E Cycle Read → Edit → Source
Ctrl+N New note
Ctrl+O Open file
Ctrl+S Save (atomic; prompts on disk conflict)
Ctrl+F Find in document
Ctrl+Shift+F Search workspace
Ctrl+Shift+H Go to heading
Ctrl+Shift+G Open graph view
Ctrl+Shift+O Open directory
Alt+Left / Alt+Right Back / Forward through visited documents
[[ Wiki-link filename autocomplete (in Edit / Source)
Ctrl+Shift+W Toggle narrow / wide preview
Ctrl+Alt+I Toggle inspector

Common command-palette note actions: New Note, New Note from Template, Open Daily Note, Rename or Move Note, Show Tasks, Open Graph View.

Markdown extensions

Beyond GitHub Flavored Markdown, mdvw understands:

==highlighted== text
++underlined++ text
{color:orange}orange{/color}, {color:#bf3989}pink{/color}

[[Note]], [[Note|alias text]], [[Note#Heading]], [[#Same-doc heading]]
![[Note]], ![[Note#Heading]]

Inline math $e^{i\pi}+1=0$ and block math:

$$
x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}
$$

Mermaid diagrams:

```mermaid
graph LR
    A[Open .md] --> B[Edit]
    B --> C[Preview]
    C --> D[Save]
```

Safety notes

Documents render through an HTML sanitizer with no network access, so opening an unfamiliar .md file doesn't fetch remote resources or leak that you opened it. Saves are atomic and notice when the file changed on disk between load and save. Vendored JS/CSS is SHA256-pinned and verified in CI.

How it works (one paragraph)

render.py parses Markdown with markdown-it-py + plugins, sanitizes with nh3 (Rust ammonia), resolves wiki links against the open workspace, expands block transclusions, and rewrites user-relative URLs against the document's own directory. app.py renders a template into a per-instance HTML in %TEMP%, references packaged JS/CSS via absolute file:// URLs (no <base> — that would misdirect user links), and opens it in a pywebview window using Windows WebView2. KaTeX / Mermaid / highlight.js run in the browser post-inject.

Releasing

The project uses a single-commit + tag pattern so the PyPI artifact's source matches the tag byte-for-byte:

# 1. Write notes under `## [Unreleased]` in CHANGELOG.md, commit
# 2. Cut the release (atomic bump + changelog date + commit + tag):
python scripts/release.py 0.2.0
git push origin main v0.2.0      # triggers release.yml → PyPI + GH Release

# 3. Open the next dev cycle:
python scripts/release.py --post-release 0.3.0.dev0
git push origin main

Development

git clone https://github.com/ThomasRohde/mdvw && cd mdvw
pip install -e .[dev]
python scripts/fetch_vendor.py --verify   # make sure vendor hashes match
pytest -q                                  # run tests
ruff check src tests scripts               # lint
python -m mdvw README.md                   # try it

To upgrade a vendored library: python scripts/fetch_vendor.py --update, then commit the refreshed files and manifest.json together.

License

MIT. The bundled third-party assets keep their own licenses (KaTeX: MIT; Mermaid: MIT; highlight.js: BSD-3).

Metadata

Release files for mdvw 0.11.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mdvw 0.11.1
File Size Uploaded
mdvw-0.11.1.tar.gz 1.3 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for mdvw 0.11.1
File Interpreter ABI Platform
mdvw-0.11.1-py3-none-any.whl Python 3 none any Details

Total release size: 2.6 MB

Release files / mdvw-0.11.1.tar.gz

Download URL mdvw-0.11.1.tar.gz
Size 1.3 MB
Tags Source
SHA-256 checksum
How to use checksums
81d3e2194260b8cc7b21d03dd1c768f31b26f675d7eee2d2e8433e2ebcc72ceb
BLAKE2b-256 checksum
How to use checksums
944d43d2b4336055b5873d62b878e32b1bed3d826d61bb7ac16aada046d0e97e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 21, 2026.

Transparency log

Release files / mdvw-0.11.1-py3-none-any.whl

Download URL mdvw-0.11.1-py3-none-any.whl
Size 1.3 MB
Tags Python 3
SHA-256 checksum
How to use checksums
19114d21f0921123e34ab93105fa506080a65b5c08e2a8de9bed7e613ad71d07
BLAKE2b-256 checksum
How to use checksums
fefa3798072f30c09e5f463c749055697b109f254e52a9708d1f093a53f9275e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 21, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.11.1 This release

2 release files

0.11.0

2 release files

0.10.0

2 release files

0.9.1

2 release files

0.9.0

2 release files

0.8.0

2 release files

0.7.1

2 release files

0.7.0

2 release files

0.6.2

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page