Skip to main content
Glama
README.md
# MD Vision

> A minimalist, read-only Markdown & code viewer for the desktop, built for **comfortably reviewing** work — including output produced by AI agents.

[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
![Platforms](https://img.shields.io/badge/platforms-macOS%20%7C%20Windows%20%7C%20Linux-lightgrey)
![Built with Electron](https://img.shields.io/badge/built%20with-Electron-47848F)

MD Vision is a small Electron app that renders Markdown and source code beautifully and gets out of your way. It is **read-only by design** — there is no editor. The single priority is legibility: a clean syntax theme, fast keyboard navigation, and a layout meant for *reading*, not editing.

It also shines as a companion to AI coding assistants: select any lines and copy a ready-to-paste **`path:lines` reference**, or let an agent open and highlight files for you (see [Driving MD Vision from an AI agent](#driving-md-vision-from-an-ai-agent)).

<p align="center"><img src="docs/screenshot.png" alt="MD Vision: file tree on the left, a source file open with Mariana syntax highlighting and line numbers on the right" width="900"></p>

```
┌──────────────┬─────────────────────────────────┐
│  file tree   │  rendered file (Markdown / code) │
│  (sidebar)   │  scrolls independently           │
└──────────────┴─────────────────────────────────┘
```

- **Left** — the tree of the opened folder. Only viewable files are shown; everything else (and empty folders) is hidden.
- **Right** — the selected file, with its own scroll.
  - `.md` → high-quality, GitHub-style HTML (tables, highlighted code, task lists, anchors).
  - code & text → syntax highlighting, line numbers, and a header (name + language).

## Features

- **Markdown rendering** via [markdown-it](https://github.com/markdown-it/markdown-it) + [github-markdown-css](https://github.com/sindresorhus/github-markdown-css) (tables, task lists, heading anchors).
- **Syntax highlighting** via [Shiki](https://shiki.style/) (TextMate grammars, *Mariana* theme) with line numbers, at the same size as the Markdown text.
- **PDF viewing** rendered in-app with [PDF.js](https://mozilla.github.io/pdf.js/) (selectable text, lazy-loaded pages) — no opaque embedded viewer.
- **Search** by file name and by content (powered by a bundled [ripgrep](https://github.com/BurntSushi/ripgrep)), **accent-insensitive** (e.g. `eleve` matches `élève`); content search also covers **PDF text, by page**.
- **Copy a `path:lines` reference** from any selection — the fastest way to point an AI agent at exact lines.
- **Configurable build buttons** that run a command in your terminal, filtered by the current file type.
- **Agent-drivable**: an MCP server lets an assistant open a file and highlight a range; an optional hook auto-displays files as they are edited.
- **Multilingual UI & help** — English, French, Spanish, German, Portuguese, Chinese (auto-detected from the OS, switchable from the toolbar).
- **Dark theme** tuned for the Mariana syntax colors.
- **Resizable sidebar**, multiple tabs, internal `.md` links and relative images resolved, last opened folder remembered.
- **Cross-platform**: macOS, Windows, Linux.

## Supported files

| Category | Rendering |
| --- | --- |
| **Markdown** (`.md` `.markdown` `.mdown` `.mkd` `.mkdn` `.mdwn`) | Rich GitHub-style HTML |
| **Plain text** (`.txt`) | Raw text + line numbers |
| **Source code** (see below) | Syntax highlighting + line numbers |
| **PDF** (`.pdf`) | Rendered with PDF.js — selectable text, lazy-loaded pages, searchable by page |

Code highlighting covers a broad set of languages, including:

> C, C++, C#, Objective-C · Python, Ruby, Perl, PHP, Lua, R, Julia · JavaScript/JSX, TypeScript/TSX, Vue, Svelte, HTML, CSS/SCSS/Less · Go, Rust, Java, Kotlin, Swift, Scala, Groovy/Gradle, Dart, Haskell, Elixir, Erlang, Clojure · Shell, PowerShell, Batch · JSON/JSONC, YAML, TOML, INI, XML/SVG, SQL, GraphQL, Protobuf, Nix, LaTeX, diff/patch · Dockerfile, Makefile.

Adding a language is a one-line change in [`src/languages.js`](src/languages.js), the single source of truth.

## Download

Pre-built apps for **macOS, Windows and Linux** are attached to each [release](https://github.com/caplandorlespan/MD_vision/releases). Grab the zip for your OS, unzip it, and launch the app inside — no installation step.

> The apps are **not code-signed**, so the first launch shows a one-time warning:
> - **macOS** — right-click the app → **Open** → confirm (Gatekeeper).
> - **Windows** — **More info** → **Run anyway** (SmartScreen).
>
> Prefer to run from source? See [Getting started](#getting-started) below.

## Getting started

### Prerequisites

- [Node.js](https://nodejs.org/) 18 or later (includes npm).

### Install & run

```bash
git clone https://github.com/caplandorlespan/MD_vision.git
cd MD_vision
npm install   # also downloads the platform's ripgrep binary
npm start
```

`npm install` is required on each machine: it pulls Electron and the ripgrep binary for your OS (these are not committed to the repo).

## Keyboard shortcuts

> On **Windows / Linux**, use **`Ctrl`** wherever `⌘` is shown.

| Shortcut | Action |
| --- | --- |
| `⌘F` | Search (name + content) |
| `Esc` | Clear the search |
| `⌘C` | Copy the `path:lines` reference of the selection |
| `⌘⇧C` | Copy the selected text |
| `⌘W` | Close the current tab |
| `⌘]` / `⌘[` | Next / previous tab |
| `⌘+` / `⌘−` / `⌘0` | Larger / smaller / default text size |

Right-click a tree item to copy its path (relative or absolute); right-click a selection to copy its reference or text.

## Copying a reference for an AI agent

This is the signature feature. **Select** text in any file (code, Markdown, *or* PDF) and press **`⌘C`** (`Ctrl+C`): instead of the raw text, MD Vision copies a **`path:lines` reference**, for example:

```
src/main.js:42-58
```

Paste it into your conversation with an assistant and it knows exactly which lines you mean — no copying code, no hunting for line numbers. The path is relative to the opened folder (absolute otherwise); a single line yields `path:42`, a range yields `path:42-58`. It works both in code view (exact lines) and in Markdown view (mapped back to the source lines). In a **PDF**, a selection yields `path (page N)` (or `path (page N1-N2)` across pages) — the same reference you get by right-clicking a PDF search hit; clicking a PDF search hit also opens the page with the matched text already selected. Need the actual text instead? Use **`⌘⇧C`** for a normal copy.

## Build tools

Build buttons appear above the right pane **when the current file matches** (by extension). Clicking one runs the command in a terminal: on macOS, Terminal.app reusing the same tab; on Windows, a `cmd /k` console; on Linux, the first terminal emulator found on the `PATH`.

Buttons are defined in a JSON file, by precedence:

1. **Per project** — `.mdvision-builds.json` at the root of the opened folder;
2. **Global** — created empty on first use in the app's data directory:
   - macOS: `~/Library/Application Support/md-vision/md-vision-builds.json`
   - Windows: `%APPDATA%\md-vision\md-vision-builds.json`
   - Linux: `~/.config/md-vision/md-vision-builds.json`

```json
{
  "builds": [
    {
      "name": "Compile",
      "cmd": ["/bin/bash", "/path/to/my-script.sh", "${file_path}", "compile"],
      "extensions": [".cpp", ".hpp", ".c", ".h"]
    }
  ]
}
```

- `cmd` — one argument per array entry (no quoting to worry about).
- `extensions` *(optional)* — restricts the button to those files; omit it to always show the button.
- Variables (Sublime-style): `${file}`, `${file_path}` (the file's **folder**), `${file_name}`, `${file_base_name}`, `${folder}` (the opened root).

## Packaging

Always pass `--asar.unpack="*.{wasm,mjs}"` (so Shiki's `onig.wasm` **and** PDF.js's `pdf.worker.mjs` load) and `--extra-resource` (so ripgrep ships with the app), otherwise highlighting, PDF rendering, or search can break in the packaged app. Pass `--icon` with the platform-specific file in `build/` (`.icns` on macOS, `.ico` on Windows, `.png` on Linux), otherwise the packaged app ships with Electron's default icon.

**macOS:**

```bash
npm install -D @electron/packager
npx electron-packager . "MD Vision" --platform=darwin --arch=arm64 --overwrite \
  --icon="build/icon.icns" \
  --asar.unpack="*.{wasm,mjs}" \
  --extra-resource="$(node -e 'console.log(require("@vscode/ripgrep").rgPath)')"
```

**Windows** (run *on* Windows, after `npm install` fetched `rg.exe`):

```bat
npx electron-packager . "MD Vision" --platform=win32 --arch=x64 --overwrite ^
  --icon="build/icon.ico" ^
  --asar.unpack="*.{wasm,mjs}" ^
  --extra-resource="<path to rg.exe>"
```

**Linux:**

```bash
npx electron-packager . "MD Vision" --platform=linux --arch=x64 --overwrite \
  --icon="build/icon.png" \
  --asar.unpack="*.{wasm,mjs}" \
  --extra-resource="$(node -e 'console.log(require("@vscode/ripgrep").rgPath)')"
```

## Releasing (maintainers)

Releases are built automatically by GitHub Actions ([`.github/workflows/release.yml`](.github/workflows/release.yml)) — natively on Windows, macOS and Linux, so each OS bundles its own ripgrep binary. No need to package by hand.

**Two ways to trigger it:**

1. **Push a version tag** → builds all three OSes **and** publishes a [GitHub Release](https://github.com/caplandorlespan/MD_vision/releases) with the zips attached:
   ```bash
   git tag v1.0.0
   git push --tags
   ```
2. **The "Run workflow" button** → open the repo's **Actions** tab → **Release** → **Run workflow**. This builds the three zips and attaches them to the run page (handy for a test build; it does **not** create a public Release).

Watch progress in the **Actions** tab. The manual section above (`electron-packager` commands) is only needed for a local one-off build.

## Driving MD Vision from an AI agent

MD Vision can be driven from the outside so an assistant can *show you its work*: open a file, jump to a range, and highlight it. Tab color indicates the source — neutral (you opened it), **green** (the agent just created/edited it), **violet** (the agent wants to show it to you).

It ships with a dependency-free **MCP server** (`show_file` / `show_lines` tools, compatible with any MCP client) and an optional **edit hook**. The control channel is loopback-only (`127.0.0.1`) and token-protected; nothing is exposed to the network. Full setup for Claude Code, Cursor, and other clients lives in [`mcp/README.md`](mcp/README.md).

## Project structure

```
src/
  main.js              # main process: window, IPC, disk reads + tree, builds
  platform.js          # all OS-specific code (ripgrep path, terminal launch, quoting)
  languages.js         # single source of truth for recognized languages
  control.js           # loopback control channel (agent → app)
  preload.js           # secure bridge + markdown-it & code rendering (Shiki)
  help.<lang>.md       # in-app help (the "?" button), one per language
  shiki-mariana.js     # Mariana theme for Shiki
  renderer/            # UI: tree, file opening, navigation, build bar
    index.html         # app shell / layout
    renderer.js        # UI logic (tree, tabs, search, shortcuts)
    styles.css         # styling (incl. tab colors for agent-driven views)
    i18n.js            # single source of truth for UI strings (6 languages)
mcp/                   # MCP server + edit hook to drive the app from an agent
examples/              # sample files
```

Internals and gotchas (Shiki/asar, bundled ripgrep, portability, i18n, control channel) are documented in [`ARCHITECTURE.md`](ARCHITECTURE.md).

## License

[MIT](LICENSE) © Caplandor Lespan