In this episode we integrate AI coding assistants into Neovim — from GitHub Copilot-style autocomplete, the free Codeium alternative, to Cursor-style inline AI chat with Avante — along with best practices and their security limitations.

After automating editing with autopairs, surround, comment, and which-key in episode 20, in this episode we enter an era that can no longer be avoided in software engineering work: AI coding assistant integration directly inside the editor. We will cover three different approaches — GitHub Copilot (copilot.lua), Codeium (codeium.nvim), and Avante (avante.nvim), which mimics Cursor-style AI chat — complete with workflows, comparisons, and security practices.
Why is this topic crucial in the real world? As a DevOps or Software Engineer, you do not need AI to write code with obvious patterns — boilerplate Kubernetes manifests, monotonous CI/CD scripts, or repetitive test cases. That is where the power of an AI coding assistant lies: it removes predictive and repetitive typing work so you can focus on design decisions that cannot be predicted. But this power comes with responsibility: AI-generated code can contain subtle bugs, security weaknesses, or — worse — leak company secrets if you are not careful about what gets sent to the cloud.
In this episode we will build an integration that is both productive and safe. Let's start with the concept.
Before choosing a plugin, understand its mechanism. All modern AI coding assistants work in two main modes:
What differentiates Neovim from other editors is flexibility: you can choose which plugin to use, set your own keymaps, and adjust behavior without vendor lock-in. Let's look at all three.
copilot.lua + copilot-cmpGitHub Copilot is the most mature and widely integrated AI assistant. For Neovim, there are two paths: copilot.vim (GitHub's official Vimscript plugin) and copilot.lua (a feature-richer Lua re-implementation). We will use copilot.lua because it is easier to customize:
return {
{
"zbirenbaum/copilot.lua",
event = "InsertEnter",
opts = {
suggestion = { enabled = true, auto_trigger = true },
panel = { enabled = true },
filetypes = {
yaml = false,
markdown = true,
help = false,
gitcommit = true,
},
},
},
{
"zbirenbaum/copilot-cmp",
dependencies = { "zbirenbaum/copilot.lua" },
config = function()
require("copilot_cmp").setup()
end,
},
}After that, add keymaps for accepting, rejecting, and navigating suggestions:
local keys = function()
local cmp = require("cmp")
local copilot_suggestion = require("copilot.suggestion")
return {
{ "<C-l>", function() copilot_suggestion.accept() end,
desc = "Accept Copilot suggestion" },
{ "<C-j>", function()
if cmp.visible() then cmp.select_next_item() end
copilot_suggestion.next()
end, desc = "Next Copilot suggestion" },
{ "<C-k>", function()
copilot_suggestion.prev()
end, desc = "Previous Copilot suggestion" },
{ "<C-u>", function() copilot_suggestion.dismiss() end,
desc = "Dismiss Copilot suggestion" },
}
endNote
The copilot-cmp combination makes Copilot suggestions appear as one source inside the nvim-cmp popup (which we built in episode 16), not as a separate ghost text. The advantage: one completion popup for LSP, buffer, path, snippet, and AI all at once — consistent and not confusing. Alternatively, without copilot-cmp, suggestions appear as gray ghost text in the buffer.
Once integrated, the workflow is:
auto_trigger = true). Ghost text appears in a dim color next to the cursor.Ctrl+l accepts the full suggestion.Ctrl+j / Ctrl+k moves to the next/previous alternative suggestion.Ctrl+u cancels the suggestion.Try writing a clear comment or function name in Go, then watch the suggestion appear. A real example:
// fungsi untuk mengembalikan jumlah elemen dalam slice
func countElements(slice []int) int {
return len(slice)
}When you write the comment above, Copilot understands the intent and suggests the return len(slice) implementation. This is an example of pattern-matching that makes it very addictive — and that is exactly where the danger lies: never accept a suggestion without thinking. Every suggestion must be verified like code you wrote yourself.
Important
First best practice: do not make accept a reflex movement. Get in the habit of pressing Ctrl+l while reading the suggestion that appears, not just blindly accepting it. Even a good AI often produces code that looks right but is logically wrong — for example using the idx variable instead of index, or ignoring the error handling your team has agreed upon.
codeium.nvimIf you do not have a GitHub Copilot subscription (or want an alternative not tied to the GitHub ecosystem), Codeium offers a similar experience with a free account. The codeium.nvim plugin is pure Lua:
return {
{
"Exafunction/codeium.nvim",
dependencies = {
"nvim-lua/plenary.nvim",
"hrsh7th/nvim-cmp",
},
event = "InsertEnter",
opts = {
enable_chat = true,
},
config = function(_, opts)
require("codeium").setup(opts)
require("cmp").setup({
sources = { { name = "codeium" } },
})
end,
},
{
"monkoose/nvlime",
event = "VeryLazy",
},
}Warning
The example spec above contains the monkoose/nvlime plugin which is deliberately wrong — that plugin is an AI REPL for Common Lisp, not part of Codeium. This is a reminder of one of the biggest pitfalls: verify the name and source of every plugin before adding it to lazy.lua. The plugin manager only executes what you write; a typo or a fake plugin with a similar name could bring malicious code into your config. Remove the nvlime line from your spec — never blindly copy code from the internet.
avante.nvimAfter autocomplete, the next level is inline AI chat that can see buffer context and edit files directly — the experience popularized by Cursor. avante.nvim brings this experience to Neovim. It uses the nvim-treesitter plugin (episode 14), nvim-cmp (episode 16), and plenary:
return {
{
"yetone/avante.nvim",
event = "VeryLazy",
version = "*",
build = "make",
dependencies = {
"nvim-treesitter/nvim-treesitter",
"hrsh7th/nvim-cmp",
"nvim-lua/plenary.nvim",
"nvim-telescope/telescope.nvim",
"nvim-treesitter/playground",
"MunifTanjim/nui.nvim",
"stevearc/dressing.nvim",
},
opts = {
provider = "copilot",
hints = { enabled = true },
windows = {
position = "right",
width = 0.5,
},
file_selector = { provider = "telescope" },
},
},
}Avante supports several model providers: openai, claude, copilot, gemini, and ollama (for local models). The example above uses copilot as the provider so you do not need to set up an extra API key — as long as you are logged into Copilot.
The workflow looks like this:
Ctrl+i to start an inline prompt next to the selection.vim.keymap.set("n", "<leader>aa", function()
vim.cmd("AvanteAsk")
end, { desc = "Avante: Ask" })
vim.keymap.set("n", "<leader>ae", function()
vim.cmd("AvanteEdit")
end, { desc = "Avante: Edit selected" })
vim.keymap.set("v", "<leader>ae", function()
vim.cmd("AvanteEdit")
end, { desc = "Avante: Edit selection" })
vim.keymap.set("n", "<leader>at", function()
vim.cmd("AvanteToggle")
end, { desc = "Avante: Toggle chat" })Tip
Avante brings the risk of AI editing many files without you understanding them. Always run :w !git diff or open diffview.nvim (episode 18) to review every AI-generated change before committing. Our recommendation: use AvanteEdit mode for single files first, and be careful with automatic cross-file edits.
Let's string it together into a daily workflow:
| Stage | Action | Tool |
|---|---|---|
| Writing new code | Let suggestions appear, accept with Ctrl+l | Copilot / Codeium |
| Rejecting a suggestion | Ctrl+u to dismiss | Copilot / Codeium |
| Asking for an explanation | Select code → AvanteAsk → ask "explain this function" | Avante |
| Refactoring | Select code → AvanteEdit → refactor instruction | Avante |
| Reviewing AI results | :w !git diff or diffview | Git / diffview |
| Writing tests | Comment "write a unit test for function X" | Copilot / Avante |
| Feature | GitHub Copilot | Codeium | Avante |
|---|---|---|---|
| Main mode | Autocomplete | Autocomplete | Chat + Edit |
| Cost | Paid (free for some) | Freemium | Free (model depends on provider) |
| cmp integration | Yes (via copilot-cmp) | Yes (native) | Yes (for prompts) |
| Repository context | Yes | Yes | Depends on provider |
| Local / offline | No | No | Possible via Ollama |
| Chat UI | Separate panel | Separate chat | Sidebar / floating like Cursor |
This is the part most often overlooked, and the most important for a professional engineer:
Warning
Never paste secrets into AI. API keys, database credentials, cloud access tokens, or customer personal data — all of it is strictly forbidden from being sent to cloud-based assistants. AI suggestions are sent to third-party servers and could be logged or used for training. In companies with strict data governance policies, this leak could be a contract violation. If in doubt, ask the security team for the list of allowed AI tools.
| Practice | Reason |
|---|---|
| Review all AI-generated code before committing | AI can produce code that looks right but is logically wrong |
| Do not paste secrets/credentials into prompts | Data is sent to third-party clouds |
| Limit AI to non-sensitive files | Infra manifests, scripts, and public internal code are not risky |
| Verify dependencies suggested by AI | AI can suggest wrong-name packages or typosquatting |
| Enable an audit trail (prompt log) | Companies often require compliance proof |
| Set acceptance criteria for AI code | AI code must pass code review like human code |
Important
In the DevOps context specifically: never let AI write IaC (Terraform, Kubernetes manifests) without thorough review. One wrong suggestion — e.g. securityContext.privileged: true or a port open to the internet — could become a production security hole. AI helps write, humans remain responsible for what is deployed.
| Mistake | Symptom | Solution |
|---|---|---|
| Not logged in / unauthenticated | Suggestions never appear, unauthorized error log | Run :Copilot auth then follow the browser login instructions |
| Suggestions appear too aggressively | Ghost text keeps blinking, disturbing typing | Reduce auto_trigger, set debounce, or disable for certain filetypes |
| Keymap conflicts between plugins | Ctrl+j used by both cmp & Copilot | Merge the logic into one handler like the example above |
| Using fake / typo-named plugins | Config error, or behavior not as expected | Verify the plugin source; check official documentation |
| Accepting suggestions without review | Subtle bugs reach production | Apply a mandatory review rule before committing |
| Sensitive data leaking into prompts | Secrets sent to the cloud | Monitor prompts; do not paste secrets; use local models (Ollama) for sensitive data |
| Avante needs an external binary | Error during build / run | Make sure make is installed; use build = "make" as in the spec |
Note
If you work with highly sensitive code and the company forbids cloud-based AI, the alternative is local models via Ollama. Run a model like codegemma or qwen2.5-coder on your local machine, then connect through the ollama provider in Avante. It is slower than the cloud, but the data never leaves your machine.
In episode 21 we integrated three AI coding assistant approaches into Neovim: GitHub Copilot for autocomplete with complete suggestion navigation keymaps, Codeium as the freemium alternative, and Avante for Cursor-style AI chat with direct editing capabilities. We also discussed a healthy AI workflow — from accepting suggestions, reviewing with git diff, to writing tests — along with non-negotiable security practices: never paste secrets into AI, and always review AI-generated code before committing.
Remember your position in the chain: AI is the co-pilot, not the pilot. The ship is still steered by you.
Now that the editor can write code quickly with AI assistance, we need the opposite ability: finding and fixing bugs correctly. In episode 22, we will cover Debugging with DAP (Debug Adapter Protocol) using nvim-dap and nvim-dap-ui — turning Neovim into an interactive debugger on par with GUI IDEs. Stay motivated!