An open API service indexing awesome lists of open source software.

https://github.com/k1low/mo

mo is a Markdown viewer that opens .md files in a browser.
https://github.com/k1low/mo

markdown markdown-viewer

Last synced: 3 months ago
JSON representation

mo is a Markdown viewer that opens .md files in a browser.

Awesome Lists containing this project

README

          






mo




# mo

[![build](https://github.com/k1LoW/mo/actions/workflows/ci.yml/badge.svg)](https://github.com/k1LoW/mo/actions/workflows/ci.yml) ![Coverage](https://raw.githubusercontent.com/k1LoW/octocovs/main/badges/k1LoW/mo/coverage.svg) ![Code to Test Ratio](https://raw.githubusercontent.com/k1LoW/octocovs/main/badges/k1LoW/mo/ratio.svg) ![Test Execution Time](https://raw.githubusercontent.com/k1LoW/octocovs/main/badges/k1LoW/mo/time.svg)

`mo` is a **M**arkdown viewer that **o**pens `.md` files in a browser.

## Features

- GitHub-flavored Markdown (tables, task lists, footnotes, etc.)
- Syntax highlighting ([Shiki](https://shiki.style/))
- [Mermaid](https://mermaid.js.org/) diagram rendering
- LaTeX math rendering ([KaTeX](https://katex.org/))
- [GitHub Alerts](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts) (admonitions)
- Fullscreen zoom modal for images and Mermaid diagrams
- dark theme Dark / light theme light theme
- group File grouping
- toc Table of contents panel
- flat view Flat / tree view tree sidebar view with drag-and-drop reorder
- file name File name / heading title heading title sidebar display toggle (per-group)
- search Full-text search across file names and content
- YAML frontmatter display (collapsible metadata block)
- MDX file support (renders as Markdown, strips `import`/`export`, escapes JSX tags)
- wide view Wide / narrow view narrow content width toggle
- raw Raw markdown view
- copy Copy content (Markdown / Text / HTML)
- restart 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:**

```console
$ brew install k1LoW/tap/mo
```

**manually:**

Download binary from [releases page](https://github.com/k1LoW/mo/releases)

## Usage

``` console
$ 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.

``` console
$ 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:

``` console
$ mo draft.md -p 6276
```

![Multiple files with sidebar](images/multiple-files.png)

### Groups

Files can be organized into named groups using the `--target` (`-t`) flag. Each group gets its own URL path and sidebar.

``` console
$ 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
```

![Group view](images/groups.png)

### Glob pattern watching

Use `--watch` (`-w`) to specify glob patterns. Matching files are opened automatically, and watched directories are monitored for new files.

``` console
$ 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:

``` console
$ 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.

``` console
$ 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`.

### Sidebar view modes

The sidebar supports flat and tree view modes. Flat view shows file names only, while tree view displays the directory hierarchy.

| Flat | Tree |
|------|------|
| ![Flat view](images/sidebar-flat.png) | ![Tree view](images/sidebar-tree.png) |

### 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.

``` console
$ 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:

``` console
$ 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`:

``` console
$ mo --foreground README.md
```

### Server restart

Click the restart 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.

``` console
$ 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:

``` console
$ 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:

``` console
$ 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.

``` console
$ 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`:

``` console
$ 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 |
| `--dangerously-allow-remote-access` | | | Allow remote access without authentication (trusted networks only) |

> [!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](https://pnpm.io/).

``` console
$ make build
```

## References

- [yusukebe/gh-markdown-preview](https://github.com/yusukebe/gh-markdown-preview): GitHub CLI extension to preview Markdown looks like GitHub.

## License

- [MIT License](LICENSE)
- Include logo as well as source code.
- Only logo license can be selected [CC BY 4.0](https://creativecommons.org/licenses/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.