Skip to content

Coming from NvChad

mnml was built by an NvChad refugee, for NvChad refugees. The vim input handler is first-class — not a “vim emulation layer” bolted onto a modeless editor — and the leader system is a built-in which-key trie under <space> with the chord vocabulary you already have in your fingers. If you came in from nvim --clean plus NvChad, almost everything you reach for already works.

This page is the migration map. It assumes you know vim. The job here is to point at the handful of places where mnml’s chord differs from NvChad’s, surface the new chords mnml added (Harpoon, integrations, AI panes), and tell you which Neovim feature isn’t here so you can stop reaching for it.

standard is the default input style — flip it once and forget:

~/.config/mnml/config.toml
[editor]
input_style = "vim"

Or per-workspace at <workspace>/.mnml/config.toml if you want vim everywhere except one team’s onboarding repo. Switch at runtime any time:

:set input=vim
:set input=standard

The runtime swap is non-destructive — your buffers, cursor, undo history, and macros survive the handler change. Toggle from the palette as editor: toggle keymap, the chord <leader>tk, or the bufferline mode chip. The architecture is documented in Editing — the short version is that both handlers translate keys into the same closed EditOp set, so the editor and every pane around it never branch on which mode is active.

If you launched mnml without setting the config, force it for one run:

Terminal window
mnml --input vim ~/some/project

These are the chords NvChad ships with mnml’s equivalents alongside. Categories follow how you’d actually learn them.

These are pure-vim behavior, nothing to translate. mnml’s vim handler covers them as you’d expect:

  • Modes: Esc / i / a / o / O / S / c… / v / V / Ctrl-V / R — note the capital: Normal-mode s is flash, not substitute
  • Motions: hjkl, wbge, 0$^, f/t/F/T plus ; , repeat, %, gg/G, H/M/L, Ctrl-D/Ctrl-U/Ctrl-F/Ctrl-B, { / } for paragraph nav, ( ) for sentence nav
  • Operators: d / c / y / > / < / = / gU / gu / gq / gJ (no-space join) / ~ (toggle case)
  • Text objects: iw/aw, i(/a(, i"/a", ip/ap, is/as, plus tree-sitter if/af (function), ic/ac (class), ia/aa (argument), ii/ai (indent)
  • Visual-block (Ctrl-V) + I / A to insert/append on every line — the real multi-cursor for the column case

The statusline mode chip differentiates VISUAL (char), V-LINE (V), and V-BLOCK (Ctrl-V) — same purple background, different label and tooltip — so NvChad’s “which kind of visual am I in?” muscle memory transfers without squinting.

The . dot-repeat, jumplist (Ctrl-O / Ctrl-I), and changelist (g; / g,) all work. Macros (qa…q@a) and named/numbered registers ("ay, "+y, "0p) are persisted across restarts. Counts thread through macros — 5@a replays macro a five times, like vim.

A couple of edge-case motions that match vim exactly (and didn’t always):

  • $ lands on the line’s last printable char, not one cell past it. Paste after $ lands immediately after the last visible character.
  • G (bare) lands on the start of the last line, not the phantom row past a trailing newline.
  • * and # advance past the current match — the star jumps to the next occurrence of the word under the cursor (instead of finding the cursor’s current word).
  • V doesn’t snap the cursor down a row — the anchor moves to line_start, the cursor stays put, and '< / '> after a yank reflect the correct row range.
  • :%s/.../.../g is one undo step — a 12-match substitute reverts on one u, not twelve.
  • Charwise v is inclusive of the cell under the cursorv y yanks one character, v l l y yanks three, v l l d leaves defghij in abcdefghij. It used to come up one short on every v+motion d / c / y, and a bare v y yanked the empty string over your register. V and Ctrl-V were always correct.
  • zo opens and zc closes; only za toggles — all six of za zA zo zO zc zC used to be the same toggle, so zo twice closed a fold.

cc, guu, gUU, g~~ all operate on the full line and leave the cursor at the start of the next line, so g~~g~~g~~ walks down toggling case line by line.

See Editing for the full operator + text-object inventory; this page won’t repeat it.

What you do in NvChad What it is in mnml
:e <file> :e <file> — opens new buffer (creates if missing)
:bn / :bp / :bd :bn / :bp / :bd (also :b <name> fuzzy match)
<leader>fb (buffer picker) <leader>fb
:tabnew / gt / gT / :tabclose All present
:vsp / :sp :vsplit / :split, plus the <leader>sv / <leader>ss chords
Ctrl-w h/j/k/l Ctrl-w h/j/k/l (also <leader>sh/sj/sk/sl)
Ctrl-w w cycle Ctrl-w w (also <leader>sw)
Ctrl-w c close Ctrl-w c or Ctrl-w q (also <leader>sc)
Ctrl-w = equalize Ctrl-w =
Ctrl-w o close-others Ctrl-w o (also <leader>so)
Ctrl-w > < + - resize Ctrl-w > < + -
Ctrl-w T move to new tab Ctrl-w T
Ctrl-w f split-open file under cursor Ctrl-w f
Ctrl-w d split + goto definition Ctrl-w d
Ctrl-w n new scratch split Ctrl-w n

Ctrl-w H/J/K/L (move split to the far edge of the parent) and Ctrl-w x / Ctrl-w r (swap / rotate) work too. Maximize the active split with Ctrl-w _ (height) or Ctrl-w | (width).

NvChad mnml
/pattern ?pattern n N * # All present
:noh / :nohlsearch :noh / :nohlsearch
:%s/old/new/g (and /gc confirm) Yes — including ranges, :'<,'>s/…, :s//repl/g repeat-search
:g/pattern/d / :v/pattern/d Present
gf open file under cursor gf (mnml maps to editor.open_at_cursor)
gx open URL under cursor gx (opens in OS browser)
gd / gD LSP goto def / declaration gd / gD
Ctrl-] jump to tag (= goto def) Ctrl-] (mapped to lsp.goto_definition)
Ctrl-T jump back Ctrl-T (mapped to nav.back)
K hover docs K (LSP hover popup)

gi (jump to last-insert + insert), gI (insert at column 0), gv (restore last visual), g; / g, (changelist) are present.

All present with vim’s exact semantics:

  • ma set local mark, mA global mark
  • 'a jump to line, `a jump to exact column
  • "ay / "ap, "+y / "+p (system clipboard), "*y / "*p (X11/Wayland primary)
  • "0p last yank, "1p"9p delete ring
  • qaq record, @a replay, 5@a replay 5×, @@ repeat last

Marks + macros persist across mnml restarts via per-workspace <workspace>/.mnml/ storage. The delete ring resets at startup (vim parity).

  • Ctrl-R <reg> paste register inline (vim canonical)
  • Ctrl-V <key> insert next keystroke verbatim (use for literal Tab, etc.)
  • Ctrl-O <cmd> one-shot Normal — fire one normal command then back to Insert
  • Ctrl-N / Ctrl-P walk the completion popup
  • Ctrl-Space request LSP completion explicitly

The vim chords are directional, the way :help zo describes them — zo opens and stays open, zc closes and stays closed, and za is the only one that alternates.

Chord mnml Command
za / zA toggle at cursor editor.toggle_fold
zo / zO open (idempotent) editor.open_fold
zc / zC close (idempotent) editor.close_fold
zf fold enclosing bracket pair; in Visual, fold the selection editor.toggle_fold / editor.fold_selection
zR / zE open every fold editor.unfold_all
zM fold every multi-line bracket pair editor.fold_all_brackets
zj / zk next / previous top-level fold editor.fold_next / editor.fold_prev

zO / zC are the recursive forms in vim. mnml’s folds are line-based with a single level per header, so they collapse onto the plain open/close rather than being dead chords — the same call zA already made. LSP-supplied fold ranges and indent-fallback folds both work, and the fold set persists across buffer close and mnml restarts.

<space> is the leader in vim mode (it’s Ctrl-K in standard mode — same trie, different entry chord). After <space> a which-key popup paints the available continuations. Press the next char to descend; press Esc to back out. Press ? at the root for a full cheatsheet pane.

What follows is every chord the built-in trie ships with. Source of truth: src/whichkey.rs. Categories match the trie groups.

Chord Command Notes
<leader>ff picker.files Fuzzy file picker (NvChad parity)
<leader>fb picker.buffers Open-buffer picker
<leader>fg find.grep Workspace live-grep (NvChad parity — added 2026-06-08)

:Rg <pattern> / :vimgrep and Ctrl-Shift-F also work for the workspace-grep pane.

Chord Command
<leader>bn buffer.next
<leader>bp buffer.prev
<leader>bd buffer.close
<leader>br buffer.reopen (reopen the last-closed)

NvChad’s “close all but this” doesn’t have a chord today — palette: buffer: close others.

Chord Command
<leader>te view.toggle_tree (file explorer)
<leader>tk editor.toggle_keymap (vim ⇄ standard)
<leader>tt theme.pick (theme picker)
<leader>th view.toggle_hidden (hidden files in focused tree node)
<leader>tH view.toggle_hidden_all (hidden files everywhere)

A deeper surface than NvChad ships. The full git story is on Git.

Chord Command
<leader>gd diff file
<leader>gD diff worktree
<leader>gA diff all vs HEAD (multi-file)
<leader>gp peek change at cursor
<leader>gb blame toggle
<leader>gc commit
<leader>gl commit graph
<leader>gs status / staging pane
<leader>gm AI (Claude) commit message
<leader>gM AI rewrite of HEAD’s message
<leader>gx Codex commit message
<leader>go checkout branch
<leader>gn new branch
<leader>gw worktrees → shell
<leader>gS stash (prompts for message)
<leader>gP stash pop
Chord Command
<leader>la code actions
<leader>lc complete at cursor
<leader>ls symbols in this file
<leader>lS workspace symbols
<leader>lo outline pane
<leader>ld goto definition
<leader>lh hover docs
<leader>lr find references
<leader>lR rename symbol
<leader>le diagnostics list
<leader>ln next diagnostic
<leader>lp prev diagnostic

Mirror of Ctrl-w but via leader — handy when you set up a layout from scratch.

Chord Command
<leader>sv split right
<leader>ss split down
<leader>sh/j/k/l focus left/down/up/right
<leader>sw focus next split
<leader>sc close split
<leader>so close others

mnml ships an in-editor HTTP client (.http / .curl / .rest files). See HTTP client.

Chord Command
<leader>hs send request
<leader>hy copy as curl
<leader>hd ask Claude (debug)
Chord Command
<leader>Ta run all
<leader>Tf run this file
<leader>Tt run test at cursor
<leader>Tl re-run last-failed
<leader>Th heal failing test (Claude)
<leader>Tw flaky/wobbly dashboard
Chord Command
<leader>Pp cross-host PR picker
<leader>Pr refresh cross-host cache (background)

See Cross-host PR workflow.

The integration siblings (forge / cloud / observability viewers) launch from here. Each chord opens a separate sibling binary as a pane — the sibling has to be installed for the chord to do anything visible. All of these siblings are installable via the Marketplace tab; once installed, mnml core’s pre-registered chords fire without extra config.

Chord Command Sibling
<leader>ib Bitbucket viewer mnml-forge-bitbucket
<leader>ig GitHub viewer mnml-forge-github
<leader>il GitLab viewer mnml-forge-gitlab
<leader>iz Azure DevOps viewer mnml-forge-azdevops
<leader>ij Jira viewer mnml-tracker-jira
<leader>ic AWS CodeBuild mnml-aws-codebuild
<leader>iw CloudWatch Logs mnml-aws-cloudwatch-logs
<leader>ia AWS Amplify mnml-aws-amplify
<leader>iL AWS Lambda mnml-aws-lambda
<leader>ie AWS EventBridge mnml-aws-eventbridge
<leader>id DynamoDB mnml-db-dynamodb
<leader>is S3 browser mnml-fs-s3
<leader>iA Azure Blob mnml-fs-azure-blob
<leader>iR RDS mnml-aws-rds
<leader>iC ECS mnml-aws-ecs
<leader>iE ECR mnml-aws-ecr
<leader>io Cognito mnml-aws-cognito
<leader>iq SQS mnml-aws-sqs
<leader>iN SNS mnml-aws-sns
<leader>iD Datadog mnml-datadog
<leader>iK Docker mnml-docker
<leader>iF Cloudflare mnml-cloudflare
<leader>iG Gmail mnml-gmail
<leader>iS Slack mnml-slack
<leader>iT Teams mnml-teams
<leader>iM Mandrill mnml-mandrill
<leader>iB Buttondown mnml-buttondown
<leader>ih htop system binary (mnml offers brew install / apt install if missing)
<leader>iI iftop system binary (mnml offers brew install / apt install if missing)
<leader>ir btop system binary (mnml offers brew install / apt install if missing)
Chord Command
<leader>aa ask Claude
<leader>ae explain selection
<leader>af fix bugs
<leader>ar refactor
<leader>aw write tests
<leader>am mirror Claude session
<leader>ac open Claude Code
<leader>aC Claude chat (with context)
<leader>ax open Codex
<leader>at shell pane
<leader>aM mixr DJ panel

Note the capital — lowercase i is taken by integrations. NvChad’s <leader>i for “insert” needed to move; capital I keeps the muscle memory close.

Chord Command
<leader>Is snippet picker
<leader>Ix expand snippet at cursor

The ThePrimeagen Harpoon idiom — pin a small set of “I keep coming back to these” files, jump to them by index. mnml ships it as a built-in.

Chord Command
<leader>Ha pin active file
<leader>Hm menu / picker
<leader>1<leader>9 jump to harpoon slot 1–9
Chord Command
<leader>w save (write)
<leader>q close buffer
<leader>e toggle file tree
<leader>p command palette
<leader>o run task (palette-style task runner)
<leader>m markdown preview
<leader>B open browser (Chrome via CDP)
<leader>r restart mnml
<leader>? cheatsheet pane (every chord → command)

Honest list of places where NvChad muscle memory doesn’t translate cleanly.

This is the biggest single divergence from vim canon, and it’s on purpose. In mnml’s Normal mode, s starts a flash/leap-style two-character jump:

  1. s arms it.
  2. Type two characters you can see at the target.
  3. Every visible occurrence of that pair gets a one-character label. Press a label to jump, or Esc to cancel.

Three keystrokes, not two — and step 3 is what trips people. s g a over a line containing gamma paints an f on top of the ga, so the line momentarily reads famma and the cursor hasn’t moved. That’s flash armed and waiting, not a corrupted buffer; a bug report once filed s as “dead” after stopping at step 2. mnml now paints a cue on the pane’s bottom row while labels are up:

ga → press a label to jump · Esc cancels

Matching is case-insensitive and limited to the visible viewport (at most 60 labels). Labels never reuse the two characters you typed. A jump goes on the nav back-stack, so Alt-Left returns.

Two asymmetries to keep straight:

  • Vim’s substitute is cl — same edit, one more keystroke.
  • S still substitutes the whole line (3S does three lines, like 3cc). Only the lowercase half of the pair was reassigned.

Visual-mode s is untouched: it still changes the selection.

NvChad puts “insert” group under <leader>i. mnml has 28 integration siblings (one of them named mnml-tickets-jira<leader>ij), so <leader>i is the integrations group. Snippets live under capital <leader>I instead. The trie test integrations_group_is_reachable enforces this — there was a regression in May 2026 where the two groups collided and silently nuked integrations.

<leader>w closes a buffer? No — it saves

Section titled “<leader>w closes a buffer? No — it saves”

<leader>w is file.save (write). For “close buffer” use <leader>q (or :bd, or <leader>bd). The single-letter <leader>w matches more of the vim-ism of :w than NvChad’s “window-close” interpretation.

Ctrl-D / Ctrl-U half-page scroll vs multi-cursor

Section titled “Ctrl-D / Ctrl-U half-page scroll vs multi-cursor”

NvChad keeps Ctrl-D as vim’s half-page-down. In mnml’s vim mode it’s the same — Ctrl-D scrolls a half page. (mnml’s standard-mode Ctrl-D is the VS-Code-style “add next occurrence” multi-cursor chord, but that’s a different mode entirely.)

There’s no :Telescope ex command. The two pickers you’d want:

  • Ctrl-P opens the file picker (also <leader>ff / picker.files)
  • Ctrl-Shift-P opens the command palette (also F1)

Fuzzy-search is built-in across both — Ctrl-N / Ctrl-P walk results, Enter picks.

:Telescope find_files etc. — palette instead

Section titled “:Telescope find_files etc. — palette instead”

The command palette (Ctrl-Shift-P / <leader>p) is the catch-all. Every command — every chord, every ex command, every plugin action — is reachable from it by name. If you forget a chord, search the palette for what you want to do.

mnml’s “plugins” model is two parts: registered commands (Rust-side, in src/command.rs) and out-of-process sibling binaries launched as Pty panes via :term <binary>. There’s no Lua, no Packer/Lazy, no per-buffer autocmds. If you need a thing, either it’s already there as a command + chord, or you write a sibling.

Treesitter is on by default — no :TSInstall

Section titled “Treesitter is on by default — no :TSInstall”

Tree-sitter highlighting + text objects (if/af, ic/ac, ia/aa, ii/ai) are baked in. Languages are bundled, no per-install step. If a language isn’t highlighting, file an issue — that’s a missing grammar, not a config problem.

No which-key.nvim plugin to configure — the trie IS the config

Section titled “No which-key.nvim plugin to configure — the trie IS the config”

The leader trie is the source of truth at src/whichkey.rs. A [keys.leader] config overlay for user-extensions is a planned refinement (today the trie is built-in); the popup itself is always on.

A 60-second path from “fresh install” to “I can work like I did in NvChad.”

  1. Set vim mode in ~/.config/mnml/config.toml:

    [editor]
    input_style = "vim"
  2. Launch in your workspace:

    Terminal window
    mnml ~/some/project
  3. Check the mode chip in the bottom-left of the statusline. It should read NORMAL (block cursor). If it doesn’t, :set input=vim and try again.

  4. Try a leader chord — press <space>, wait a beat, the which-key popup should paint. Press f to descend into find, then f to open the file picker.

  5. Press <leader>? to open the cheatsheet pane — every chord, every command, searchable.

You’re in. The rest is muscle memory you already have.

  • Editing — the architectural framing, ex commands, vim-surround, multi-cursor specifics
  • Settings & configuration — TOML schema, the settings overlay, every config knob
  • LSP — language servers, completion, code actions, refactors
  • Git — the deeper git workflow under <leader>g
  • Cross-host PR workflow<leader>Pp + the multi-host PR cache
  • Coming from VS Code — the other half of the migration story, for teammates