Neovim Setup Guide

Complete guide to integrating Bootspring with Neovim for terminal-based development.

Overview#

Neovim is a hyperextensible text editor. Bootspring integrates through:

  • Terminal commands - Run Bootspring from within Neovim
  • Custom commands - Vim commands for common operations
  • Status line - Display project status
  • LSP integration - Enhanced completions
  • Telescope - Fuzzy finding agents and skills

Prerequisites#

  • Neovim 0.8+ installed
  • Bootspring CLI installed (npm install -g bootspring)
  • Node.js 18+ installed
  • Plugin manager (lazy.nvim, packer, or vim-plug)

Installing Neovim#

macOS#

brew install neovim

Linux#

1# Ubuntu/Debian 2sudo apt install neovim 3 4# Fedora 5sudo dnf install neovim 6 7# Arch 8sudo pacman -S neovim

Windows#

winget install Neovim.Neovim

Basic Configuration#

Initialize Bootspring#

cd your-project bootspring init bootspring generate

Neovim Lua Configuration#

Add to ~/.config/nvim/lua/bootspring.lua:

1local M = {} 2 3-- Configuration 4M.config = { 5 default_agent = "frontend-expert", 6 auto_generate = false, 7 show_notifications = true, 8} 9 10-- Setup function 11function M.setup(opts) 12 M.config = vim.tbl_deep_extend("force", M.config, opts or {}) 13 M.create_commands() 14 M.create_keymaps() 15end 16 17-- Create user commands 18function M.create_commands() 19 -- Generate context 20 vim.api.nvim_create_user_command("BootspringGenerate", function() 21 M.generate() 22 end, { desc = "Regenerate Bootspring context" }) 23 24 -- Check status 25 vim.api.nvim_create_user_command("BootspringStatus", function() 26 M.status() 27 end, { desc = "Show Bootspring status" }) 28 29 -- Invoke agent 30 vim.api.nvim_create_user_command("BootspringAgent", function(opts) 31 M.invoke_agent(opts.args) 32 end, { nargs = "+", desc = "Invoke Bootspring agent" }) 33 34 -- Apply skill 35 vim.api.nvim_create_user_command("BootspringSkill", function(opts) 36 M.apply_skill(opts.args) 37 end, { nargs = 1, desc = "Apply Bootspring skill" }) 38 39 -- Quality check 40 vim.api.nvim_create_user_command("BootspringQuality", function(opts) 41 local preset = opts.args ~= "" and opts.args or "pre-commit" 42 M.quality(preset) 43 end, { nargs = "?", desc = "Run Bootspring quality check" }) 44 45 -- List agents 46 vim.api.nvim_create_user_command("BootspringAgents", function() 47 M.list_agents() 48 end, { desc = "List available agents" }) 49 50 -- Start workflow 51 vim.api.nvim_create_user_command("BootspringWorkflow", function(opts) 52 M.start_workflow(opts.args) 53 end, { nargs = 1, desc = "Start Bootspring workflow" }) 54end 55 56-- Create keymaps 57function M.create_keymaps() 58 local keymap = vim.keymap.set 59 local opts = { noremap = true, silent = true } 60 61 -- Leader key mappings (assuming <leader> is space or \) 62 keymap("n", "<leader>bg", ":BootspringGenerate<CR>", 63 vim.tbl_extend("force", opts, { desc = "Generate context" })) 64 keymap("n", "<leader>bs", ":BootspringStatus<CR>", 65 vim.tbl_extend("force", opts, { desc = "Show status" })) 66 keymap("n", "<leader>ba", ":BootspringAgent ", 67 vim.tbl_extend("force", opts, { desc = "Invoke agent" })) 68 keymap("n", "<leader>bq", ":BootspringQuality<CR>", 69 vim.tbl_extend("force", opts, { desc = "Quality check" })) 70 keymap("n", "<leader>bl", ":BootspringAgents<CR>", 71 vim.tbl_extend("force", opts, { desc = "List agents" })) 72end 73 74-- Helper: Run command and handle output 75function M.run_command(cmd, callback) 76 local output = vim.fn.system(cmd) 77 local success = vim.v.shell_error == 0 78 79 if callback then 80 callback(success, output) 81 else 82 if success then 83 vim.notify(output, vim.log.levels.INFO) 84 else 85 vim.notify("Error: " .. output, vim.log.levels.ERROR) 86 end 87 end 88 89 return success, output 90end 91 92-- Generate context 93function M.generate() 94 vim.notify("Generating Bootspring context...", vim.log.levels.INFO) 95 M.run_command("bootspring generate", function(success, output) 96 if success then 97 vim.notify("Context generated successfully", vim.log.levels.INFO) 98 else 99 vim.notify("Failed to generate context: " .. output, vim.log.levels.ERROR) 100 end 101 end) 102end 103 104-- Show status 105function M.status() 106 local success, output = M.run_command("bootspring status") 107 if success then 108 -- Open in floating window 109 local buf = vim.api.nvim_create_buf(false, true) 110 vim.api.nvim_buf_set_lines(buf, 0, -1, false, vim.split(output, "\n")) 111 112 local width = math.min(80, vim.o.columns - 4) 113 local height = math.min(20, vim.o.lines - 4) 114 115 vim.api.nvim_open_win(buf, true, { 116 relative = "editor", 117 width = width, 118 height = height, 119 col = (vim.o.columns - width) / 2, 120 row = (vim.o.lines - height) / 2, 121 style = "minimal", 122 border = "rounded", 123 title = " Bootspring Status ", 124 }) 125 end 126end 127 128-- Invoke agent 129function M.invoke_agent(args) 130 local parts = vim.split(args, " ", { trimempty = true }) 131 local agent = parts[1] or M.config.default_agent 132 local prompt = table.concat(vim.list_slice(parts, 2), " ") 133 134 if prompt == "" then 135 prompt = vim.fn.input("Prompt: ") 136 end 137 138 if prompt == "" then 139 vim.notify("No prompt provided", vim.log.levels.WARN) 140 return 141 end 142 143 vim.notify("Invoking " .. agent .. "...", vim.log.levels.INFO) 144 145 local cmd = string.format('bootspring agent invoke %s "%s"', agent, prompt) 146 local success, output = M.run_command(cmd) 147 148 if success then 149 -- Open result in split 150 vim.cmd("vnew") 151 local buf = vim.api.nvim_get_current_buf() 152 vim.api.nvim_buf_set_lines(buf, 0, -1, false, vim.split(output, "\n")) 153 vim.bo[buf].filetype = "markdown" 154 vim.bo[buf].buftype = "nofile" 155 vim.bo[buf].modifiable = false 156 end 157end 158 159-- Apply skill 160function M.apply_skill(pattern) 161 vim.notify("Applying skill: " .. pattern, vim.log.levels.INFO) 162 M.run_command("bootspring skill apply " .. pattern) 163end 164 165-- Run quality check 166function M.quality(preset) 167 vim.notify("Running quality check: " .. preset, vim.log.levels.INFO) 168 local success, output = M.run_command("bootspring quality " .. preset) 169 170 if success then 171 vim.notify("Quality check passed!", vim.log.levels.INFO) 172 else 173 -- Parse and show in quickfix 174 vim.fn.setqflist({}, "r", { title = "Bootspring Quality", lines = vim.split(output, "\n") }) 175 vim.cmd("copen") 176 end 177end 178 179-- List agents 180function M.list_agents() 181 local success, output = M.run_command("bootspring agent list") 182 if success then 183 local buf = vim.api.nvim_create_buf(false, true) 184 vim.api.nvim_buf_set_lines(buf, 0, -1, false, vim.split(output, "\n")) 185 186 vim.api.nvim_open_win(buf, true, { 187 relative = "editor", 188 width = 60, 189 height = 30, 190 col = (vim.o.columns - 60) / 2, 191 row = (vim.o.lines - 30) / 2, 192 style = "minimal", 193 border = "rounded", 194 title = " Available Agents ", 195 }) 196 end 197end 198 199-- Start workflow 200function M.start_workflow(workflow) 201 vim.notify("Starting workflow: " .. workflow, vim.log.levels.INFO) 202 203 -- Open in terminal 204 vim.cmd("terminal bootspring workflow start " .. workflow) 205end 206 207return M

Load in init.lua#

1-- ~/.config/nvim/init.lua 2 3-- Load Bootspring module 4require("bootspring").setup({ 5 default_agent = "frontend-expert", 6 auto_generate = false, 7 show_notifications = true, 8})

Plugin Manager Setup#

lazy.nvim#

1-- ~/.config/nvim/lua/plugins/bootspring.lua 2return { 3 { 4 dir = "~/.config/nvim/lua/bootspring.lua", 5 config = function() 6 require("bootspring").setup() 7 end, 8 }, 9}

packer.nvim#

1use { 2 "~/.config/nvim/lua/bootspring", 3 config = function() 4 require("bootspring").setup() 5 end, 6}

Telescope Integration#

Install Telescope#

-- lazy.nvim { "nvim-telescope/telescope.nvim", dependencies = { "nvim-lua/plenary.nvim" }, }

Bootspring Telescope Extension#

Create ~/.config/nvim/lua/telescope/_extensions/bootspring.lua:

1local pickers = require("telescope.pickers") 2local finders = require("telescope.finders") 3local conf = require("telescope.config").values 4local actions = require("telescope.actions") 5local action_state = require("telescope.actions.state") 6 7local M = {} 8 9-- Agent picker 10M.agents = function(opts) 11 opts = opts or {} 12 13 local output = vim.fn.system("bootspring agent list --json") 14 local agents = vim.fn.json_decode(output) 15 16 pickers.new(opts, { 17 prompt_title = "Bootspring Agents", 18 finder = finders.new_table({ 19 results = agents, 20 entry_maker = function(entry) 21 return { 22 value = entry, 23 display = entry.name .. " - " .. entry.description, 24 ordinal = entry.name, 25 } 26 end, 27 }), 28 sorter = conf.generic_sorter(opts), 29 attach_mappings = function(prompt_bufnr) 30 actions.select_default:replace(function() 31 actions.close(prompt_bufnr) 32 local selection = action_state.get_selected_entry() 33 local prompt = vim.fn.input("Prompt: ") 34 if prompt ~= "" then 35 require("bootspring").invoke_agent(selection.value.name .. " " .. prompt) 36 end 37 end) 38 return true 39 end, 40 }):find() 41end 42 43-- Skill picker 44M.skills = function(opts) 45 opts = opts or {} 46 47 local output = vim.fn.system("bootspring skill list --json") 48 local skills = vim.fn.json_decode(output) 49 50 pickers.new(opts, { 51 prompt_title = "Bootspring Skills", 52 finder = finders.new_table({ 53 results = skills, 54 entry_maker = function(entry) 55 return { 56 value = entry, 57 display = entry.name, 58 ordinal = entry.name, 59 } 60 end, 61 }), 62 sorter = conf.generic_sorter(opts), 63 attach_mappings = function(prompt_bufnr) 64 actions.select_default:replace(function() 65 actions.close(prompt_bufnr) 66 local selection = action_state.get_selected_entry() 67 require("bootspring").apply_skill(selection.value.name) 68 end) 69 return true 70 end, 71 }):find() 72end 73 74-- Workflow picker 75M.workflows = function(opts) 76 opts = opts or {} 77 78 local workflows = { 79 { name = "preseed", description = "Idea to documentation" }, 80 { name = "seed", description = "Project scaffolding" }, 81 { name = "feature-development", description = "Full feature lifecycle" }, 82 { name = "security-audit", description = "Security review" }, 83 { name = "mvp", description = "MVP generation" }, 84 } 85 86 pickers.new(opts, { 87 prompt_title = "Bootspring Workflows", 88 finder = finders.new_table({ 89 results = workflows, 90 entry_maker = function(entry) 91 return { 92 value = entry, 93 display = entry.name .. " - " .. entry.description, 94 ordinal = entry.name, 95 } 96 end, 97 }), 98 sorter = conf.generic_sorter(opts), 99 attach_mappings = function(prompt_bufnr) 100 actions.select_default:replace(function() 101 actions.close(prompt_bufnr) 102 local selection = action_state.get_selected_entry() 103 require("bootspring").start_workflow(selection.value.name) 104 end) 105 return true 106 end, 107 }):find() 108end 109 110return require("telescope").register_extension({ 111 exports = { 112 agents = M.agents, 113 skills = M.skills, 114 workflows = M.workflows, 115 }, 116})

Telescope Keymaps#

vim.keymap.set("n", "<leader>fa", ":Telescope bootspring agents<CR>", { desc = "Find agents" }) vim.keymap.set("n", "<leader>fk", ":Telescope bootspring skills<CR>", { desc = "Find skills" }) vim.keymap.set("n", "<leader>fw", ":Telescope bootspring workflows<CR>", { desc = "Find workflows" })

Lualine Integration#

Status Line#

1-- ~/.config/nvim/lua/plugins/lualine.lua 2require("lualine").setup({ 3 sections = { 4 lualine_x = { 5 { 6 function() 7 local status = vim.fn.system("bootspring status --json 2>/dev/null") 8 if vim.v.shell_error == 0 then 9 local data = vim.fn.json_decode(status) 10 if data and data.initialized then 11 return "󰊤 " .. (data.project or "bootspring") 12 end 13 end 14 return "" 15 end, 16 cond = function() 17 return vim.fn.filereadable("bootspring.config.js") == 1 18 end, 19 }, 20 }, 21 }, 22})

Which-Key Integration#

1-- ~/.config/nvim/lua/plugins/which-key.lua 2require("which-key").register({ 3 ["<leader>b"] = { 4 name = "+bootspring", 5 g = { ":BootspringGenerate<CR>", "Generate context" }, 6 s = { ":BootspringStatus<CR>", "Show status" }, 7 a = { ":BootspringAgent ", "Invoke agent" }, 8 q = { ":BootspringQuality<CR>", "Quality check" }, 9 l = { ":BootspringAgents<CR>", "List agents" }, 10 w = { ":BootspringWorkflow ", "Start workflow" }, 11 }, 12})

Terminal Integration#

Toggleterm#

1-- ~/.config/nvim/lua/plugins/toggleterm.lua 2require("toggleterm").setup({ 3 size = 20, 4 open_mapping = [[<c-\>]], 5 direction = "horizontal", 6}) 7 8-- Bootspring terminal 9local Terminal = require("toggleterm.terminal").Terminal 10 11local bootspring = Terminal:new({ 12 cmd = "bootspring status && exec $SHELL", 13 direction = "float", 14 float_opts = { 15 border = "curved", 16 }, 17}) 18 19vim.keymap.set("n", "<leader>bt", function() 20 bootspring:toggle() 21end, { desc = "Bootspring terminal" })

Auto Commands#

Auto-Generate on Save#

1vim.api.nvim_create_autocmd("BufWritePost", { 2 pattern = { "*.ts", "*.tsx", "*.js", "*.jsx" }, 3 callback = function() 4 if vim.fn.filereadable("bootspring.config.js") == 1 then 5 -- Only if auto_generate is enabled 6 if require("bootspring").config.auto_generate then 7 require("bootspring").generate() 8 end 9 end 10 end, 11})

Project Detection#

1vim.api.nvim_create_autocmd("VimEnter", { 2 callback = function() 3 if vim.fn.filereadable("bootspring.config.js") == 1 then 4 vim.notify("Bootspring project detected", vim.log.levels.INFO) 5 end 6 end, 7})

LSP Integration#

Custom Source for nvim-cmp#

1-- Add Bootspring suggestions to completion 2local source = {} 3 4source.new = function() 5 return setmetatable({}, { __index = source }) 6end 7 8source.get_trigger_characters = function() 9 return { "@" } 10end 11 12source.complete = function(self, request, callback) 13 local items = {} 14 15 -- Add agent completions 16 local agents = { "frontend-expert", "backend-expert", "database-expert", "security-expert" } 17 for _, agent in ipairs(agents) do 18 table.insert(items, { 19 label = "@bootspring-agent: " .. agent, 20 kind = vim.lsp.protocol.CompletionItemKind.Reference, 21 }) 22 end 23 24 -- Add skill completions 25 local skills = { "patterns/api-endpoint", "patterns/react-component", "patterns/prisma-crud" } 26 for _, skill in ipairs(skills) do 27 table.insert(items, { 28 label = "@bootspring-skill: " .. skill, 29 kind = vim.lsp.protocol.CompletionItemKind.Snippet, 30 }) 31 end 32 33 callback({ items = items }) 34end 35 36require("cmp").register_source("bootspring", source.new())

Treesitter#

Highlight CLAUDE.md#

1-- Add markdown highlighting for CLAUDE.md 2vim.api.nvim_create_autocmd({ "BufRead", "BufNewFile" }, { 3 pattern = "CLAUDE.md", 4 callback = function() 5 vim.bo.filetype = "markdown" 6 end, 7})

Troubleshooting#

Commands Not Working#

1# Verify Bootspring is installed 2bootspring --version 3 4# Check PATH 5echo $PATH | tr ':' '\n' | grep -E "(npm|node)" 6 7# Test command directly 8bootspring status

Lua Module Not Found#

-- Check module path print(vim.inspect(package.path)) -- Ensure file exists :!ls ~/.config/nvim/lua/bootspring.lua

Terminal Issues#

1-- Use jobstart for async commands 2vim.fn.jobstart("bootspring generate", { 3 on_stdout = function(_, data) 4 vim.notify(table.concat(data, "\n")) 5 end, 6 on_exit = function(_, code) 7 if code == 0 then 8 vim.notify("Done!") 9 end 10 end, 11})

Performance#

1-- Cache agent list 2local cached_agents = nil 3local function get_agents() 4 if not cached_agents then 5 local output = vim.fn.system("bootspring agent list --json") 6 cached_agents = vim.fn.json_decode(output) 7 end 8 return cached_agents 9end

Complete Configuration#

Full init.lua Example#

1-- ~/.config/nvim/init.lua 2 3-- Bootstrap lazy.nvim 4local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" 5if not vim.loop.fs_stat(lazypath) then 6 vim.fn.system({ 7 "git", "clone", "--filter=blob:none", 8 "https://github.com/folke/lazy.nvim.git", 9 "--branch=stable", lazypath, 10 }) 11end 12vim.opt.rtp:prepend(lazypath) 13 14-- Leader key 15vim.g.mapleader = " " 16 17-- Plugins 18require("lazy").setup({ 19 -- Telescope 20 { 21 "nvim-telescope/telescope.nvim", 22 dependencies = { "nvim-lua/plenary.nvim" }, 23 }, 24 -- Lualine 25 { "nvim-lualine/lualine.nvim" }, 26 -- Which-key 27 { "folke/which-key.nvim" }, 28 -- Toggleterm 29 { "akinsho/toggleterm.nvim" }, 30}) 31 32-- Load Bootspring 33require("bootspring").setup({ 34 default_agent = "frontend-expert", 35 auto_generate = false, 36}) 37 38-- Basic options 39vim.opt.number = true 40vim.opt.relativenumber = true 41vim.opt.expandtab = true 42vim.opt.shiftwidth = 2

Next Steps#