Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsBlogPro
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Authors
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges
  • Chrome Extension
  • Skill Manager

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

ProTermsPrivacyRefunds
Back to skills

Neovim

BSecurity

Neovim is a terminal text editor configured in Lua, with a built-in LSP client, Treesitter parsing and, since 0.12, a built-in plugin manager (vim.pack). Use this skill to install Neovim, write or repair an init.lua, add plugins, wire up language servers with vim.lsp.config and vim.lsp.enable, set up format-on-save, or run Neovim headless for scripted edits. Trigger phrases: "set up neovim", "fix my init.lua", "neovim LSP not working", "lspconfig deprecated warning", "add a plugin to nvim", "...

155 stars
0 votes
0 copies
0 views
Added 10/4/2026
developmenttypescriptpythongobashreactgitapi

Works with

terminalcliapi

Security Analysis

B84/100
mediumUses curl or wget to download content
criticalModifies startup scripts or system services for persistence

Pro scans all 2 files and shows the line behind each finding

Scanned 10/4/2026

$npx -y skills add TerminalSkills/skills --skill neovim --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Neovim?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Neovim
[![Security: B — Skills Directory](https://www.skillsdirectory.com/api/skills/terminalskills-neovim/badge)](https://www.skillsdirectory.com/skills/terminalskills-neovim)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
Files
SKILL.md
---
name: neovim
description: >-
  Neovim is a terminal text editor configured in Lua, with a built-in LSP client,
  Treesitter parsing and, since 0.12, a built-in plugin manager (vim.pack). Use
  this skill to install Neovim, write or repair an init.lua, add plugins, wire up
  language servers with vim.lsp.config and vim.lsp.enable, set up format-on-save,
  or run Neovim headless for scripted edits. Trigger phrases: "set up neovim",
  "fix my init.lua", "neovim LSP not working", "lspconfig deprecated warning",
  "add a plugin to nvim", "nvim --headless", "format on save in neovim".
license: Apache-2.0
compatibility: "Neovim 0.12+ for vim.pack (0.11+ for vim.lsp.config/enable); git for plugin installs; language servers installed separately"
metadata:
  author: terminal-skills
  version: "1.0.0"
  category: development
  tags: ["neovim", "lua", "lsp", "treesitter", "text-editor"]
  repository: https://github.com/neovim/neovim
---

# Neovim — Lua-configured terminal editor with built-in LSP

## Overview

Neovim (`nvim`) is a Vim-based editor that runs in a terminal and is configured with Lua. It ships an LSP client (diagnostics, go-to-definition, rename, formatting), Treesitter (syntax trees for highlighting, folding and queries) and, from 0.12, `vim.pack`, a Git-based plugin manager with a lockfile. The current stable line is 0.12.x (0.12.5 at the time of writing).

An agent cannot usefully drive the interactive UI, but it can do most of the setup work: install the binary, write `init.lua`, pin plugins, configure language servers, check the config for errors and run Neovim headless for batch edits. This skill covers those jobs.

## Instructions

### Installation

Package managers first; check the version afterwards, because distribution packages often lag behind and `vim.pack` needs 0.12.

```bash
brew install neovim            # macOS or Linux with Homebrew
winget install Neovim.Neovim   # Windows
sudo pacman -S neovim          # Arch
nvim --version | head -1       # expect NVIM v0.12.x
```

If the distro package is too old, use the official release archive (download, then extract as a separate step):

```bash
VER=v0.12.5
curl -LO https://github.com/neovim/neovim/releases/download/$VER/nvim-linux-x86_64.tar.gz
# GitHub records a SHA-256 digest for every release asset; compare before extracting
WANT=$(curl -s https://api.github.com/repos/neovim/neovim/releases/tags/$VER \
  | jq -r '.assets[] | select(.name == "nvim-linux-x86_64.tar.gz") | .digest' | cut -d: -f2)
echo "$WANT  nvim-linux-x86_64.tar.gz" | sha256sum -c -   # must print OK
sudo tar -C /opt -xzf nvim-linux-x86_64.tar.gz
echo 'export PATH="/opt/nvim-linux-x86_64/bin:$PATH"' >> ~/.bashrc
```

Prepending puts the new binary ahead of an older `/usr/bin/nvim`. Archives exist for `linux-arm64`, `macos-arm64` and `macos-x86_64` too.

### Config layout

- `~/.config/nvim/init.lua` — entry point (`:echo stdpath('config')` shows the real path).
- `~/.config/nvim/lua/<name>.lua` — modules loaded with `require('<name>')`.
- `~/.config/nvim/lsp/<server>.lua` — a language-server config returned as a table.
- `~/.config/nvim/after/lsp/<server>.lua` — overrides that win over plugin-provided configs.
- `~/.config/nvim/nvim-pack-lock.json` — the `vim.pack` lockfile; commit it with the config.

To try a config without touching the user's, set `NVIM_APPNAME`: Neovim then reads `~/.config/<name>` and keeps separate data and state directories.

```bash
NVIM_APPNAME=nvim-trial nvim
```

### Plugins with vim.pack (0.12+)

`vim.pack.add()` clones missing plugins into the data directory (`site/pack/core/opt`) and loads them. It needs `git` and is marked experimental in the docs.

```lua
vim.pack.add({
  'https://github.com/neovim/nvim-lspconfig',
  { src = 'https://github.com/nvim-treesitter/nvim-treesitter', version = 'main' },
})
```

- `vim.pack.update()` fetches updates and opens a review buffer: `:write` applies, `:quit` discards. `vim.pack.update(nil, { force = true })` skips the review.
- `vim.pack.update(nil, { target = 'lockfile' })` moves plugins back to the lockfile revisions.
- To remove a plugin, first delete it from the `add()` list and `:restart`, then run `vim.pack.del({ 'plugin-name' })`. `del()` refuses a plugin that is still loaded unless you pass `{ force = true }`.
- Build steps go in a `PackChanged` autocommand defined before `vim.pack.add()`.

Third-party managers such as lazy.nvim still work; do not mix two managers for the same plugin.

### Language servers (vim.lsp.config / vim.lsp.enable)

Neovim provides the client; servers are separate programs on `PATH`. nvim-lspconfig ships ready-made configs in its `lsp/` directory, so after installing it one line per server is enough:

```lua
vim.lsp.enable({ 'pyright', 'ruff', 'ts_ls', 'lua_ls' })
```

Customise with `vim.lsp.config()`; it merges over the plugin's defaults:

```lua
vim.lsp.config('lua_ls', {
  settings = { Lua = { runtime = { version = 'LuaJIT' } } },
})
vim.lsp.config('pyright', { root_markers = { 'pyproject.toml', '.git' } })
vim.lsp.config('*', {   -- fallback for fields a server's own config leaves unset
  capabilities = { textDocument = { semanticTokens = { multilineTokenSupport = true } } },
})
```

`'*'` has the lowest priority: nvim-lspconfig's `lsp/<server>.lua` files override it, so setting `root_markers` there changes nothing. Set root markers per server, as above, or in `after/lsp/<server>.lua`.

A server that nvim-lspconfig does not know needs `cmd`, `filetypes` and `root_markers`. The old `require('lspconfig').<server>.setup{}` framework is deprecated; replace each call with `vim.lsp.config` (settings) plus `vim.lsp.enable` (activation).

Built-in keymaps once a server attaches: `K` hover, `grn` rename, `grr` references, `gri` implementation, `gra` code action, `gO` document symbols, `CTRL-S` signature help in insert mode, and `CTRL-]` jumps to the definition through 'tagfunc'. `:lsp restart` and `:lsp stop` manage clients.

### Format on save and completion

Some servers (ruff, for example) register formatting only after they attach, so check capability when saving rather than inside `LspAttach`:

```lua
vim.api.nvim_create_autocmd('BufWritePre', {
  group = vim.api.nvim_create_augroup('my.format', {}),
  callback = function(ev)
    if #vim.lsp.get_clients({ bufnr = ev.buf, method = 'textDocument/formatting' }) > 0 then
      vim.lsp.buf.format({ bufnr = ev.buf, timeout_ms = 2000 })
    end
  end,
})

vim.api.nvim_create_autocmd('LspAttach', {
  group = vim.api.nvim_create_augroup('my.lsp', {}),
  callback = function(ev)
    local client = assert(vim.lsp.get_client_by_id(ev.data.client_id))
    if client:supports_method('textDocument/completion') then
      vim.lsp.completion.enable(true, client.id, ev.buf, { autotrigger = true })
    end
  end,
})
```

With several formatters attached, pass `name = 'ruff'` or a `filter` function to `vim.lsp.buf.format()`.

### Treesitter

Neovim bundles parsers for C, Lua, Markdown, Vimscript, Vimdoc and Treesitter queries. Other languages need parsers, usually from nvim-treesitter (its `main` branch requires Neovim 0.12, `tree-sitter-cli` and a C compiler; the old `master` branch is frozen).

```lua
require('nvim-treesitter').install({ 'python', 'typescript', 'tsx' })

vim.api.nvim_create_autocmd('FileType', {
  pattern = { 'python', 'typescript', 'typescriptreact', 'lua' },
  callback = function(ev)
    -- pcall: the parser may not be installed yet (install() is asynchronous)
    if pcall(vim.treesitter.start, ev.buf) then
      vim.wo[0][0].foldexpr = 'v:lua.vim.treesitter.foldexpr()'
      vim.wo[0][0].foldmethod = 'expr'
    end
  end,
})
```

Without the `pcall`, every buffer of a language whose parser is missing raises "Parser could not be created". To install parsers before first use, for example on a new machine, wait for the install in a headless run:

```bash
nvim --headless -c "lua require('nvim-treesitter').install({ 'python', 'typescript', 'tsx' }):wait(300000)" -c qa
```

After updating nvim-treesitter, run `:TSUpdate` so parsers match the plugin.

### Headless and scripted use

```bash
nvim --headless +qa                                  # load the config, install vim.pack plugins, exit
nvim --headless "+checkhealth vim.lsp" "+write! lsp-health.txt" +qa
nvim --headless -c 'lua vim.pack.update(nil, { force = true })' -c qa
nvim -l scripts/report.lua src/app.lua               # run a Lua script with Neovim's API, then exit
```

- `nvim -l script.lua args…` skips the user config, exposes arguments as `arg[1]…`, and sends `print()` to stderr; use `io.write()` for stdout.
- `nvim --clean` starts with no user config or plugins — the fastest way to tell a config bug from a Neovim bug.
- `nvim --headless +qa` exits 0 even when `init.lua` fails. To get a failing exit code, test `v:errmsg`: `nvim --headless -c 'if v:errmsg != "" | cquit 1 | endif' -c qa`.

## Examples

### Example 1: Python IDE features over SSH

**User request:** "Set up Neovim on the build box for our `invoicing` Python service: pyright for types, ruff for lint and format on save."

```bash
uv tool install pyright   # PyPI wrapper; provides pyright-langserver
uv tool install ruff
```

`~/.config/nvim/init.lua`:

```lua
vim.g.mapleader = ' '
vim.o.number = true
vim.o.expandtab = true
vim.o.shiftwidth = 4
vim.o.undofile = true

vim.pack.add({ 'https://github.com/neovim/nvim-lspconfig' })
vim.lsp.enable({ 'pyright', 'ruff' })

vim.diagnostic.config({ virtual_text = true })
vim.keymap.set('n', '<leader>e', vim.diagnostic.open_float, { desc = 'Show diagnostic' })

vim.api.nvim_create_autocmd('BufWritePre', {
  group = vim.api.nvim_create_augroup('my.format', {}),
  callback = function(ev)
    if #vim.lsp.get_clients({ bufnr = ev.buf, method = 'textDocument/formatting' }) > 0 then
      vim.lsp.buf.format({ bufnr = ev.buf, timeout_ms = 2000 })
    end
  end,
})
```

```bash
nvim --headless +qa        # clones nvim-lspconfig and writes nvim-pack-lock.json
```

**Result:** opening `billing.py` inside the project (which has a `pyproject.toml`) attaches both servers with the project as root. Ruff flags "`os` imported but unused" and "Undefined name `totl`" inline, and `:w` rewrites `def total(items:list[float])->float:` as `def total(items: list[float]) -> float:` with two blank lines around top-level definitions.

### Example 2: Remove the lspconfig deprecation warning

**User request:** "After updating plugins I get 'The `require('lspconfig')` framework is deprecated, use vim.lsp.config'. Fix my config for TypeScript and Lua."

Old code:

```lua
require('lspconfig').ts_ls.setup({ on_attach = on_attach })
require('lspconfig').lua_ls.setup({ settings = { Lua = { diagnostics = { globals = { 'vim' } } } } })
```

Replacement (keep nvim-lspconfig installed — its `lsp/` configs are still used):

```lua
vim.lsp.config('lua_ls', {
  settings = { Lua = { diagnostics = { globals = { 'vim' } } } },
})
vim.lsp.enable({ 'ts_ls', 'lua_ls' })
-- on_attach logic moves into an LspAttach autocommand (see Instructions)
```

```bash
nvim --headless -c 'if v:errmsg != "" | cquit 1 | endif' -c qa && echo config-ok
```

**Result:** `config-ok` prints, the warning is gone, and `:checkhealth vim.lsp` lists `ts_ls` and `lua_ls` under "Enabled Configurations".

### Example 3: Rename a class across a folder without opening the UI

**User request:** "Rename `BillingClient` to `LedgerClient` in every file under `handlers/`."

```bash
nvim --clean --headless -c 'argdo %s/\<BillingClient\>/LedgerClient/ge | update' -c qa handlers/*.py
grep -rn "LedgerClient" handlers/
```

**Result:** `handlers/refunds.py` and `handlers/invoices.py` are rewritten; `handlers/health.py`, which had no match, is left untouched because `update` writes only modified buffers. `\<…\>` keeps `BillingClientError` from being changed. For symbol-aware renames that follow imports, use `grn` with a language server instead.

## Guidelines

- Check `nvim --version` before writing config: `vim.pack` needs 0.12, `vim.lsp.config`/`vim.lsp.enable` need 0.11. Current nvim-lspconfig requires 0.11.3 or newer.
- Language servers are not bundled. Install them with the ecosystem's package manager and confirm the binary (`pyright-langserver`, `ruff`, `typescript-language-server`) is on `PATH` for the process that starts Neovim.
- Root markers (`pyproject.toml`, `package.json`, `.git`…) decide the workspace root. Without one, most servers (pyright, ruff, lua_ls) still attach in single-file mode with no root, so cross-file features are weaker. Servers marked `workspace_required` (eslint, biome, tailwindcss) do not attach at all outside a project. `:checkhealth vim.lsp` shows the resolved `cmd`, filetypes and root markers.
- Put the user's own overrides in `vim.lsp.config()` or `after/lsp/`, not in the plugin directory; plugin updates overwrite it.
- Commit `nvim-pack-lock.json` so another machine installs the same plugin revisions; do not edit it by hand.
- Before editing someone's config, back it up by copying, or work under `NVIM_APPNAME`. Do not delete the data directory to "fix" plugins; use `vim.pack.del()` or `vim.pack.update(nil, { target = 'lockfile' })`.
- Plugins are code from third parties that runs with the user's permissions. Pin to tags with `version = vim.version.range('1.0')` where a plugin publishes semver tags, and review `vim.pack.update()` changes before `:write`.
- Headless regex edits are text replacements, not refactors: they ignore scope, strings and comments. Use them for mechanical changes and check the diff afterwards.
- Do not use this skill for editor-agnostic tasks (formatting in CI, linting) — call the formatter or linter directly; for VS Code or Zed, use their own settings.

Attribution

TerminalSkillsTerminalSkills
View sourceSee grades on GitHubMore from TerminalSkills →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Clean Code

Pragmatic coding standards - concise, direct, no over-engineering, no unnecessary comments

304955 votes

Browser Extension Developer

Use this skill when developing or maintaining browser extension code in the `browser/` directory, including Chrome/Firefox/Edge compatibility, content scripts, background scripts, or i18n updates.

286712 votes

Seo Optimizer

SEO optimization with keyword analysis, readability assessment, technical validation, content quality. Use for search rankings, blog posts, content audits, or encountering keyword density, readability scores, meta tags, schema markup errors.

2222 votes

Google Official Seo Guide

Official Google SEO guide covering search optimization, best practices, Search Console, crawling, indexing, and improving website search visibility based on official Google documentation

1862 votes

Writing Plans

Use when you have a spec or requirements for a multi-step task, before touching code

2927051 votes
View all in development →