A full-featured markdown and org language server that works the moment you open a note. Navigation, completion, diagnostics with quick fixes, renames and moves that keep links intact, refactorings and notebook-wide queries, with no init step, no config and no root markers. mdroots finds the notebook a file belongs to, indexes it in the background, and keeps the index in your user cache dir, so the next editor that opens the notebook starts warm.
It understands the link styles your notes already use: zk, Obsidian, marksman, Foam, Dendron, Logseq, org-mode and plain relative paths, in one notebook if you mix them.
- Instant. The note you opened answers in about 10 ms, whatever the notebook size; whole-notebook answers follow once the index is up.
- Warm across editors. Every editor on a notebook shares one cache; only changed notes are re-read.
- Zero config, honest about it. Roots and conventions are detected, and
the settings you already made in zk or Obsidian are honoured.
mdroots roots NOTEshows the root it picked and why. - Safe on big trees. It never walks a remote, virtual or oversized tree; it falls back to the folders you actually open.
- A library first. The server, the CLI and embedders such as ramble (a TUI reader) share the same Rust API.
Time from server start, synthetic notebooks, median of 5 runs (method, caveats and how to reproduce):
| 10,000 notes | mdroots (warm cache) | mdroots (cold) | zk (indexed) | marksman |
|---|---|---|---|---|
| first answer (go to definition) | 11 ms | 11 ms | 207 ms | 4.7 s |
| full note completion | 411 ms | 2.3 s | 290 ms | 4.7 s |
| broken-link diagnostic | 368 ms | 2.3 s | 218 ms | 5.2 s |
| memory (phys_footprint) | 60 MB | 60 MB | 56 MB | 317 MB |
| setup | none | none | zk index: 109 s |
none |
zk answers fastest once zk index has run; mdroots needs no index step,
answers the open note first, and at this size uses about as much memory as
indexed zk. At 1,000 notes mdroots uses the least memory (14 MB vs 25 MB for
zk and 105 MB for marksman). Numbers are from local main after 0.2.10
(memory).
- Not a note manager. It reads notes and answers questions about them; it never writes to your notes or folders, and fills no templates. Renames, moves, quick fixes and refactorings come back as edits for your editor to apply.
- Not a daemon. Each editor runs it in-process; the first process on a notebook writes the cache, the others read it.
- Not a tenant in your notes. Nothing is written into your trees; tool configs are read, never required or written.
cargo install mdroots-cli # the `mdroots` binary (server + CLI)
cargo add mdroots # the libraryPrebuilt binaries for macOS (Apple silicon) and Linux (x86_64, aarch64) are on the releases page. With mise, which picks the right one for the machine:
mise use -g github:martintrojer/mdroots # latest release
mise up github:martintrojer/mdroots # update latermise holds back releases younger than 24 hours by default
(minimum_release_age), so within a day of a release name the version:
mise use -g github:martintrojer/mdroots@<version>.
Neovim 0.12+: copy editors/nvim/lsp/mdroots.lua
and plugin/mdroots.lua into
~/.config/nvim/ and open a markdown file. The plugin file calls
vim.lsp.enable('mdroots') and adds optional mappings; to skip it, call
vim.lsp.enable('mdroots') in your own config. :MdrootsInfo shows the root and
why (details).
mdroots check notes/ # broken links and anchors; exit 1 on problems (CI)
mdroots search 'rust async' notes/ # notes containing every word
mdroots backlinks notes/a.md # who links here
mdroots roots notes/a.md # the notebook root mdroots picked, and why
mdroots lsp # the language server on stdio- Navigate: go to definition on every link form, heading and
path:linemention; references and backlinks (of notes and tags); hover previews; highlights; document and workspace symbols; folding. - Write: completion of notes, headings, paths and tags; inlay hints with resolved titles; backlink code lenses.
- Fix: diagnostics for broken links, missing anchors, ambiguous links and frontmatter problems, each with quick fixes (change to the closest note or heading, create the note, pick a candidate).
- Refactor: rename a note and update every link; moves made in your
file tree (
willRenameFiles) fix links to moved notes and folders; convert links between wiki and Markdown; turn a selection into a link; extract a selection to a new note. - Explore the notebook: orphans, missing backlinks, related notes,
full-text search,
zk list-style queries, tags and a notebook-wide check, as commands that fill your quickfix list.
The full list, with links to the exact behaviour: docs/features.md.
- Everything mdroots does
- How roots are found and what happens on huge or remote trees
- The index, links and resolution
- The library API, the CLI and the server
- Design decisions and what's not built yet
- Changelog and the docs map
bash scripts/check.sh # fmt, clippy -D warnings, all testsMIT licensed.