| name | nvim-doc |
| description | Write, update, and improve Neovim plugin help documentation (vimdoc) in doc/<plugin>.txt. Use when the user asks to write docs, update docs, generate the help file, add documentation for a function, or mentions vimdoc, help tags, or plugin documentation. Reads the plugin source code to extract API, commands, configuration, and other info from LuaCATS annotations and code structure, then writes a properly formatted doc/<plugin>.txt following vimdoc conventions. Do not use for general Neovim :help lookups (use nvim-help skill instead) or for writing README.md, CHANGELOG.md, or other non-vimdoc documentation.
|
| allowed-tools | Bash read edit write |
Neovim Plugin Documentation (vimdoc)
This skill writes and updates Neovim plugin help documentation. The output is
doc/<plugin>.txt — a plain text file that integrates with Neovim's :help
system using the vimdoc format.
Vimdoc format rules
These rules are derived from Neovim's own help files and established Neovim
plugin documentation. Follow them precisely.
General
- Text width: 78 characters (set by modeline
tw=78)
- Section separators: exactly 80
= characters, no trailing whitespace, no
blank line between the separator and the section header that follows it
- Tags:
*like-this* — lowercase, hyphens for sections, dots for functions
- Cross-references:
|like-this|
- Indentation within sections and code blocks: 2 spaces
- File must end with the modeline as the last line:
vim:tw=78:ts=8:et:ft=help:norl:
Section headers
Title in UPPERCASE left-aligned, tag right-aligned, total width 80 chars.
Pad with spaces so *tag* ends at column 80. Blank line after the header.
INTRODUCTION *myplug*
FEATURES *myplug-features*
CONFIGURATION *myplug-config*
Subsections
Lowercase or title-case followed by : ~. The : ~ suffix distinguishes
subsections from regular text.
Using lazy.nvim: ~
Install with...
Common Issues: ~
Issue: Something doesn't work ~
- Try this
Tags
- Sections:
*plugin-section-name* (lowercase, hyphens)
- Functions:
*plugin.function()* (includes parens)
- Submodule functions:
*plugin.submodule.function()*
- Plugin name = directory under
lua/
Function tags go on a separate line ABOVE the signature, right-aligned:
*myplug.setup()*
myplug.setup({opts}) ~
Configure the plugin.
For submodule functions, show the full require path in the signature:
*myplug.cli.get_blocks()*
require("myplug.cli").get_blocks() ~
Get raw blocks data.
Cross-references
|tag-name| for internal refs, also works for Neovim built-in help tags
(e.g. |nvim_set_keymap()|). Every cross-reference must resolve to an
existing tag — broken references are a serious error.
Table of contents
Inside INTRODUCTION. Numbered list with description and right-aligned tag,
padded so |tag| ends near column 80:
Table of contents:
1. FEATURES: What this plugin provides. |myplug-features|
2. REQUIREMENTS: Plugin dependencies and setup. |myplug-requirements|
3. INSTALLATION: How to install the plugin. |myplug-installation|
4. CONFIGURATION: Available options and their defaults. |myplug-config|
Code blocks
Delimited by > (with filetype) and < on their own lines. Content
indented 2 spaces. Multiple blocks can appear in sequence with text between:
>lua
require("myplug").setup({
option = "value",
})
<
Enable the component:
>lua
{ "some/dep.nvim", opts = { component = "myplug" } }
<
Filetypes: >lua, >vim, >bash. Every > must have a matching <.
Configuration docs
Show setup() signature, then a code block with ALL default options. Each
option has its default value and a comment with description and type:
>lua
{
name = "default", -- Description of name (string, default: "default")
verbose = false, -- Enable verbose output (boolean, default: false)
max_count = 10, -- Maximum items (number, default: 10)
on_done = nil, -- Callback when finished (function|nil)
}
<
Read the actual config/defaults module to get real defaults — never guess.
Command docs
:PluginName [args] ~
Description of what the command does.
- `subcommand1`: Description
- `subcommand2`: Description
Health check:
:checkhealth pluginname ~
Run health checks. Validates:
- Plugin installation
- Configuration validity
Function docs (API)
Strict layout: tag line → signature → description → Parameters → Return →
optional example.
Simple function:
*myplug.hello()*
myplug.hello() ~
Display a greeting.
Return format: ~
"Hello [name]"
With parameters:
*myplug.parse.item()*
myplug.parse.item({item}) ~
Convert a quickfix item to a formatted string.
Parameters: ~
{item} (`table`) A quickfix or location list item.
Return: ~
`string` The formatted representation.
Returning complex data — use a code block:
Return format: ~
>lua
{
blocks = {
{ id = "block-id", tokens = 1000, cost = 5.25 },
-- ... more blocks
}
}
<
Requirements
Bullet points with URLs. Optional deps marked with - optional:
- Neovim >= 0.10
- some-cli (https://example.com) for external tool integration
- lualine.nvim (https://github.com/nvim-lualine/lualine.nvim) - optional
Installation
lazy.nvim as primary example. Include dependencies in the spec if needed.
If the plugin is a template (e.g. the repo has "Use this template" on GitHub),
include the template-based workflow as a subsection before the lazy.nvim
install:
Using as a template: ~
1. Click "Use this template" on GitHub to create a new repository
2. Clone your new repository and customize for your plugin:
- Replace "base" with your plugin name throughout the codebase
- Replace "S1M0N38" with your GitHub username
- Update plugin description and functionality
After the install code block, optionally break down each field:
- `user/myplug.nvim`: The plugin's GitHub repository.
- `version`: Pin to semantic version.
- `opts`: See |myplug.setup()|.
- `dependencies`: Required/optional plugins.
Troubleshooting
Start with health check, then reproduction steps, then common issues:
Common Issues: ~
Issue: Something doesn't work ~
- Check step 1
- Verify step 2
Workflow
Step 1 — Discover the plugin
ls lua/
find lua/ -name "*.lua" | sort
ls plugin/
ls doc/
If no lua/ directory, use the project directory name, stripping .nvim.
Step 2 — Read the source code
Read plugin source to extract everything needing documentation. Read in this
priority order:
lua/<plugin>/init.lua — Main module, exports, setup()
lua/<plugin>/config.lua or defaults.lua — Default options
(most reliable source for config docs)
lua/<plugin>/types.lua — LuaCATS type annotations
plugin/<plugin>.lua — User commands, lazy-loading
lua/<plugin>/health.lua — Health check items
- Other
lua/<plugin>/*.lua — Submodules with public functions
README.md — Description (don't copy verbatim)
What to extract:
- setup() and config defaults: options, types, defaults, descriptions
- Exported functions: name, params (names + types), return type, behavior
- User commands: name, arguments, subcommands, completion
- Highlight groups: names, default links, descriptions
- Autocmds: events listened to or fired
- Keymaps: default keymaps
If LuaCATS annotations are sparse, infer from test files (tests/). If still
unclear, ask the user rather than guessing.
Step 3 — Read existing docs (if updating)
Read doc/<plugin>.txt fully before editing. When updating, the goal is
minimal changes — only touch what's stale or missing. Treat the existing
doc as the source of truth for style and structure.
- Preserve existing tag names — renaming breaks bookmarks and cross-refs
- Preserve section structure — never remove sections, even if they seem
redundant. Only remove entries within a section if the corresponding code
was deleted. Add new sections where they fit in the canonical order.
- Preserve narrative text — explanatory paragraphs, blank lines used
to separate concepts, and any prose that helps the reader. Don't strip
these out when updating.
- Preserve formatting alignment — keep the same column alignment used
in the existing doc for ToC entries, section headers, etc.
- Update stale descriptions — match current code behavior
- Add missing docs — new functions, options, commands
- Remove obsolete entries — only functions or options whose code was
actually deleted
Step 4 — Write the help file
Follow the format rules above precisely. Use this canonical section order
(omit sections that don't apply):
- INTRODUCTION —
*plugin* — Description, links, table of contents
- FEATURES —
*plugin-features* — Feature list. Include this section
when the plugin has meaningful features to highlight. If the README or
source code describes features, document them here.
- REQUIREMENTS —
*plugin-requirements* — Dependencies
- INSTALLATION —
*plugin-installation* — lazy.nvim install
- CONFIGURATION —
*plugin-config* — setup() options and defaults
- COMMANDS —
*plugin-commands* — User commands
- KEYMAPS —
*plugin-keymaps* — Default keymaps (if any)
- HIGHLIGHTS —
*plugin-highlights* — Highlight groups (if any)
- API or FUNCTIONS —
*plugin-api* — Public Lua functions
- EXAMPLES —
*plugin-examples* — Usage patterns (optional)
- DEVELOPMENT —
*plugin-development* — Testing, building (optional)
- TROUBLESHOOTING —
*plugin-troubleshooting* — Common issues
Step 5 — Validate
After writing, verify:
- Every
|cross-reference| points to an existing *tag*
- Every
> has a matching <
- No content line exceeds 78 characters
- Table of contents matches actual sections
- Function signatures match the source code
- No trailing whitespace on blank/separator lines
Quick validation:
grep -oP '\|[^|]+\|' doc/<plugin>.txt | tr -d '|' | sort -u | while read tag; do
if ! grep -q "\*${tag}\*" doc/<plugin>.txt; then
echo "BROKEN REFERENCE: |$tag|"
fi
done
Writing style
- Concise and factual. Every sentence helps the user do or understand something.
- Present tense: "Displays a greeting" not "Will display a greeting".
- Explain what and why, not how (implementation goes in code comments).
- Show a usage example if the function isn't obvious from its signature.
- Config options always show the default value.
- lazy.nvim as the primary (usually only) installation example.
- Mark optional dependencies clearly.
- Narrative prose is welcome — short paragraphs that explain the purpose of
a section or connect concepts make the docs more readable. Don't strip
these when updating an existing doc.
- Use blank lines to separate distinct concepts within a section (e.g.
between different installed plugins in a lazy.nvim spec). Don't collapse
these away.