A curated lazy.nvim config built for a Ruby on Rails, Stimulus, React (JS/JSX), ERB, Markdown, and AI-agent workflow — tuned for the Podia app. Inspired by Omarchy's LazyVim setup, but hand-assembled from individual plugins rather than a distro, so every choice is explicit and easy to change.
One config runs in two places: standalone Neovim and inside the VSCode-Neovim extension. Heavy UI plugins are gated on vim.g.vscode, so VS Code keeps its own UI while Neovim still provides motions, text objects, surround, flash, and comments.
🎮 Play Keycombat — an interactive, ADHD-friendly game that drills these keymaps into muscle memory (Rails-developer moves first): 11 worlds, 96 bindings, from Daily Drivers through Ruby Surgery and the Debugger. Runs right in the browser. Source in
docs/game/.
- Setup — installing the toolchain (Homebrew + mise) on a fresh machine
- Getting started — requirements, first launch, updating, backups
- Keymap reference — the full cheatsheet
- Rails workflow — ruby-lsp, formatting, navigation, RSpec
- JavaScript / React / Stimulus — vtsls, ESLint, Prettier, Jest
- AI workflow — Copilot, Copilot Chat, Avante, CLI agents
- Using in VS Code — the VSCode-Neovim extension
- Troubleshooting — common issues and fixes
- Plugin inventory — every plugin and where it's configured
- Keycombat game — play it live to learn the keymaps by doing
- Neovim 0.12+ (uses the native
vim.lsp.config/vim.lsp.enableAPI). - A Nerd Font (JetBrainsMono Nerd Font is assumed for icons).
git,rg(ripgrep),fd,make, a C compiler,lazygit,node, andruby.tree-sitter(the parser CLI) onPATH— nvim-treesitter'smainbranch compiles parsers locally. It's provided here via mise, so launch nvim from a mise-activated shell (the same requirement as ruby-lsp).- For Ruby:
ruby-lsponPATH(already provided here via mise). It runs the project's composed bundle, which auto-loadsruby-lsp-railsandruby-lsp-rspec. - For AI: the
claude,opencode, andcodexCLIs (already installed) plus a GitHub Copilot subscription. No model API keys are needed — everything is subscription-based.
On the first time you open a file, mason.nvim auto-installs the language servers and tools (vtsls, eslint-lsp, stimulus-language-server, lua-language-server, marksman, stylua, shfmt, markdownlint, …) with a progress indicator. ruby-lsp is not installed by Mason — it comes from the project's own bundle. Run :Lazy sync to (re)install plugins and :checkhealth to verify.
init.lua leader keys, globals, load order (vscode vs terminal split)
lua/config/
options.lua editor options (UI-only opts gated behind vim.g.vscode)
keymaps.lua core keymaps (standalone Neovim only)
autocmds.lua yank highlight, last cursor position, .erb -> eruby, mkdir on save
lazy.lua lazy.nvim bootstrap + setup (imports lua/plugins/)
vscode.lua delegates LSP/files/search to VS Code commands
lua/plugins/
colorscheme.lua onedarkpro (active) + tokyonight/catppuccin (available)
ui.lua snacks, lualine, bufferline, which-key, noice
editor.lua telescope, neo-tree, trouble, todo-comments, flash, matchup,
undotree, persistence
treesitter.lua syntax + indent + textobjects (rewritten `main`; Neovim 0.12+)
editing.lua mini.ai/surround/pairs, ts-comments, vim-repeat (both envs)
lsp.lua nvim-lspconfig + mason; ruby_lsp, herb_ls, vtsls, eslint, ...
completion.lua blink.cmp (+ Copilot source, Rails/RSpec snippets)
formatting.lua conform.nvim (prettier / stylua / shfmt / herb-format)
linting.lua nvim-lint (markdownlint)
git.lua gitsigns, diffview, lazygit (via snacks)
test.lua neotest + neotest-rspec (bin/rspec) + neotest-jest (yarn jest)
dap.lua nvim-dap + nvim-dap-ruby (rdbg), dap-ui, virtual text
ruby.lua vim-rails, projectionist, bundler, endwise, Rails pickers +
bin/rails commands
javascript.lua nvim-ts-autotag (JSX/HTML/ERB tags)
stimulus.lua (empty — Stimulus is covered by stimulus_ls + treesitter)
markdown.lua render-markdown, markdown-preview
obsidian.lua obsidian.nvim (digital-brain vault)
ai.lua copilot.lua, CopilotChat, avante, CLI-agent terminals
Leader is Space. Press Space and wait to see which-key hints for everything below.
| Key | Action |
|---|---|
<leader><space> / <leader>ff |
Find files |
<leader>fr |
Recent files |
<leader>fg |
Git files |
<leader>, |
Buffers |
<leader>/ |
Live grep |
<leader>sw |
Grep word under cursor / selection |
<leader>sh <leader>sk <leader>sd |
Help / keymaps / diagnostics |
<leader>sr <leader>sc <leader>sn <leader>st |
Resume / commands / nvim config / todos |
<leader>e / <leader>E |
File explorer toggle / reveal current file |
| Key | Action |
|---|---|
gd gr gI gy |
Definition / references / implementation / type definition |
K gK |
Hover / signature help |
<leader>cr <leader>ca |
Rename / code action |
<leader>cf <leader>cl |
Format buffer / run code lens |
<leader>cd ]d [d |
Line diagnostics / next / prev |
<leader>th |
Toggle inlay hints |
<leader>xx <leader>xX <leader>xs |
Trouble: diagnostics / buffer / symbols |
<leader>xl <leader>xL <leader>xQ <leader>xt |
Trouble: LSP / loclist / quickfix / todos |
| Key | Action |
|---|---|
<leader>gg <leader>gl |
Lazygit / lazygit log |
<leader>gd <leader>gf <leader>gF |
Diffview / file history / repo history |
<leader>gb |
Toggle line blame |
]c [c |
Next / prev hunk |
<leader>ghs <leader>ghr <leader>ghp <leader>ghb |
Stage / reset / preview hunk, blame line (<leader>gh = more) |
| Key | Action |
|---|---|
<leader>tr <leader>tf <leader>tl |
Run nearest / file / last |
<leader>ts <leader>to <leader>tO |
Toggle summary / show output / output panel |
<leader>tw <leader>tS <leader>td |
Toggle watch / stop / debug nearest |
RSpec runs via bin/rspec, Jest via yarn jest — the adapter is chosen by filetype.
Multiple, complementary layers (details in docs/rails-workflow.md):
- vim-rails:
<leader>raalternate,<leader>rrrelated;:A,:Emodel,:Eview,:Econtroller,:Emigration;gfon partials/associations;.projections.jsonhonored. - Resource pickers:
<leader>rmmodels,rccontrollers,rvviews,rsspecs,rimigrations,rllibs,rjjobs,rnmailers,rucomponents,rtStimulus controllers,rdschema. - Running Rails:
<leader>rRroutes picker (jumps to the action),rCconsole,rMdb:migrate,rGgenerate. - ruby-lsp:
gdgo-to-definition,grreferences,<leader>csworkspace symbols, and Code Lens "jump to view"/route links via<leader>cl. - Ruby motions:
%jumpsdef↔end,damdeletes a whole method,]m/[mstep between methods.
herb_ls parses the HTML and the ERB together, so unclosed tags and a missing <% end %> surface as ordinary diagnostics — things ruby-lsp can't see. herb-format formats views on save once installed.
Breakpoint debugging for Ruby via nvim-dap + rdbg: <leader>db breakpoint, <leader>dc start/continue, <leader>di/do/dO step, <leader>du toggle UI. <leader>td debugs the nearest spec. Variable values render inline as you step.
Subscription-based; no API keys.
| Key | Action |
|---|---|
<M-l> / <M-]> / <M-[> |
Copilot inline: accept / next / prev (insert mode) |
<leader>at |
Toggle Copilot auto-suggestions |
<leader>aa <leader>ax <leader>ap |
Copilot Chat: toggle / reset / prompt actions |
<leader>ae <leader>af <leader>av <leader>aT |
Chat: explain / fix / review / tests (works on a visual selection) |
<leader>Aa <leader>At <leader>Ae |
Avante: ask / toggle / edit (Copilot provider by default) |
<leader>ac <leader>ao <leader>aC |
Toggle a terminal running Claude Code / opencode / Codex |
Run :Copilot auth once to sign in. Avante defaults to the Copilot provider; to drive it through the Claude subscription instead, uncomment the ACP/claude-code block in lua/plugins/ai.lua (still no API key).
s/S flash jump, sa/sd/sr surround add/delete/replace, gc/gcc comment, <C-s> save, <C-h/j/k/l> window navigation, <A-j>/<A-k> move lines, <leader>uw/us/ul/ud/uv/un UI toggles, <leader>uu undo tree, <leader>l Lazy, <leader>qq quit all.
Sessions: <leader>qs reopens this project exactly as you left it (buffers + window layout), <leader>ql restores the last session anywhere.
Open the repo with the VSCode-Neovim extension and this config loads in "vscode" mode: UI plugins are skipped and lua/config/vscode.lua maps the same leader keys to VS Code commands (<leader>ff quick open, <leader>/ search, gd/K/<leader>ca/<leader>cr code intelligence, za/zR/zM folds). Motions, surround, flash, and comments come from Neovim.
The previous kickstart-modular config is preserved on the backup/kickstart-modular-20260723 git branch and copied to ~/.config/nvim.bak-20260723. To roll back: git checkout backup/kickstart-modular-20260723.