mdv

command module
v0.1.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 29, 2026 License: MIT Imports: 20 Imported by: 0

README

mdv

mdv is a local, privacy-first Markdown preview server for the CLI: it renders a Markdown file (or directory) in your browser, entirely on your machine.

Markdown → HTML conversion happens server-side in Go; the browser only displays the generated HTML. (Mermaid diagrams are the one interactive piece that runs browser-side JavaScript — served from the embedded bundle, never a CDN.) Your Markdown content is never sent to any external service, and a strict Content-Security-Policy also stops the browser from fetching remote resources referenced by a document — images, scripts, frames, fonts — so simply viewing a file leaks nothing off your machine.

mdv pairs well with AI-assisted documentation workflows: keep mdv -d docs/ running, let an AI agent (or your editor) write Markdown into the directory, and every save shows up in the browser via live reload:

┌─────────────┐  write/save  ┌──────────────┐    SSE    ┌─────────────┐
│ AI / editor │ ───────────▶ │ mdv          │ ────────▶ │ browser     │
│ writes .md  │              │ local server │   reload  │ rendered MD │
└─────────────┘              │ + watcher    │           └─────────────┘
                             └──────────────┘

Features

  • Open a formatted view in the browser with a single command (mdv README.md)
  • Mermaid diagrams, GitHub Alerts (> [!NOTE] etc.), a table of contents, and syntax highlighting
  • Light / dark theme with an in-browser toggle (remembered per browser); follows the OS setting in auto mode
  • Bring your own CSS: auto-loads .mdv.css from the served root, or pass a file with --css
  • Live reload on save — including the Vim/Neovim "write temp + rename" pattern
  • Single binary, no runtime dependencies: all assets are embedded via go:embed and the tool works fully offline
  • Private by default: binds to 127.0.0.1, sanitizes HTML passthrough, and blocks all external resource loads via CSP
  • Runs as a standalone process, independent of your editor; --no-open keeps it headless for agents and scripts

Install

Requires Go 1.25 or newer.

go install github.com/gr1m0h/mdv@latest

Or via mise:

mise use -g go:github.com/gr1m0h/mdv@latest   # build from source
mise use -g ubi:gr1m0h/mdv                    # prebuilt binary from GitHub Releases

Usage

mdv                 # list the .md files in the current directory
mdv README.md       # open a file (the served root is its parent directory)
mdv docs/           # serve a directory as the root and show its listing

By default the server runs in the foreground — press Ctrl-C to stop it.

Background servers

Use -d to detach and return to the shell, then manage running servers with mdv ls and mdv stop:

mdv -d README.md        # start in the background; prints the URL, PID and port
mdv ls                  # list running background servers
mdv stop --port 4649    # stop one by port
mdv stop --all          # stop all
mdv stop                # stop the only one (errors if several are running)

Each background server binds its own port (4649, 4650, …) and is tracked in a per-instance record under MDV_STATE_DIR (default: the user cache dir). mdv stop only terminates servers mdv itself started — it never kills an unrelated process that happens to hold the port. Background mode is POSIX-only (Linux and macOS); on Windows, run in the foreground.

Flags
Short Long Default Description
-p --port 4649 Listen port (+1, up to 20 times, if the port is busy)
--host 127.0.0.1 Bind address
-t --theme auto Color theme: auto | light | dark
-c --css Path to a custom CSS file (else auto-loads .mdv.css)
-d --daemon Run in the background and return to the shell
-n --no-open Do not open the browser automatically
-q --quiet Suppress access logs
-h --help Show help
-V --version Show version

[!NOTE] By default mdv binds to 127.0.0.1, so the server — and the directory it serves — is reachable only from your own machine. Passing --host 0.0.0.0 (or any non-loopback address) exposes it to the network: anyone who can reach the port can read every file mdv serves. Only do this on a network you trust.

Subcommands
Command Description
mdv stop [--port N | --all] Stop background server(s)
mdv ls (alias status) List running background servers
Theming

Set the initial theme with --theme/MDV_THEME (auto follows the OS). In the browser, the toggle button in the top-right switches between light and dark; that choice is stored per browser (localStorage) and overrides the initial theme until you clear it. auto keeps following the OS until you pick one.

Custom CSS

Your own stylesheet loads after the built-in styles, so your rules win. mdv resolves it in this order: --css/-cMDV_CSS.mdv.css in the served root (auto-loaded when present).

mdv --css ~/mdv-theme.css docs/   # explicit file
echo '.markdown-body { max-width: 72ch; }' > docs/.mdv.css && mdv docs/  # auto-loaded

Useful hooks:

  • .markdown-body — the rendered document container

  • [data-theme="dark"] / [data-theme="light"] on <html> — per-theme rules

  • Color tokens are CSS variables (--fg, --bg, --link, --border, …); override them to re-skin both themes at once, e.g.:

    [data-theme="dark"] {
      --bg: #101418;
      --link: #7aa2f7;
    }
    :root {
      --mdv-max-width: 820px;
    } /* content column width */
    

The stylesheet is served with Cache-Control: no-store, so a browser refresh picks up edits immediately.

Environment variables

MDV_PORT / MDV_HOST / MDV_BROWSER / MDV_WATCH (fsnotify|poll) / MDV_THEME (auto|light|dark) / MDV_CSS / MDV_STATE_DIR (precedence: flag > environment variable > default)

Development

Tasks are managed with mise (which also pins Go 1.25):

mise run build            # build the binary
mise run test             # test (covers the R/H/S/W/C acceptance criteria)
mise run check            # fmt check + vet + test
mise run generate         # regenerate the chroma stylesheets
mise run vendor-mermaid   # fetch the real mermaid bundle (see note below)
Architecture
  • internal/render — goldmark pipeline (highlighting, alerts, heading IDs/TOC, mermaid, sanitization)
  • internal/server — HTTP router, shell HTML, fragment, SSE, embedded assets, path guarding
  • internal/watch — fsnotify (parent-directory watch + debounce) with a polling fallback
  • internal/assets — static assets embedded via go:embed
  • internal/browser — per-OS browser launching
  • main / daemon.go — CLI, flag parsing, and background-server management (detach via listener-fd inheritance, instance registry, stop/ls)

Note: the real Mermaid bundle is vendored and committed at internal/assets/static/mermaid.min.js (the pinned version and SHA-256 are recorded in internal/assets/static/mermaid.version), so go install builds render Mermaid out of the box. To upgrade it, re-vendor and commit:

mise run vendor-mermaid && git add internal/assets/static/mermaid.* && git commit

Flowchart diagrams have been verified to render under the strict CSP (script-src 'self', no 'unsafe-eval'); the remaining diagram types (sequence/gantt/state/ER/class) have not been exhaustively checked. If one fails to render with a CSP error, add 'unsafe-eval' to script-src in server.contentSecurityPolicy.

License

See LICENSE, and THIRD_PARTY_LICENSES.md for bundled components.

Documentation

Overview

Command mdv renders a Markdown file (or directory) in the browser from the CLI, serving everything locally with no external network access.

Directories

Path Synopsis
internal
assets
Package assets embeds the static browser assets (CSS, JS, mermaid, favicon) so mdv ships as a single binary with no runtime network access (spec §8.3).
Package assets embeds the static browser assets (CSS, JS, mermaid, favicon) so mdv ships as a single binary with no runtime network access (spec §8.3).
browser
Package browser opens a URL in the user's default browser.
Package browser opens a URL in the user's default browser.
render
Package render implements the server-side Markdown rendering pipeline: goldmark parse -> chroma highlight -> alerts -> heading IDs/TOC -> mermaid -> bluemonday sanitize.
Package render implements the server-side Markdown rendering pipeline: goldmark parse -> chroma highlight -> alerts -> heading IDs/TOC -> mermaid -> bluemonday sanitize.
server
Package server implements the mdv HTTP server: shell HTML, rendered fragments, live-reload SSE, embedded assets and guarded static files.
Package server implements the mdv HTTP server: shell HTML, rendered fragments, live-reload SSE, embedded assets and guarded static files.
watch
Package watch reports changes to a single target file.
Package watch reports changes to a single target file.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL