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 neovimLinux#
1# Ubuntu/Debian
2sudo apt install neovim
3
4# Fedora
5sudo dnf install neovim
6
7# Arch
8sudo pacman -S neovimWindows#
winget install Neovim.NeovimBasic Configuration#
Initialize Bootspring#
cd your-project
bootspring init
bootspring generateNeovim 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 MLoad 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 statusLua Module Not Found#
-- Check module path
print(vim.inspect(package.path))
-- Ensure file exists
:!ls ~/.config/nvim/lua/bootspring.luaTerminal 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
9endComplete 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 = 2Next Steps#
- Generate Context
- Using Agents
- Claude Desktop Setup
- VS Code Setup (alternative)