{"slug": "effective-neovim-setup-for-agentic-coding-towards-2027", "title": "Effective Neovim setup for agentic coding towards 2027", "summary": "Developer Takuya published a new Neovim configuration built from scratch with an AI agent, moving off LazyVim after finding the distribution grew unstable with each update. The setup requires Neovim 0.12 or newer to use built-ins including vim.pack, vim.lsp.enable and the ui2 message UI, and Takuya writes the config as an English-language spec stored in Inkdrop and feeds it to the agent step by step via Inkdrop's MCP server, reloading with a ZR keymap mapped to :restart and reviewing each diff before committing. Takuya says he now mainly uses Neovim to review code rather than write it by hand.", "body_md": "[Tips](https://www.devas.life/tag/tips/)\n\n# Effective Neovim setup for agentic coding towards 2027\n\nHey, what's up? It's [Takuya](https://x.com/inkdrop_app?ref=devas.life) here. In this article, I'm going to share my new Neovim setup, which I built from scratch with an AI agent.\n\nWatch the video tutorial on YouTube:\n\nMy Dotfiles is here:\n\n## Moved off LazyVim\n\nIn [the previous setup I shared in 2023](https://www.devas.life/effective-neovim-setup-for-web-development-towards-2024/), I used [LazyVim](https://www.lazyvim.org/?ref=devas.life) to avoid maintaining plugins, and it's been working great.\n\nThanks to the LazyVim community, I could easily keep my plugins up to date and tweak the settings.\n\nBut the more I customized it, the more unstable it got.\n\nFixing errors after every LazyVim update was kind of annoying.\n\nMeanwhile, recent Neovim releases have added a lot of built-in features that used to need plugins:\n\n- `vim.pack` : a built-in plugin manager\n- `vim.lsp.enable` and`after/lsp/<name>.lua` : LSP setup with almost no boilerplate\n- ui2: a new message UI\n- `:restart` : reloads Neovim and restores the session\n\nSo I decided to build a fresh setup on top of them.\n\n## Neovim for agentic coding\n\nThe agentic coding paradigm shift has arrived, and [I've adapted to an agentic workflow](https://www.devas.life/hackers-and-photographers/).\n\nThese days, I mainly use Neovim to **review code**, rather than to write it by hand.\n\nTo be honest, I don't know how long I'll keep using it, since workflows are changing so fast.\n\nBut I thought it would be interesting to share my current setup.\n\n## Writing the config in plain English\n\nTweaking a Neovim config is super easy now, because you just tell your agent what you want.\n\nSo instead of writing Lua, I wrote a **spec** of my config in English on [Inkdrop](https://www.inkdrop.app/?ref=blog), and fed it to my agent step by step via [the MCP server](https://docs.inkdrop.app/reference/mcp-server?ref=devas.life).\n\nThe spec describes *what* I want and *why*, not *how*.\n\nThe agent figures out the Lua.\n\n### The workflow\n\n1. Write a step of the spec.\n2. Ask the agent to implement only that step.\n3. Reload Neovim with `:restart` and check the behavior myself.\n4. Review the diff and commit.\n\n### Prompt for the agent\n\nI gave the agent these rules:\n\n- Read the spec and implement only the step I name. Add nothing beyond it.\n- Check your work lightly:\n  - Neovim starts without errors: `nvim --headless +qa`\n  - New keymaps exist: `:verbose map <key>`\n- Neovim starts without errors: \n- Don't build test projects or drive the UI. I check the behavior myself after the restart.\n\n### Reloading the config\n\nI mapped `ZR` to `:restart`.\n\n- Neovim restarts in the same terminal and restores the windows, tabs, and buffers.\n- Save first with `:wa` . Unsaved buffers block the restart.\n  - Or use `:restart +qall!` to discard them.\n- Or use \n- After a step that adds a plugin, `vim.pack` shows an install prompt. Confirm it.\n- Run the agent in a separate terminal split, not in a `:terminal` inside Neovim, since the restart kills it.\n\nBelow is the whole spec, step by step.\n\nFeel free to copy it and feed it to your own agent, and tweak it to your taste.\n\n## 0. Prerequisites\n\n### 0.1 Neovim\n\n- [Neovim](https://neovim.io/doc/install/?ref=devas.life)**0.12** or newer.\n  - The config relies on built-ins that landed in 0.12: `vim.pack` ,`vim.lsp.enable` , and the ui2 message UI.\n- The config relies on built-ins that landed in 0.12: \n\n### 0.2 CLI tools\n\n| Tool | Why | \n|---|---|\n| `git` | `vim.pack` clones plugins with it | \n| `tree-sitter` CLI + C compiler | *nvim-treesitter* 's main branch builds parsers locally | \n| `curl` and`tar` | Parser and *blink.cmp* binary downloads | \n| Node.js + npm | *Mason* installs most language servers through npm | \n| `ripgrep` and`fd` | Back the text search and the file finder | \n| `lazygit` and`git-delta` | The git UI and its diff renderer | \n\n### 0.3 Font\n\n- A Nerd Font. I use [PlemolJP](https://github.com/yuru7/PlemolJP?ref=devas.life) Console NF.\n  - Icons appear in the tabline, statusline, completion menu, and file explorer, so a plain font shows boxes.\n\n### 0.4 Git\n\n- The config folder is a git repository.\n- `.gitignore` lists`nvim-pack-lock.json` .\n\n## 1. Foundation\n\n### 1.0 Start a session\n\nI started by telling the agent where the spec lives:\n\n```\nI'd like to make a neovim setup. I'm going to write a spec in this note: <link to the spec>\nWhen you are ready, say so\n```\n\n### 1.1 Layout\n\n- `~/.config/nvim` : the config root folder\n  - `init.lua` : enables`vim.loader` for faster startup, then requires these files directly, in order:\n    1. `craftzdog.utils` , assigned to the global`Craftzdog`\n    2. `craftzdog.config.options` ,`.keymaps` ,`.autocmds` ,`.commands` ,`.workarounds`\n    3. `craftzdog.plugins`\n  - `lua/craftzdog/` : my config lives here\n    - `utils/` : shared helpers\n      - `init.lua` : returns a table of helper modules, empty for now.\n        - Later steps add modules like `utils/editor.lua` , exposed as`editor` .\n      - Later steps add modules like \n    - `config/` : plain Neovim settings, one file per name above\n    - `plugins/`\n      - `init.lua` : installs every plugin in one`vim.pack.add` call, then requires each group file\n      - Each plugin group gets its own file next to it (e.g. `ui.lua` ), which configures its plugins with`require(\"<plugin>\").setup({ ... })` .\n      - `keymaps.lua` : every keymap that uses a plugin, required last so all plugins are set up first. Group files hold no keymaps.\n- Lua files are indented with tabs, formatted by stylua with its defaults.\n\n### 1.2 Leader and basics\n\n- Leader and local leader are **Space** .\n- Mouse is **off** . Keyboard-only.\n- Clipboard is `unnamedplus` , so yank and paste go through the system clipboard.\n- Indent is **2 spaces** :\n  - `tabstop` ,`shiftwidth` , and`softtabstop` are all**2**\n  - `expandtab` and`smartindent` are**on**\n- `-` counts as part of a word, so`foo-bar` is one word.\n  - Fits CSS classes and kebab-case names.\n\n### 1.3 Look of the buffer\n\n- **Hybrid** line numbers:`number` +`relativenumber`**on** , so the cursor line shows its real number.\n- `cursorline`**on** . No wrap,` scrolloff`**10** ,` sidescrolloff`**8** .\n- `signcolumn`**always on** .\n  - Text doesn't jump when git or diagnostic marks appear.\n- `cmdheight`**0** and one global statusline (` laststatus`**3** ).\n  - Maximizes vertical space.\n- **Rounded** borders on every float (`winborder` ).\n- Popup menu: at most **10** rows, slightly see-through (`pumheight`**10** ,` pumblend`**10** ).\n- Matching brackets flash briefly (`showmatch`**on** ,` matchtime`**2** ).\n- `title`**on** , so the terminal tab shows the file name.\n- Diagonal `╱` fill in empty diff areas.\n\n### 1.4 Search, files, undo\n\n- `ignorecase` +`smartcase`**on** : case-insensitive until a capital letter is typed.\n- `path` adds`**` , so`:find` searches subfolders.\n- `:` completion:\n  - `wildmode` is`longest:full,full`\n  - `wildignore` skips`*/node_modules/*` ,`*.o` ,`*.obj` ,`*.pyc` ,`*.class` ,`*.jar`\n- `swapfile` and`writebackup`**off** .\n- Persistent undo (`undofile`**on** ) lives in`~/.cache/nvim/undodir` .\n  - Undo survives closing the file. Swap files only get in the way.\n- Snappier timing: `updatetime`**300** ,` timeoutlen`**500** ,` ttimeoutlen`**0** .\n  - Faster CursorHold events, and key sequences resolve without lag.\n\nTry it:\n\n- `/craftzdog` in`init.lua` , then`/Craftzdog`\n- `:find opt<Tab>`\n- Edit `init.lua` ,`:wq` , reopen it, then`u`\n\n### 1.5 Splits and folds\n\n- New splits open **below** and to the**right** .\n- Folds come from **Treesitter** , with`foldlevel`**99** .\n  - Everything starts unfolded, and folds can still be closed by syntax.\n\nTry it:\n\n- `:split` ,`:vsplit`\n- `:e $VIMRUNTIME/lua/vim/keymap.lua` , then`zc` /`zo` inside a function\n- `zM` /`zR`\n\n### 1.6 Messages\n\nNeovim 0.12's experimental **ui2** handles messages. It's turned on at the end of `config/options.lua`.\n\n- Short messages: corner popup up to **30%** of the screen tall, gone after**5 seconds** .\n- Long output (errors, `:ls` ,`:verbose` , shell commands, progress): a scrollable pager up to**half** the screen.\n- Search count, search pattern, completion, `:` completion list, and confirm prompts stay in the command line.\n- Output of a command I type goes to the command line too, whatever its kind.\n  - It expands over the bottom of the screen until the next key.\n  - `Enter` moves it into the pager.\n\n[tiny-cmdline.nvim](https://github.com/rachartier/tiny-cmdline.nvim?ref=devas.life) shows the `:` command line as a floating box, centered left to right, **20%** from the top. It's set up in `plugins/ui.lua`.\n\n- With `cmdheight` 0, the command line needs somewhere to appear, and near the top is where the eyes already are.\n\nTry it:\n\n- `:echo \"hi\"`\n- `:lua print(\"hi\")`\n- `:foo`\n- `:!ls`\n- `:verbose set ts?`\n\n### 1.7 Autocmds\n\n- Yanked text flashes briefly.\n- Only the active window shows the cursorline.\n\n### 1.8 Core keymaps\n\n| Keys | Action | Notes | \n|---|---|---|\n| `x` | Deletes without copying |  | \n| `<leader>d` ,`<leader>c` ,`<leader>p` | Delete, change, and paste without touching the yank register | The yanked text stays safe while editing around it. | \n| `dw` | Deletes the word backwards without copying |  | \n| `+` /`-` | Increment and decrement numbers |  | \n| `<C-a>` | Selects all |  | \n| `te` | Opens a new tab |  | \n| `Tab` /`Shift-Tab` | Cycle tabs |  | \n| `ss` /`sv` | Split | Short, home-row window control. | \n| `sh`` sj``sk`` sl` | Move between windows | Short, home-row window control. | \n| `<C-m>` | Jumps forward in the jump list | `<C-i>` is the same key as Tab in the terminal, and Tab is taken by tab switching. | \n| `<leader>o` /`<leader>O` | Open a line below or above without continuing a comment ( `o<Esc>^Da` ) |  | \n\n### 1.9 Close hidden buffers\n\n- `<leader>bd` closes every hidden buffer, except unsaved ones.\n\n## 2. Look & feel\n\n### 2.1 Colorscheme\n\n- [solarized-osaka](https://github.com/craftzdog/solarized-osaka.nvim?ref=devas.life) ,`vivid` style,**transparent** background.\n  - The terminal's blur shows through, and the palette matches the Ghostty theme.\n\n### 2.2 Icons\n\n- [mini.icons](https://github.com/nvim-mini/mini.icons?ref=devas.life) , also mocking[nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons?ref=devas.life) .\n  - One icon source for every plugin.\n\n### 2.3 Tabline\n\nA custom tabline in `utils/tabline.lua`, with no plugin.\n\n- Shown only when there are **2** or more tabs.\n- Each tab shows the active window's file name with its icon, padded with **3** spaces, between slanted separators.\n  - Both edges slant outward going down, so each tab is a trapezoid, wider at the bottom:\n\n- Colors from the *solarized-osaka* palette:\n  - Active tab: bold **base4** text on**yellow**\n  - Inactive tab: **base0** on**base02**\n  - The icon takes the tab's text color.\n  - The separators take the tab's color on a transparent background, and so does the empty area after the last tab.\n- Active tab: bold \n- Names longer than **20** characters are cut to**17** plus`…` .\n- Unsaved tabs show `[+]` before the icon.\n- Terminals show `[Terminal]` and empty buffers`[No Name]` , with no icon.\n\n### 2.4 Statusline\n\n[lualine](https://github.com/nvim-lualine/lualine.nvim?ref=devas.life), one global bar, theme `auto`.\n\n| Section | Content | \n|---|---|\n| a | Mode | \n| b | Git branch | \n| c | Project root name (only when it differs from cwd), filetype icon, pretty path | \n| x | Macro recording register, diagnostics, git diff counts | \n| y | Progress | \n| z | line:column | \n\n- The project root is found by searching upward for `.git` ,`lua` ,`package.json` ,`Makefile` ,`Cargo.toml` ,`go.mod` , or`pyproject.toml` .\n- Refreshes on cursor move and macro start/stop.\n  - The recording indicator replaces the hidden command line.\n- The result would look like:\n\nResult:\n\n### 2.5 Window labels\n\n- [incline.nvim](https://github.com/b0o/incline.nvim?ref=devas.life) shows a filename tag with an icon in the top-right corner of each window, plus`[+]` when unsaved.\n  - With a single global statusline, each split still needs to say which file it holds.\n- The tag hides when the cursor reaches its line.\n\n### 2.6 Snacks\n\n[snacks.nvim](https://github.com/folke/snacks.nvim?ref=devas.life) provides the notifier, indent guides, statuscolumn, and word highlighting.\n\nLater steps turn on more of it, like the picker and the lazygit integration.\n\n- **Words** : the word under the cursor is highlighted everywhere.`]]` /`[[` jump between occurrences.\n  - It needs a language server, so it works after step 5.1.\n- **Smooth scroll** is**off** .\n  - Scrolling should feel instant.\n\n## 3. Navigating\n\n### 3.1 Picker\n\nThe *snacks.nvim* picker.\n\n| Keys | Action | Notes | \n|---|---|---|\n| `;f` | Finds files, including hidden ones | Dotfiles like `.github/` and`.env.example` are part of real projects. | \n| `;r` | Live-greps, including hidden files |  | \n| `;;` | Reopens the last picker |  | \n| `\\\\` | Lists open buffers | Jumps to a window that already shows the buffer. | \n| `;e` | Lists diagnostics |  | \n| `;n` | Shows notification history |  | \n| `;h` | Lists git hunks |  | \n\n### 3.2 File explorer\n\n[oil.nvim](https://github.com/stevearc/oil.nvim?ref=devas.life) replaces netrw and shows hidden files.\n\n- The directory is a buffer, so renaming, moving, and deleting files is plain text editing followed by `:w` .\n- Columns: icon, permissions, size, modified time.\n- Renaming a file asks the LSP to update imports and saves those edits automatically.\n- In the tabline (2.3), an oil tab shows its directory (`~/foo` ) with no icon.\n  - Paths longer than **20** characters are cut from the left to`…` plus the last**17** .\n- Paths longer than \n\n| Keys | Action | Notes | \n|---|---|---|\n| `sf` | Opens oil as a centered float with a live preview | At most **200** columns wide, with rounded corners. | \n| `h` | Goes to the parent directory |  | \n| `q` | Closes oil |  | \n\n## 4. Syntax\n\n### 4.1 Treesitter\n\n[nvim-treesitter](https://github.com/nvim-treesitter/nvim-treesitter?ref=devas.life), main branch.\n\n- Ensures 38 parsers:\n  - astro, bash, c, cmake, cpp, css, diff, fish, gitignore, go, graphql, html, http, java, javascript, jsdoc, json, lua, luadoc, luap, markdown, markdown_inline, php, printf, python, query, regex, rust, scss, sql, svelte, toml, tsx, typescript, vim, vimdoc, xml, yaml\n- A FileType autocmd starts highlighting and Treesitter indent whenever a parser exists.\n- `:TSUpdate` runs on the`PackChanged` event.\n  - Parsers stay in sync with the plugin version.\n\n### 4.2 Small highlights\n\n- [todo-comments.nvim](https://github.com/folke/todo-comments.nvim?ref=devas.life) highlights`TODO` ,`FIXME` , and the like, with defaults.\n- [nvim-highlight-colors](https://github.com/brenoprata10/nvim-highlight-colors?ref=devas.life) paints hex, rgb, hsl, ANSI, and CSS variable colors as backgrounds. Tailwind is off.\n  - Neovim's LSP document colors are turned off, so colors aren't painted twice.\n\n## 5. Code smarts\n\n### 5.1 Language servers\n\n[Mason](https://github.com/mason-org/mason.nvim?ref=devas.life) + [mason-tool-installer](https://github.com/WhoIsSethDaniel/mason-tool-installer.nvim?ref=devas.life) install on start, and never auto-update:\n\n- Servers: lua-language-server, vtsls, eslint-lsp, oxlint, tailwindcss-language-server, css-lsp, rust-analyzer, copilot-language-server\n- Formatters: prettier, prettierd, oxfmt, stylua, shfmt\n\n[nvim-lspconfig](https://github.com/neovim/nvim-lspconfig?ref=devas.life) supplies defaults.\n\n- Servers are turned on with `vim.lsp.enable` : eslint, oxlint, lua_ls, cssls, vtsls, tailwindcss, rust_analyzer.\n- Every server gets file-rename support (`didRename` /`willRename` ).\n\n### 5.2 Diagnostics look\n\n- Underlined, not updated while typing, sorted by severity.\n- Inline text: `● message` , with the source only when there are several.\n- Gutter icons come from the shared icon set.\n\nFor example, typing `const x: number = 'a'` in a TSX file:\n\n- The error is underlined, with `● Type 'string' is not assignable…` inline and an icon in the gutter.\n- The line also has a \"never read\" hint, but the gutter shows the error icon, since they are sorted by severity.\n- oxlint flags the unused `x` too, so each message shows its source (`ts` ,`oxc` ).\n\n### 5.3 Per-server settings\n\nPer-server settings live in `after/lsp/<name>.lua`.\n\nNeovim 0.12 merges these automatically, so there's no setup boilerplate.\n\n- **vtsls** :\n  - Uses the workspace TypeScript and updates imports on file move.\n  - Server-side fuzzy matching and function-call completion.\n  - Inlay hints are short: no variable types, **30** characters max.\n- **lua_ls** : knows the Neovim runtime, shows param-type hints, silences a few noisy checks.\n- **cssls** : ignores empty rules.\n- **oxlint** : starts with`oxlint --lsp` .\n\n### 5.4 Completion\n\n[blink.cmp](https://github.com/saghen/blink.cmp?ref=devas.life), version `^1`, `enter` preset: Enter accepts.\n\n- Every language server from 5.1 also gets *blink.cmp* 's completion capabilities.\n- Auto-brackets after functions. Docs pop up after **200 ms** .\n- Menu items are colorized by Treesitter, with kind icons from the shared icon set.\n- Ghost text is **off** .\n  - Copilot already shows inline suggestions, and two ghost texts would clash.\n- In the command line, the menu opens by itself for `:` commands only, with nothing preselected.\n\n### 5.5 Pairs\n\n- [mini.pairs](https://github.com/nvim-mini/mini.pairs?ref=devas.life) with defaults, in insert and command mode.\n\n### 5.6 Formatting\n\n[conform.nvim](https://github.com/stevearc/conform.nvim?ref=devas.life) formats on save with a **1000 ms** timeout, falling back to the LSP.\n\n| Filetypes | Formatter | \n|---|---|\n| js, ts, jsx, tsx, json, css, scss, less, html, markdown, mdx, yaml | oxfmt, then prettierd, then prettier (first available) | \n| lua | stylua | \n| sh | shfmt | \n| fish | fish_indent | \n\n- oxfmt runs only when the project has an oxfmt config, like `.oxfmtrc.json` or a Vite+`vite.config.ts` .\n  - Projects using prettier keep their own formatter.\n- `:ToggleFormatter` turns format-on-save off or back on for the current buffer, with a notification.\n  - The command lives in `config/commands.lua` .\n- The command lives in \n\n### 5.7 LSP keymaps\n\n| Keys | Action | Notes | \n|---|---|---|\n| `gd` | Goes to the definition | Through the picker, like `gD` ,`gy` , and`gr` . | \n| `gD` | Goes to the declaration |  | \n| `gy` | Goes to the type definition |  | \n| `gr` | Lists references |  | \n| `gI` | Goes to the source definition in TypeScript, the implementation in other languages | Skips the `.d.ts` to reach the real code. | \n| `;c` | Lists incoming calls |  | \n| `K` | Shows hover docs |  | \n| `gK` /`<C-k>` (insert) | Show signature help |  | \n| `<C-j>` | Jumps to the next diagnostic with a float |  | \n| `<leader>ca` | Shows code actions |  | \n| `<leader>cr` | Renames the symbol |  | \n| `<leader>cR` | Renames the file with import updates |  | \n| `<leader>f` | Formats now |  | \n| `<leader>cl` | Shows LSP info |  | \n\n## 6. Git\n\nSince I mostly review code written by my agent now, this is the part of the setup I use the most.\n\n### 6.1 Signs and blame\n\n[gitsigns.nvim](https://github.com/lewis6991/gitsigns.nvim?ref=devas.life) with defaults.\n\n| Keys | Action | Notes | \n|---|---|---|\n| `<leader>gb` | Blames the line |  | \n| `<leader>gB` | Blames the buffer |  | \n| `<leader>go` | Opens the file as of the commit that last touched the line, in a new tab | Shows the context of an old change without leaving the editor. | \n| `<leader>gs` | Stages the buffer, or unstages it if nothing is left to stage |  | \n| `<leader>gh` | Stages or unstages the hunk |  | \n\n### 6.2 Diff overlay\n\n[mini.diff](https://github.com/nvim-mini/mini.diff?ref=devas.life) from my fork ([`craftzdog/mini.diff`](https://github.com/craftzdog/mini.diff/tree/feat/grouping?ref=devas.life), branch `feat/grouping`).\n\n- The fork groups changes into whole hunks, the way `git diff` shows them.\n\n| Keys | Action | \n|---|---|\n| `<leader>gd` | Toggles the overlay | \n| `]c` /`[c` | Jump between hunks | \n\n### 6.3 Diff view\n\n[codediff.nvim](https://github.com/esmuellert/codediff.nvim?ref=devas.life) for side-by-side diffs and history.\n\nI use it when my agent makes a lot of changes in the codebase.\n\n- Explorer: **tree** view,**50** columns wide, opens files as the cursor moves, shows +/- line stats.\n- Compact mode: only changes plus **8** context lines, with folds synced across panes.\n\n| Keys | Action | \n|---|---|\n| `<leader>dv` | Toggles the diff view | \n| `<leader>dh` | Shows the current file's history | \n| `<leader>dH` | Shows the repo history | \n\n### 6.4 Lazygit\n\n`;g` opens [lazygit](https://github.com/jesseduffield/lazygit?ref=devas.life) in a float through *snacks.nvim*, with the theme synced and the active border in the WarningMsg color.\n\nPressing `e` on a file closes lazygit and opens the file in the window it was launched from, through `$NVIM` and `nvim --server --remote`.\n\n- `;g` remembers the current window.\n- `e` quits lazygit, focuses that window with`--remote-send` , then opens the file, so the cursor ends up in the file.\n- Not a new tab and not a nested Neovim. Outside Neovim, it just runs `nvim <file>` .\n- The edit command is written in fish syntax.\n\nLazygit's own config lives in `~/.config/lazygit/config.yml`, outside the Neovim config. *snacks.nvim* loads it together with the synced theme. It holds:\n\n- Diffs render with `delta --dark --paging=never --syntax-theme=\"Solarized (dark)\"` .\n- Mouse events are off and auto-fetch is off.\n- `C` in the files panel commits with commitizen (`git cz` ).\n\n### 6.5 Links\n\n- [gitlinker.nvim](https://github.com/linrongbin16/gitlinker.nvim?ref=devas.life) :`:GitLink` copies a GitHub URL for the current line, or the selected range.\n\n## 7. AI\n\n### 7.1 Copilot\n\n[copilot.lua](https://github.com/zbirenbaum/copilot.lua?ref=devas.life) with auto-trigger on, enabled in Markdown and help too.\n\n- Notes and docs benefit from suggestions as much as code does.\n- Requires `:Copilot auth` once.\n- On macOS, the terminal needs Option as Alt.\n\nThe keys work in insert mode:\n\n| Keys | Action | \n|---|---|\n| `<C-l>` | Accepts the suggestion | \n| `Alt-l` | Accepts a word | \n| `Alt-Shift-l` | Accepts a line | \n| `Alt-]` /`Alt-[` | Cycle suggestions | \n| `<C-]>` | Dismisses the suggestion | \n\n📷 Frame: A Copilot suggestion as ghost text\n\n## 8. Agentic coding\n\nThese are small helpers for passing context from Neovim to an agent.\n\n### 8.1 Copy paths for agents\n\n| Keys | Action | Notes | \n|---|---|---|\n| `<leader>yf` | Copies the current file's path relative to cwd with `#L<line>` | e.g. `lua/craftzdog/config/options.lua#L12` | \n| `<leader>yp` | Copies the absolute path the same way |  | \n\n- Both show the copied text in a notification.\n  - Pasting the path into an agent's prompt points it at the exact line.\n\n### 8.2 Helper keymaps\n\n| Keys | Action | Notes | \n|---|---|---|\n| `<leader>cc` (visual) | Copies the selection as a Markdown code block with `filename=\"…\"` and`line=…` attributes | The same format Inkdrop uses for code-block attributes. Short language names ( `tsx` ,`jsx` ,`ts` ,`js` ). | \n| `<leader>j` | Opens the project's `package.json` in a centered**80%** float.`q` or`Esc` closes it. |  | \n\n## Example workflow: Building a tiny app with the new setup\n\nTo try the setup in a real agentic workflow, I built a keymap cheat sheet website with [Vite+](https://viteplus.dev/?ref=devas.life) and my agent.\n\nTo show how I use this setup day to day, I built a tiny app with it: a one-page cheat sheet of every keymap in this config.\n\nI followed Inkdrop's [note-driven agentic coding](https://docs.inkdrop.app/start-guide/note-driven-agentic-coding?ref=devas.life) workflow.\n\nEach task gets one note, which works as a shared place for me and the agent.\n\nI write the requirements, and the agent fills in the rest of the plan.\n\n### 1. Scaffold the app\n\nI created a [Waku](https://waku.gg/?ref=devas.life) app in `~/Developments/devaslife/keymap-cheatsheet`:\n\n```\nnpm create waku@latest\n```\n\n### 2. Write the requirements in a plan note\n\nI created a new note and applied the built-in **Implementation plan** [note template](https://docs.inkdrop.app/reference/note-templates?ref=devas.life) with `Cmd+T`.\n\n- The template starts with **Requirements** and**Related notes** sections for me to write.\n- The rest is a skeleton for the agent: requirements restatement, current state, decisions, phases, risks, status, and outcome.\n- Instructions for the agent live in `> # !Instructions` and`> # !Example` blocks.\n  - Inkdrop strips them from the created note, and the agent reads them from the source template.\n\nMy requirements were just two lines, plus a link to the spec note:\n\n```\n## Requirements\n\n- Build a one-page keymap cheatsheet for my neovim setup\n- It renders a simple table for each keymap\n\n## Related notes\n\n- [Set up Neovim](inkdrop://note/…)\n```\n\n### 3. Let the agent fill out the plan\n\nI copied the note link and passed it to Claude Code:\n\n```\nfill out [Create a keymap cheatsheet for Neovim setup](inkdrop://note/eOuwoieG)\n```\n\nClaude Code reads and updates the note through the Inkdrop MCP server, using the `fill-out-template` skill.\n\nBefore writing the plan, it read both the spec note and my actual Lua config.\n\n- It listed where every keymap is defined, with `file:line` references.\n- It found mismatches between the spec and the config.\n  - e.g. the spec had a typo, `:f` instead of`;f` , for finding files.\n- e.g. the spec had a typo, \n- It decided to trust the config over the spec.\n\nThen it asked me about the decisions only I could make:\n\n| Decision | Question | My pick | \n|---|---|---|\n| Data source | Where does the page get its keymaps? | A hand-curated, typed TS data file | \n| Coverage | Spec tables only, or every key the config maps? | Every mapped key | \n| Starter UI | Keep the starter header and footer? | Remove it, so there's one page at `/` | \n\nIt recorded my answers in **Decisions Needed** and broke the work into three phases:\n\n1. Keymap data\n2. Page and table component\n3. Remove starter leftovers\n\nReviewing a plan is much cheaper than reviewing code, so this is where I spend my attention.\n\n### 4. Implement it\n\nI told Claude Code to work on it, and it implemented all three phases in **1 minute 18 seconds**.\n\nIt checked off each phase in the note's **Status** section as it went.\n\nThe cheat sheet has 7 sections and 59 keys, with dark mode.\n\n### 5. Review the code in Neovim\n\nThis is where the Git part of my setup comes in:\n\n- `;g` : lazygit, to skim the whole diff\n- `<leader>dv` : codediff, to walk through each changed file side by side\n- `<leader>gd` : the mini.diff overlay, to see the changes inside a file\n\nAfter the review, I switched the project to pnpm and committed it.\n\n### 6. Record the outcome\n\nFinally, I pasted a screenshot of the working page into Claude Code.\n\nIt filled out the note's **Outcome** and **Follow-up** sections.\n\nNow the note records what was built and why, including the follow-up to fix the typo in my spec. The finished note: [Create a keymap cheatsheet for Neovim setup](https://community.inkdrop.app/d975606d93c067c5ef8d6adfb5db83b5/eOuwoieG?ref=devas.life)\n\n## Wrapping up\n\nWriting code is very cheap now, so writing the config as a spec in a natural language felt natural. It's English and Japanese for me.\n\nThe spec is readable, it keeps the *why* next to each setting, and I can rebuild or tweak the setup any time by just telling my agent what I want.\n\nThe full spec is above, so feel free to copy it and make it your own. I hope it's helpful for your Neovim setup. Thanks for reading/watching!", "url": "https://wpnews.pro/news/effective-neovim-setup-for-agentic-coding-towards-2027", "canonical_source": "https://www.devas.life/effective-neovim-setup-for-agentic-coding-towards-2027/", "published_at": "2026-11-04 12:25:06+00:00", "updated_at": "2026-11-04 12:49:48.777438+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "ai-tools"], "entities": ["Takuya", "Neovim", "LazyVim", "Inkdrop", "vim.pack", "MCP"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/effective-neovim-setup-for-agentic-coding-towards-2027", "markdown": "https://wpnews.pro/news/effective-neovim-setup-for-agentic-coding-towards-2027.md", "text": "https://wpnews.pro/news/effective-neovim-setup-for-agentic-coding-towards-2027.txt", "jsonld": "https://wpnews.pro/news/effective-neovim-setup-for-agentic-coding-towards-2027.jsonld"}}