| name | install-plugin |
| description | Install a Neovim plugin configuration from a GitHub URL. Usage '/install-plugin <github-url>'. Parses the URL, fetches plugin documentation, generates optimal lazy.nvim configuration with lazy loading, and saves to `./lua/plugins/`. Optionally updates README.md. |
Install Plugin Skill
Install a new Neovim plugin configuration from a GitHub URL with optimal lazy loading.
Input Format
/install-plugin <github-url>
Examples:
/install-plugin https://github.com/folke/flash.nvim
/install-plugin github.com/nvim-treesitter/nvim-treesitter-textobjects
/install-plugin folke/noice.nvim
Workflow
Step 1: Parse GitHub URL
Extract owner and repo name from the URL:
Input: https://github.com/folke/flash.nvim
github.com/author/plugin-name
author/plugin-name
Output:
- owner: folke
- repo: flash.nvim
- plugin_name: flash (derived from repo, removing .nvim/.vim suffix)
Step 2: Fetch Plugin Documentation
Use gh CLI or web fetch to get plugin README:
gh api repos/{owner}/{repo}/readme --jq '.content' | base64 -d
curl -s https://raw.githubusercontent.com/{owner}/{repo}/main/README.md
Key information to extract:
- Plugin purpose and category
- Required dependencies
- Setup/configuration options
- Recommended keymaps
- Lazy loading triggers (commands, events, filetypes)
- Any build steps required
Step 3: Scan Existing Keymaps (CRITICAL - Conflict Prevention)
BEFORE configuring any keymaps, you MUST scan ALL existing keymaps to avoid conflicts.
3.1 Scan Core Keymaps
Read ./lua/keymap.lua to extract all core keymaps:
vim.keymap.set({ "n" }, "<leader>w", ...)
vim.keymap.set({ "n", "x" }, ";", ...)
3.2 Scan All Plugin Keymaps
Read ALL files in ./lua/plugins/*.lua and extract keymaps from:
keys = {
{ "<leader>ff", ... },
{ "<tab>f", ... },
}
vim.keymap.set("n", "<leader>ga", ...)
map("n", "<leader>gb", ...)
3.3 Build Keymap Registry
Create a mental registry of ALL existing keymaps:
| Key | Mode | Plugin/Source | Description |
|---|
<leader>ff | n | telescope | find files |
<leader>w | n | keymap.lua | save all |
<tab>f | n | hop | hop char |
gd | n | telescope | goto definition |
s | n,x,o | (available) | - |
| ... | ... | ... | ... |
3.4 Conflict Check Rules
When the new plugin recommends keymaps, check:
- Exact match: Same key + same mode = CONFLICT
- Prefix conflict:
<leader>f conflicts with <leader>ff (blocks prefix)
- Mode overlap:
{ "n", "x" } overlaps with { "n" } = CONFLICT
3.5 Conflict Resolution
If a recommended keymap conflicts:
- DO NOT use the conflicting keymap
- Find alternative based on plugin category:
- Motion plugins: Try
<tab> prefix, s, S, gs, gz
- Git plugins: Try
<leader>g + available letter
- LSP plugins: Try
<leader>l + available letter
- File plugins: Try
<leader>f + available letter
- General: Try
<leader> + plugin initial + action
- Document the change: Note in output that keymap was changed from default
3.6 Common Available Key Patterns
These are typically safe (but VERIFY first):
<leader> + 2-3 letter combos not in use
<localleader> prefix (, in this config)
] and [ for next/prev actions
g prefix combinations (gz, gx, etc.)
IMPORTANT: Never assume a key is available. ALWAYS verify by scanning.
Step 4: Determine Lazy Loading Strategy
Based on plugin type, choose the BEST lazy loading approach:
| Plugin Type | Lazy Loading | Example |
|---|
| UI/Visual (statusline, colorscheme) | event = "VeryLazy" or priority = 1000 | lualine, material |
| Keybinding-triggered (motion, surround) | keys = {...} | hop, nvim-surround |
| Command-triggered (git, file explorer) | cmd = {...} | lazygit, neo-tree |
| Filetype-specific (language support) | ft = {...} | go.nvim, vim-markdown |
| LSP-related | event = "LspAttach" | trouble, aerial |
| Insert mode (completion, pairs) | event = "InsertEnter" | nvim-cmp, autopairs |
| Buffer read (syntax, treesitter) | event = {"BufReadPre", "BufNewFile"} | treesitter |
| Git-related | event = "VeryLazy" or on git commands | gitsigns, diffview |
Priority order for lazy loading (most to least lazy):
keys - Only loads when specific key is pressed
cmd - Only loads when command is executed
ft - Only loads for specific filetypes
event - Loads on Vim events
- No lazy loading - Loads at startup (avoid unless necessary)
Step 5: Generate Plugin Configuration
Create file at ./lua/plugins/{plugin_name}.lua
Template Structure:
local function plugin_config()
require("{plugin_module}").setup({
})
end
local {plugin_var} = {
"{owner}/{repo}",
dependencies = {
"nvim-lua/plenary.nvim",
},
keys = {
{
"<leader>xx",
function()
require("{plugin_module}").some_function()
end,
desc = "{plugin}: description",
},
},
cmd = { "PluginCommand", "AnotherCommand" },
ft = { "lua", "python" },
event = "VeryLazy",
opts = {
},
config = plugin_config,
}
return { {plugin_var} }
Step 6: Follow Existing Patterns
CRITICAL: Read 2-3 similar existing plugins in ./lua/plugins/ to match:
- Code style (indentation, spacing)
- Naming conventions
- Key mapping patterns (leader key is
')
- Config function patterns
Reference files by plugin type:
- Motion/navigation:
hop.lua, nvim-surround.lua
- Git:
gitsigns.lua, diffview.lua
- LSP/completion:
telescope.lua, nvim-cmp.lua
- UI:
lualine.lua, neo-tree.lua
- Filetype:
go.lua, vim-markdown.lua
Step 7: Write the Plugin File
Save to: ./lua/plugins/{plugin_name}.lua
Naming rules:
- Use lowercase
- Replace
.nvim or .vim suffix with nothing
- Use hyphens for multi-word names (e.g.,
todo-comments.lua)
Step 8: Update README.md (If Significant)
Only update README.md if the plugin:
- Adds new key mappings users should know
- Adds new commands
- Requires external tool installation
- Is a major feature addition
Update sections:
- Add to appropriate "Plugin Categories" section
- Add key mappings to "Key Mappings" section if applicable
- Add to "Required External Tools" if dependencies needed
Output Format
After creating the plugin:
✅ Created plugin: ./lua/plugins/{plugin_name}.lua
**Plugin**: {owner}/{repo}
**Lazy Loading**: {method} ({trigger})
**Dependencies**: {list or "None"}
**Key Mappings** (if any):
| Key | Action |
|-----|--------|
| ... | ... |
**Commands** (if any):
- :Command1
- :Command2
**Notes**:
- {Any special setup instructions}
- {External tools needed}
Examples
Example 1: Motion Plugin (key-based lazy loading)
Input: /install-plugin https://github.com/folke/flash.nvim
Output file ./lua/plugins/flash.lua:
local flash = {
"folke/flash.nvim",
event = "VeryLazy",
opts = {
modes = {
search = { enabled = false },
},
},
keys = {
{
"s",
function()
require("flash").jump()
end,
mode = { "n", "x", "o" },
desc = "flash: jump",
},
{
"S",
function()
require("flash").treesitter()
end,
mode = { "n", "x", "o" },
desc = "flash: treesitter",
},
},
}
return { flash }
Example 2: Command-based Plugin
Input: /install-plugin https://github.com/sindrets/diffview.nvim
Output file ./lua/plugins/diffview.lua:
local diffview = {
"sindrets/diffview.nvim",
dependencies = { "nvim-lua/plenary.nvim" },
cmd = { "DiffviewOpen", "DiffviewFileHistory" },
opts = {
enhanced_diff_hl = true,
},
}
return { diffview }
Example 3: Filetype-specific Plugin
Input: /install-plugin https://github.com/iamcco/markdown-preview.nvim
Output file ./lua/plugins/markdown-preview.lua:
local markdown_preview = {
"iamcco/markdown-preview.nvim",
ft = { "markdown" },
build = function()
vim.fn["mkdp#util#install"]()
end,
keys = {
{
"<leader>mp",
"<cmd>MarkdownPreviewToggle<cr>",
ft = "markdown",
desc = "markdown-preview: toggle",
},
},
}
return { markdown_preview }
Important Notes
- Always lazy load - Never load plugins at startup unless absolutely necessary
- Prefer
keys or cmd - These are the laziest loading methods
- Match existing style - Read similar plugins first
- Test the config - Verify syntax is correct before finishing
- Minimal config - Start with minimal setup, user can customize later
- Document keymaps - Always include
desc for key mappings
- Check for conflicts - Ensure keymaps don't conflict with existing ones
Checklist Before Completion