Neovim config for remote machines

This is my Neovim configuration, published so that I, or an agent working on my behalf, can put it on any machine I SSH into with one command. The config is frozen: the lockfile is the contract, and the files here are byte-for-byte what I run locally.

curl -fsSL https://www.mfserna.dev/nvim/install.sh | sh

If nvim is missing or older than 0.11, add --install-nvim and the script fetches the official release tarball into ~/.local/opt/nvim (no sudo, no package manager):

curl -fsSL https://www.mfserna.dev/nvim/install.sh | sh -s -- --install-nvim

For a machine with no git or no outbound network beyond this download, install the plugin-free variant instead:

curl -fsSL https://www.mfserna.dev/nvim/install.sh | sh -s -- --minimal

Files

Requirements

Hard requirements for the full config: nvim 0.11 or newer (the config uses vim.lsp.config, vim.lsp.enable, and vim.uv), git (lazy.nvim clones plugins), and curl or wget for the download. The minimal variant needs only nvim 0.11+ and curl or wget.

Optional tools, and what each unlocks:

The installer prints which optional tools it found so you can decide whether the machine needs more.

What the installer does

  1. Checks for nvim ≥ 0.11. With --install-nvim, downloads the stable tarball for the detected OS and architecture from the Neovim GitHub releases into ~/.local/opt/nvim and links ~/.local/bin/nvim. It prints a note if that directory is not on PATH.
  2. Downloads init.lua, lazy-lock.json, and syntax/baml.vim (or just init.min.lua with --minimal) into a temporary directory.
  3. If $XDG_CONFIG_HOME/nvim (default ~/.config/nvim) exists and its init.lua differs, moves it to nvim.bak.<timestamp>. If it already matches, it refreshes in place with no backup. It never deletes anything.
  4. Copies the files into place.
  5. Runs nvim --headless "+Lazy! restore" +qa to install the pinned plugins, then counts the directories in $XDG_DATA_HOME/nvim/lazy against the lockfile. Skip this with --no-sync.
  6. Reports optional tooling.

--dry-run prints every step without writing. The script writes only to the config directory, Neovim's data directory, and, with --install-nvim, ~/.local/opt/nvim and ~/.local/bin/nvim.

Language servers are installed by Mason on the first interactive launch, not by the installer, because mason-lspconfig installs them asynchronously and a headless +qa would cut that short. Open nvim once and let :Mason finish, or run :MasonInstall for a specific server.

Verify

nvim --headless +checkhealth +qa
nvim --headless "+Lazy! check" +qa

Both should exit 0. To check that a remote machine is on the published config rather than a drifted copy:

curl -fsSL https://www.mfserna.dev/nvim/init.lua | diff - ~/.config/nvim/init.lua
curl -fsSL https://www.mfserna.dev/nvim/lazy-lock.json | diff - ~/.config/nvim/lazy-lock.json

No output means no drift.

Manual install

For a machine where piping to sh is not acceptable, the files are plain static downloads:

mkdir -p ~/.config/nvim/syntax
curl -fsSL https://www.mfserna.dev/nvim/init.lua -o ~/.config/nvim/init.lua
curl -fsSL https://www.mfserna.dev/nvim/lazy-lock.json -o ~/.config/nvim/lazy-lock.json
curl -fsSL https://www.mfserna.dev/nvim/syntax/baml.vim -o ~/.config/nvim/syntax/baml.vim
nvim --headless "+Lazy! restore" +qa

What is in the config

Gruvbox, lualine, bufferline, nvim-tree, Telescope with fzf-native, nvim-cmp with LuaSnip and friendly-snippets, gitsigns, toggleterm, which-key, Comment.nvim, indent-blankline, and nvim-autopairs. LSP goes through nvim-lspconfig and Mason, with rustaceanvim and crates.nvim for Rust, nvim-jdtls for Java, clangd flags for C and C++, and a hand-wired BAML server. Leader is space; <leader>f finds, <leader>g is git, <leader>l is LSP, <leader>r is Rust, <leader>c shells out to the Cursor CLI, and Ctrl-\ toggles a terminal. Tabs are four spaces, folds come from treesitter and start open, diagnostics show in a float on hover rather than as virtual text, and search highlighting clears itself when the cursor leaves the match.

Back to the lab · Markdown · Document surface