mo

mo is a Markdown viewer that opens .md files in a browser.
Features
- GitHub-flavored Markdown (tables, task lists, footnotes, etc.)
- Syntax highlighting (Shiki)
- Mermaid diagram rendering
- LaTeX math rendering (KaTeX)
Dark /
light theme
File grouping
Table of contents panel
Flat /
tree sidebar view with drag-and-drop reorder and file search
File name /
heading title sidebar display toggle (per-group)
- YAML frontmatter display (collapsible metadata block)
- MDX file support (renders as Markdown, strips
import/export, escapes JSX tags)
Wide /
narrow content width toggle
Raw markdown view
Copy content (Markdown / Text / HTML)
Server restart with session preservation
- Auto session backup and restore
- Drag-and-drop file addition from the OS file manager (content is loaded in-memory; live-reload is not supported for dropped files)
- Live-reload on save (for files opened via CLI)
Install
homebrew tap:
$ brew install k1LoW/tap/mo
manually:
Download binary from releases page
Usage
$ mo README.md # Open a single file
$ mo README.md CHANGELOG.md docs/*.md # Open multiple files
$ mo docs/ # Open all .md files in a directory
$ mo spec.md --target design # Open in a named group
mo opens Markdown files in a browser with live-reload. When you save a file, the browser automatically reflects the changes.
Single server, multiple files
By default, mo runs a single server on port 6275. If a server is already running on the same port, subsequent mo invocations add files to the existing session instead of starting a new one.
$ mo README.md # Starts a mo server in the background
$ mo CHANGELOG.md # Adds the file to the running mo server
To run a completely separate session, use a different port:
$ mo draft.md -p 6276

Groups
Files can be organized into named groups using the --target (-t) flag. Each group gets its own URL path and sidebar.
$ mo spec.md --target design # Opens at http://localhost:6275/design
$ mo api.md --target design # Adds to the "design" group
$ mo notes.md --target notes # Opens at http://localhost:6275/notes

Glob pattern watching
Use --watch (-w) to specify glob patterns. Matching files are opened automatically, and watched directories are monitored for new files.
$ mo --watch '**/*.md' # Watch and open all .md files recursively
$ mo --watch 'docs/**/*.md' --target docs # Watch docs/ tree in "docs" group
$ mo --watch '*.md' --watch 'docs/**/*.md' # Multiple patterns
When a directory is passed with --watch, it is automatically converted to a dir/*.md watch pattern:
$ mo --watch docs/ # Equivalent to mo --watch 'docs/*.md'
--watch cannot be combined with file arguments. The ** pattern matches directories recursively.
Removing watch patterns
Use --unwatch to stop watching a previously registered pattern. Files already added remain in the sidebar.
$ mo --unwatch '**/*.md' # Stop watching a pattern (default group)
$ mo --unwatch 'docs/**/*.md' --target docs # Stop watching in a specific group
$ mo --unwatch '/Users/you/project/**/*.md' # Stop watching by absolute path
Patterns are resolved to absolute paths before matching, so you can specify either a relative glob or the full path shown by --status.
The sidebar supports flat and tree view modes. Flat view shows file names only, while tree view displays the directory hierarchy.
Starting and stopping
mo runs in the background by default — the command returns immediately, leaving the shell free for other work. This makes it easy to incorporate into scripts, tool chains, or LLM-driven workflows.
$ mo README.md
mo: serving at http://localhost:6275 (pid 12345)
$ # shell is available immediately
Use --status to check all running mo servers, and --shutdown to stop one:
$ mo --status # Show all running mo servers
http://localhost:6275 (pid 12345, v0.12.0)
default: 5 file(s)
watching: /Users/you/project/src/**/*.md, /Users/you/project/*.md
docs: 2 file(s)
watching: /Users/you/project/docs/**/*.md
$ mo --shutdown # Shut down the mo server on the default port
$ mo --shutdown -p 6276 # Shut down the mo server on a specific port
$ mo --restart # Restart the mo server on the default port
If you need the mo server to run in the foreground (e.g. for debugging), use --foreground:
$ mo --foreground README.md
Server restart
Click the
restart button (bottom-right corner) or run mo --restart to restart the mo server process. The current session — all open files and groups — is preserved across the restart. This is useful when you have updated the mo binary and want to pick up the new version without re-opening your files.
Session backup and restore
mo automatically saves session state (open files and watch patterns per group) when files are added or removed. When starting a new server, the previous session is automatically restored and merged with any files specified on the command line. Restored session entries appear first, followed by newly specified files.
$ mo README.md CHANGELOG.md # Start with two files
$ mo --shutdown # Shut down the server
$ mo # Restores README.md and CHANGELOG.md
$ mo TODO.md # Restores previous session + adds TODO.md
Use --close to remove specific files from the running server:
$ mo --close README.md # Close a file from the default group
$ mo --close docs/*.md -t docs # Close files from the "docs" group
Use --clear to remove a saved session. If a server is running, it is automatically restarted with an empty state:
$ mo --clear # Clear saved session for the default port
$ mo --clear -p 6276 # Clear saved session for a specific port
JSON output
Use --json to get structured JSON output on stdout, useful for scripting and integration with other tools.
$ mo --json README.md
{
"url": "http://localhost:6275",
"files": [
{
"url": "http://localhost:6275/?file=a1b2c3d4",
"name": "README.md",
"path": "/Users/you/project/README.md"
}
]
}
--status also supports --json:
$ mo --status --json
[
{
"url": "http://localhost:6275",
"status": "running",
"pid": 12345,
"version": "0.15.0",
"revision": "abc1234",
"groups": [
{
"name": "default",
"files": 3,
"patterns": ["**/*.md"]
}
]
}
]
Flags
| Flag |
Short |
Default |
Description |
--target |
-t |
default |
Group name |
--port |
-p |
6275 |
Server port |
--bind |
-b |
localhost |
Bind address (e.g. 0.0.0.0) |
--open |
|
|
Always open browser |
--no-open |
|
|
Never open browser |
--status |
|
|
Show all running mo servers |
--watch |
-w |
|
Glob pattern to watch for matching files (repeatable) |
--unwatch |
|
|
Remove a watched glob pattern (repeatable) |
--close |
|
|
Close files instead of opening them |
--shutdown |
|
|
Shut down the running mo server |
--restart |
|
|
Restart the running mo server |
--clear |
|
|
Clear saved session (restarts server if running) |
--foreground |
|
|
Run mo server in foreground |
--json |
|
|
Output structured data as JSON to stdout |
[!WARNING]
Binding to a non-localhost address exposes mo to the network without any authentication. Remote clients can read any file accessible by the user, browse the filesystem via glob patterns, and shut down the server. A confirmation prompt is shown when --bind is set to a non-loopback address.
Build
Requires Go and pnpm.
$ make build
References
License
- MIT License
- Include logo as well as source code.
- Only logo license can be selected CC BY 4.0.
- Also, if there is no alteration to the logo and it is used for technical information about mo, I would not say anything if the copyright notice is omitted.