Research on the current Neovim plugin landscape for writing/journaling in
Markdown, oriented around this site’s workflow: a markata blog with YAML
frontmatter, mkdocs-material-style !!! scripture / ??? scripture
admonitions, [[ slug ]] wikilinks, and a custom pypeaday.daily module
(copier templates + telescope/fzf pickers + live_grep backlinks).
1. LazyVim lang.markdown extra — what it actually does #
Source of truth (current main):
https://github.com/LazyVim/LazyVim/blob/main/lua/lazyvim/plugins/extras/lang/markdown.lua
Docs: https://github.com/LazyVim/lazyvim.github.io/blob/main/docs/extras/lang/markdown.md
As of 2026, the extra installs/configures:
- marksman via nvim-lspconfig (
servers = { marksman = {} }) — markdown LSP with[[wikilink]]completion, go-to-definition, references (backlinks), and dead-link diagnostics. Big deal: most of whatpypeaday.daily.find_backlinks()does via telescope live_grep, marksman gives viagrr/vim.lsp.buf.references. - markdownlint-cli2 via nvim-lint (and none-ls if installed), plus
conform.nvim formatters
prettier,markdownlint-cli2, andmarkdown-toc(the last only runs when the buffer contains<!-- toc -->). Mason auto-installsmarkdownlint-cli2+markdown-toc. LazyVim switched from markdownlint-cli to cli2 in 2024: https://github.com/LazyVim/LazyVim/pull/3843 - markdown-preview.nvim (
iamcco/markdown-preview.nvim) — browser preview on<leader>cp(markdown buffers only). - render-markdown.nvim (
MeanderingProgrammer/render-markdown.nvim) — in-buffer rendering. LazyVim replacedheadlines.nvimwith this plugin back in 2024: https://github.com/LazyVim/LazyVim/pull/4139. LazyVim’s config disables heading icons and checkbox rendering, and maps a<leader>umtoggle viaSnacks.toggle.
There is no prose/spell/grammar extra in LazyVim — the full extras list
contains nothing like a lang.text or extras.spelling. Prose tooling has
to be added by hand.
The import already exists in ~/.config/nvim/lua/config/lazy.lua (line 53)
alongside ~15 other extras — verified 2026-10-04. If plugins look missing,
:Lazy sync will reconcile; :LazyExtras shows what’s active.
Built-in LazyVim defaults that matter for prose (no plugin needed):
- FileType autocmd already sets
wrapandspellfor markdown:lazyvim/config/autocmds.lua(wrap_spellaugroup, patterns includemarkdown). So spell+wrap are already on. - Toggles already mapped:
<leader>usspell,<leader>uwwrap,<leader>umrender-markdown (with the extra),<leader>uzSnacks zen mode,<leader>uDSnacks dim — seelazyvim/config/keymaps.lua.
2. render-markdown.nvim — capabilities and the admonition gap #
Repo: https://github.com/MeanderingProgrammer/render-markdown.nvim
- Renders headings, code blocks, inline code, horizontal rules, list bullets, checkboxes (with user-defined states), block quotes, callouts, tables, links, LaTeX, per the README feature list.
- Callouts: supports GitHub (
[!NOTE],[!TIP],[!IMPORTANT],[!WARNING],[!CAUTION]) and the full Obsidian set ([!QUOTE],[!TODO], etc.). Custom callouts are fully supported — each entry isname = { raw = '[!SCRIPTURE]', rendered = ' Scripture', highlight = '...' }. Wiki reference: https://github.com/MeanderingProgrammer/render-markdown.nvim/wiki/Callouts - Custom callout titles (
> [!quote] Psalm 119) are supported: https://github.com/MeanderingProgrammer/render-markdown.nvim/issues/109 - Checkboxes:
- [ ]/- [x]render as icons, and arbitrary custom states (- [/],- [>], etc.) are configurable (checkbox.custom). - mkdocs
!!!/???admonitions are NOT supported. The plugin is treesitter-driven over the standard markdown parser; admonition blocks are just indented text to it. Callout support was added for the> [!x]blockquote syntax only (https://github.com/MeanderingProgrammer/render-markdown.nvim/issues/20). - The main alternative,
OXY2DEV/markview.nvim, also only renders> [!x]callouts for markdown — its “admonitions” support is for Asciidoc, not mkdocs: https://github.com/OXY2DEV/markview.nvim/wiki/Markdown - Even
markdown-preview.nvimcan’t preview mkdocs admonitions — open feature request: https://github.com/iamcco/markdown-preview.nvim/issues/618. The faithful preview for!!! scriptureis the markata/mkdocs build itself, not an editor plugin. - Conceal/anti-conceal:
anti_concealhides the plugin’s virtual text on the cursor line so you can edit raw source;win_options.conceallevelis managed per rendered/raw view. Known upstream limitation: concealed text +wrapkeeps stale line breaks (neovim issue #14409), documented in https://github.com/MeanderingProgrammer/render-markdown.nvim/blob/HEAD/doc/limitations.md. Practical tradeoff: rendered mode is great for reading/journaling review; expect to live with<leader>umtoggling or anti-conceal while editing.
3. obsidian.nvim — fit for a non-Obsidian vault #
Repo (community fork, actively maintained; epwalsh/obsidian.nvim is the
legacy upstream): https://github.com/obsidian-nvim/obsidian.nvim
- A “workspace” is just a directory of markdown — no
.obsidian/config required.workspaces = { { name = "pype.dev", path = "~/projects/personal/pype.dev" } }is a valid setup. - Provides
:Obsidian today [OFFSET]/dailies,new_from_template,template(substitutions, date/time formats),backlinks,follow_link,search,link,links. See command list in README. - Completion of
[[wiki links and#tags via blink.cmp or nvim-cmp; newer versions do this through an in-process LSP so it works with any completion engine. - Caveats:
- Search/backlinks require
ripgrep. - Only activates inside workspace paths; the whole pype.dev repo would be
one workspace, so
:Obsidian searchscans posts+pages together (probably fine). - Default wikilink style is
[[id|alias]]-ish (wiki_link_id_prefix); the[[ slug ]]-with-spaces convention used by markata is configured viawiki_link_func. Alsodisable_frontmatter/customnote_frontmatter_funcmatters since it would otherwise write Obsidian-style frontmatter (id,aliases,tags) that markata doesn’t want. - Its built-in checkbox/conceal UI is deprecated in favor of
render-markdown.nvim — set
ui.enable = falseand let render-markdown handle visuals.
- Search/backlinks require
- Verdict: overlaps ~80% with the existing
pypeaday.dailymodule (daily notes, templates, backlinks). The genuinely new capability is[[completion and structured wikilink following — but marksman (already in lang.markdown) gives wikilink completion,gdlink following, andgrrbacklinks for free, so obsidian.nvim is optional rather than foundational. If adopted, keeppypeaday.dailyfor copier template creation and use obsidian.nvim only for links/completion.
4. Alternatives — brief survey #
- telekasten.nvim (https://github.com/nvim-telekasten/telekasten.nvim): telescope-based zettelkasten + journal; daily/weekly notes, templates, backlinks, calendar. Works, but low recent activity and it duplicates the existing copier+telescope workflow. Not recommended here.
- zk-nvim (https://github.com/zk-org/zk-nvim): Neovim frontend for
the
zkCLI (a real LSP + note DB). Solid and maintained, but it wants thezkbinary and azk-style notebook — another parallel system, not a fit for markata frontmatter/slugs. - neorg (https://github.com/nvim-neorg/neorg): still releasing (9.x),
but it’s its own
.norgfile format — incompatible with a markdown blog. Maintainer activity is low (focus shifted to theluxLua package manager): https://github.com/nvim-neorg/neorg/discussions/1673. Skip. - Preview:
markdown-preview.nvim(browser, in the extra,<leader>cp) is the maintained option.glow.nvimis abandoned — its own README points at render-markdown.nvim: https://github.com/ellisonleao/glow.nvim/ (forkshcode/nvim-glowexists but is a terminal renderer, no help for admonitions). For this site,markata’s own build/serve is the only faithful preview. - Focus: don’t install zen-mode/twilight. LazyVim already maps
Snacks.zen()to<leader>uzandSnacks.toggle.dim()to<leader>uD(folke’s snacks.nvim replaced his standalone plugins: https://github.com/folke/snacks.nvim/blob/main/docs/zen.md). - Tables:
tabularis already installed (:Tabularize /|), and prettier (via conform<leader>cf) aligns markdown tables automatically. If auto-growing tables are wanted,Kicamon/markdown-table-mode.nvimordhruvasagar/vim-table-modeare the options — probably unnecessary. - List/checkbox ergonomics:
bullets.vim(https://github.com/bullets-vim/bullets.vim) auto-continues lists on<CR>/o, renumbers withgN, indents with>>/<<, and toggles checkboxes with<leader>x— including partial-completion parent checkboxes. Perfect fit for prayer-request checklists. - Link editing nicety:
antonk52/markdowny.nvimadds vim-style surround ops for[text](url)links. Optional quality-of-life.
5. Spell / wrap / prose ergonomics #
- Already handled by LazyVim core:
spell+wrapFileType autocmd for markdown;<leader>us/<leader>uwtoggles;spelllang = "en". - Worth adding in an ftplugin/autocmd:
linebreak(wrap at words, not mid-word),breakindent(wrapped lines keep list indent),wrapmargin/colorcolumnhygiene, andconceallevel=2+concealcursor=ncif you want rendered-markdown to look clean while keeping cursor-line raw. Notesmoothscrollis globally disabled in this config (vim.opt.smoothscroll = false) — re-enable it locally for markdown if long wrapped paragraphs feel jumpy. - Prose LSPs:
- harper-ls (https://github.com/Automattic/harper,
https://writewithharper.com): Rust grammar/spelling LSP aimed at
developers; markdown-aware, fast, no Java. Installable via mason
(
harper_lsin lspconfig), every linter toggleable (linters.sentence_capitalization,long_sentences, etc.). Best current default for prose grammar. Caution: it flags in every buffer it attaches to — scope it tomarkdownfiletype only. - ltex-ls is dead —
valentjn/ltex-lsis archived (https://github.com/valentjn/ltex-ls). Maintained fork: ltex-plus/ltex-ls-plus (https://github.com/ltex-plus/ltex-ls-plus), still LanguageTool-based (heavy JVM, but deeper grammar rules). - vale (https://vale.sh): CLI style-guide linter; usable through
nvim-lint’s
valelinter. Best if you want house-style rules (write-good/proselint packs), more setup than value for journaling.
- harper-ls (https://github.com/Automattic/harper,
https://writewithharper.com): Rust grammar/spelling LSP aimed at
developers; markdown-aware, fast, no Java. Installable via mason
(
- Soft punctuation niceties:
pensieve/cmp-dictionaryare mostly dead ends; the spell dictionary viazg+ blinkbuffer/spellsource covers the practical case.
Recommended additions for this setup #
Ordered by value ÷ effort.
1. lang.markdown extra is already enabled (zero new code) #
~/.config/nvim/lua/config/lazy.lua line 53 already imports it. Verify
marksman attaches with :LspInfo in a note buffer. Then:
gdon<a href="/2025-09-13-notes/" class="wikilink" data-title="2025-09-13 Notes" data-description="yesterday: 2025-09-11-notes" data-date="2025-09-13">2025-09-13 Notes</a>jumps to the notegrr(LSP references) is a richer backlinks view than the live_grep pattern infind_daily_files/find_backlinks— keep the telescope one, it searches the spaced[[ slug ]]convention regardless of whether marksman resolves it.- Caveat: marksman treats the git root (
pype.dev) as the workspace, which is what we want. Verify it resolves the spaced[[ slug ]]form; if not, completion still works for[[slug]]and markata tolerates both.
2. Markdown writing-mode ftplugin (tiny, high value) #
~/.config/nvim/after/ftplugin/markdown.lua (LazyVim loads after/ftplugin
automatically — no spec needed):
vim.opt_local.linebreak = true -- wrap at word boundaries
vim.opt_local.breakindent = true -- keep list indentation on wrapped lines
vim.opt_local.smoothscroll = true -- undo the global `false` for prose
vim.opt_local.conceallevel = 2 -- conceal markup for rendered view
vim.opt_local.concealcursor = "nc" -- show raw text on the cursor line in insert
vim.opt_local.spell = true -- redundant w/ LazyVim autocmd, explicit is fine
-- map j/k to gj/gk for wrapped-line navigation (markdown buffers only)
vim.keymap.set({ "n", "x" }, "j", "gj", { buffer = true, remap = false })
vim.keymap.set({ "n", "x" }, "k", "gk", { buffer = true, remap = false })
3. render-markdown tweaks + a scripture callout + checkbox states #
-- lua/plugins/markdown.lua
return {
{
"MeanderingProgrammer/render-markdown.nvim",
opts = {
-- re-enable what LazyVim's extra disables
checkbox = {
enabled = true,
unchecked = { icon = " " },
checked = { icon = " " },
custom = {
praying = { raw = "[/]", rendered = " ", highlight = "RenderMarkdownWarn" },
},
},
callout = {
-- !!! scripture has no renderer; if you ever write
-- > [!scripture] in blog posts this makes it pretty.
scripture = {
raw = "[!SCRIPTURE]",
rendered = " Scripture",
highlight = "RenderMarkdownHint",
},
},
anti_conceal = { enabled = true }, -- cursor line shows raw markdown
},
},
}
Reality check: nothing renders !!! scripture blocks in the editor —
they’ll show as plain indented text (which is honest: markata is the only
real renderer). If visual distinction matters, util.mini-hipatterns is
already enabled — add a pattern:
-- inside the existing mini.hipatterns spec
local hipatterns = require("mini.hipatterns")
opts = {
highlighters = {
admonition = { pattern = "^!?%?+ +%w+.*", group = "Special" },
},
}
4. bullets.vim for prayer-request checklists (one line, high value) #
{ "bullets-vim/bullets.vim", ft = "markdown" },
<leader>x toggles - [ ]/- [x], <CR>/o continue list items,
>>/<< adjust nesting. Docs:
https://github.com/bullets-vim/bullets.vim
5. Optional, heavier lifts (only if felt needed) #
-
harper-ls grammar checking, scoped to markdown:
{ "neovim/nvim-lspconfig", opts = { servers = { harper_ls = { filetypes = { "markdown" }, settings = { ["harper-ls"] = { linters = { sentence_capitalization = false, long_sentences = false }, }, }, }, }, }, } -
obsidian.nvim for
[[completion +:Obsidian backlinks— only if marksman’s LSP completion of wikilinks proves insufficient. Keepui.enable = falseand continue usingpypeaday.daily+ copier for note creation. Expect to write awiki_link_functo emit[[ slug ]]and anote_frontmatter_funcmatching markata’s frontmatter.
Bottom line #
The copier+telescope daily-notes system is already doing the job of an
entire plugin category (telekasten/zk/obsidian daily notes). The real gaps
are: marksman wikilink navigation (free, already enabled via lang.markdown),
rendered checkboxes/callouts (render-markdown, in the extra), checkbox
toggling (bullets.vim), wrapped-line ergonomics (a 6-line ftplugin), and
optional grammar checking (harper-ls). !!! admonitions are a markata-side
concern — no editor plugin renders them; at most, highlight the marker line.