Read local Markdown and HTML files in a browser tab that stays open.
Point it at a file or a folder and it opens in your browser. A small background server keeps serving that tab after the terminal — or the editor — is closed, so a document you opened once stays readable at a stable URL.
Python standard library only. The rendering libraries are vendored, so it
works offline and there is nothing to pip install.
Requires Python 3.8+ on macOS or Linux.
git clone https://github.com/TeaNguyen/mdview.git ~/.local/share/mdview
ln -s ~/.local/share/mdview/mdview.py ~/.local/bin/mdviewMake sure ~/.local/bin is on your PATH, then:
mdview README.mdOptionally, keep the server running across reboots:
mdview autostart # macOS launch agent; `mdview autostart off` to undomdview notes.md # open one file
mdview . # open a folder: every .md / .html inside
mdview # home page: every folder you've opened
mdview list # registered folders
mdview rm <path|id> # forget one
mdview themes # list themes; `themes new <name>` scaffolds one
mdview status # is the server up?
mdview stop # shut it down
mdview autostart # start the server at login-n / --no-open prints the URL instead of opening a tab. --port N moves
off the default 4111.
Opening a single file registers the folder around it, and the sidebar shows its neighbours. A file already inside a registered folder reuses that folder.
Navigation
- A sidebar tree mirroring the folders on disk.
⌘Kfilters it, and matches auto-expand their parents. Clicking a folder opens its index; clicking the chevron collapses it. The button in the sidebar header folds every top-level folder at once. - The folder index lists subfolders then files, sorted by modified time, newest first. A folder is dated by the newest file anywhere inside it.
- Every breadcrumb segment above the current one is clickable.
- Opening anything — from a link, the breadcrumb, or a pasted URL — expands the tree down to it and scrolls it into view.
- Collapse state is remembered per folder, and
⌘Bhides the sidebar.
Reading
- Live reload: the open file re-renders on save, keeping your scroll position.
- A table of contents appears at three or more headings, indented by outline depth.
- The width button cycles narrow (708px) → wide (1000px) → full.
- Any list item with a nested list can be collapsed, with a count of what is hidden. Folds are remembered per file.
pturns the document into slides: headings become slides, an explicit---breaks them, long lists spill onto continuation slides, and the deck wears whatever theme you're using.⌘Pfrom there prints one slide per page.- Themes, from the menu behind the circle button. See below.
- A button hands the file to your default app for that file type.
Markdown
GFM (tables, task lists, strikethrough), YAML frontmatter as a property list,
GitHub alerts (> [!NOTE], [!WARNING], …) as callouts, syntax highlighting,
```mermaid diagrams, heading anchors, and a copy button on code blocks.
Relative links between Markdown files navigate in place; relative images and
other assets are served from the same folder. .html files are shown in an
iframe with the same sidebar around them.
Built in: Auto / Light / Dark, plus Medieval Parchment (aged paper,
Luminari headings, a rubricated drop cap), Typewriter (monospace
throughout), Nord and Ember. Pick one from the circle button in the top
right. The choice is remembered and applied before the page paints.
?theme=<id> on a URL pins one.
mdview themes new "sea glass" # scaffolds ~/.mdview/themes/sea-glass.css
mdview themes # lists what's installedEdit the file and reopen the menu — no restart. A theme is a stylesheet loaded after mdview's own, with a header comment giving it a name and a light or dark syntax-highlighting scheme:
/* mdview-theme
name: Sea Glass
scheme: light
*/
:root {
--bg: #eef4f2;
--text: #22403a;
--accent: #3f8f7d;
--font-body: "Iowan Old Style", Georgia, serif;
--doc-size: 17px;
}The scaffold lists every variable with a comment. In short:
| Group | Variables |
|---|---|
| Surfaces | --bg --bg-sidebar --bg-hover --bg-active --bg-code --bg-inline --bg-th |
| Ink | --text --text-soft --text-faint --text-inline --border --border-soft --accent |
| Callouts | --note --tip --warn --danger |
| Type | --font-body --font-head --font-ui --font-mono --doc-size --doc-leading --head-weight --head-case --head-spacing --title-size |
A theme is plain CSS and can restyle anything: the parchment theme paints a
paper texture on body and a drop cap with
.doc > p:first-of-type::first-letter. A file named after a built-in
(dark.css, parchment.css) replaces that theme instead of adding one.
- Tabs outlive the terminal that opened them, the editor, and — with
mdview autostart— a reboot. mdview rma folder, then reload a tab you left open on it: the folder comes back. Every folder ever opened is remembered.- Nothing is fetched at read time. Mermaid alone is 3.2 MB of the 3.9 MB repo and loads only on pages that actually draw a diagram, so diagrams render on a plane.
- Collapsed bullets are remembered by their text rather than their position, so editing elsewhere in the file doesn't shuffle your folds.
mdview .in a repo gives you every README in it, in one tree.- The parchment theme opens a page with a red drop cap, the way a scribe would.
- One command, one URL, no flags to remember — easy to hand to an AI agent:
mdview path/to/file.md.
| Variable | Default | Effect |
|---|---|---|
MDVIEW_PORT |
4111 |
Port the server binds on 127.0.0.1. Also --port N. |
MDVIEW_EDITOR |
unset | App to open files with, instead of the system default. |
Both are read by the server process. Set them before it starts:
mdview stop
MDVIEW_EDITOR="Visual Studio Code" mdview .State lives in ~/.mdview/: roots.json (folders in the home list),
known.json (every folder ever opened), themes/ (your themes), and
server.log.
- Binds
127.0.0.1only. Nothing is exposed to the network. - POSTs that change state — registering a folder, opening a file in an app —
are refused when they carry a foreign
Origin. Files can only be opened from inside a registered folder, and paths are checked against it. .htmlfiles run their own scripts in the iframe, served from the same origin. Don't point mdview at HTML you don't trust.- Folder scans skip hidden directories,
node_modules,dist,build,venvand similar, and stop at 4000 files or 8 levels deep. mdview autostartis macOS only. Everything else works on Linux; Windows is untested.- It renders; it never writes to your files.
MIT — see LICENSE.
Vendored libraries under assets/vendor/ keep their own licences: marked
(MIT), DOMPurify (Apache-2.0 OR MPL-2.0), highlight.js (BSD-3-Clause), mermaid
(MIT).