________
╱ ╲
╱ ╱
╱ ╱
╲__╱__╱__╱
Magenta is for agents.
Jan 2025 update
Plugin overview (Dec 2024)
magenta.nvim
is a plugin for leveraging LLM agents in neovim. It provides a chat window where you can talk to your AI coding assistant, as well as tools to populate context and perform inline edits. In functionality, it's similar to cursor-compose, cody or windsurf.
Rather than writing complex code to compress your repo and send it to the LLM (like a repomap in aider, etc...), magenta is built around the idea that the AI agent can choose which context to gather via tools.
Flagship models will continue to get better at tools use, and as this happens, the gap between tools like magenta and other editors that try to be clever about context management will grow smaller.
Make sure you have node installed, at least v20
:
node --version
The plugin will look for configuration for providers in the following env variables:
{
"dlants/magenta.nvim",
lazy = false, -- you could also bind to <leader>mt
build = "npm install --frozen-lockfile",
opts = {},
},
local vim = vim
local Plug = vim.fn['plug#']
vim.call('plug#begin')
Plug('dlants/magenta.vim', {
['do'] = 'npm install --frozen-lockfile',
})
vim.call('plug#end')
require('magenta').setup()
require('magenta').setup({
provider = "anthropic",
openai = {
model = "gpt-4o"
},
anthropic = {
model = "claude-3-5-sonnet-latest"
},
bedrock = {
model = "anthropic.claude-3-5-sonnet-20241022-v2:0",
prompt_caching = false
},
-- open chat sidebar on left or right side
sidebar_position = "left",
-- can be changed to "telescope"
picker = "fzf-lua",
-- enable default keymaps shown below
default_keymaps = true,
-- keymaps for the sidebar input buffer
sidebar_keymaps = {
normal = {
["<CR>"] = ":Magenta send<CR>",
}
},
-- keymaps for the inline edit input buffer
-- if keymap is set to function, it accpets a target_bufnr param
inline_keymaps = {
normal = {
["<CR>"] = function(target_bufnr)
vim.cmd("Magenta submit-inline-edit " .. target_bufnr)
end,
},
}
})
If default_keymaps
is set to true, the plugin will configure the following global keymaps:
local Actions = require("magenta.actions")
vim.keymap.set(
"n",
"<leader>mc",
":Magenta clear<CR>",
{silent = true, noremap = true, desc = "Clear Magenta state"}
)
vim.keymap.set(
"n",
"<leader>ma",
":Magenta abort<CR>",
{silent = true, noremap = true, desc = "Abort current Magenta operation"}
)
vim.keymap.set(
"n",
"<leader>mt",
":Magenta toggle<CR>",
{silent = true, noremap = true, desc = "Toggle Magenta window"}
)
vim.keymap.set(
"n",
"<leader>mi",
":Magenta start-inline-edit<CR>",
{silent = true, noremap = true, desc = "Inline edit"}
)
vim.keymap.set(
"v",
"<leader>mi",
":Magenta start-inline-edit-selection<CR>",
{silent = true, noremap = true, desc = "Inline edit selection"}
)
vim.keymap.set(
"v",
"<leader>mp",
":Magenta paste-selection<CR>",
{silent = true, noremap = true, desc = "Send selection to Magenta"}
)
vim.keymap.set(
"n",
"<leader>mb", -- like "magenta buffer"?
Actions.add_buffer_to_context,
{ noremap = true, silent = true, desc = "Add current buffer to Magenta context" }
)
vim.keymap.set(
"n",
"<leader>mf",
Actions.pick_context_files,
{ noremap = true, silent = true, desc = "Select files to add to Magenta context" }
)
vim.keymap.set(
"n",
"<leader>mp",
Actions.pick_provider,
{ noremap = true, silent = true, desc = "Select provider and model" }
)
In order to use fzf-lua as your selector for certain commands, like <leader>mp
for :Magenta provider
, you should
set it as the default selector for neovim, by running register_ui_select
at some point during initialization.
{
"ibhagwan/fzf-lua",
lazy = false,
config = function()
require("fzf-lua").setup({
-- ...
})
require("fzf-lua").register_ui_select()
end,
-- ...
}
<leader>mt
is for :Magenta toggle
. This will open a sidebar where you can chat with the model. You can add files to the context with Magenta context-files
(<leader>mf
), or paste your current visual selection with Magenta paste-selection
(<leader>mp
)<leader>mi
is for :Magenta start-inline-edit
, or start-inline-edit-selection
in visual mode. This will bring up a new split where you can write a prompt to edit the current buffer. Magenta will force a find-and-replace tool use for normal mode, or force a replace tool use for the selection in visual mode.Inline edit uses your chat history so far, so a great workflow is to build up context in the chat panel, and then use it to perform inline edits in a buffer.
The display buffer is not modifiable, however you can interact with some parts of the display buffer by pressing <CR>
. For example, you can expand the tool request and responses to see their details, and you can trigger a diff to appear on file edits.
The command :Magenta provider <provider>
will set the current provider. Currently supported values are openai
(defaults to ChatGPT 4o) and anthropic
(defaults to Claude Sonnet 3.5). You can also provide configuration to setup that will choose the default provider and model. code
Any provider that has a node sdk and supports tool use should be easy to add. Contributions are welcome.
See the most up-to-date list of implemented tools here.
:UpdateRemotePlugins
! (h/t wallpants).I think the closest plugins to this one are avante.nvim and codecompanion.nvim
Codecompanion has a single buffer, while magenta.nvim has separate input & display buffers. This makes it easier to add some interactivity to the display buffer (since it's not directly editable). I think this makes it nicer for situations when the LLM uses multiple tools at once. So for example, in codecompanion when the LLM needs permission to open a file, or proposes a change, this takes over your editor, which isn't a nice workflow when the tool needs to edit multiple files.
I think it's fairly similar. However, magenta.nvim is written in typescript and uses the sdks to implement streaming, which I think makes it more stable. I think the main advantage is the architecture is very clean so it should be easy to extend the functionality. Between typescript, sdks and the architecture, I think my velocity is pretty high. I haven't used avante in a while so I'm not sure how close I got feature-wise, but it should be fairly close, and only after a couple of weeks of development time.
AFAIK both avante and codecompanion roll their own tool system, so the tools are defined in-prompt, and they do the parsing of the tool use themselves. I'm instead using the providers tool capabilities, like the one in anthropic. In practice I think this makes the tool use a lot more robust.
I'm not doing any treesitter analysis of symbols, dependencies, or repository summarization / repomap construction. As I mentioned in the intro, I'm opting instead to rely on the agent to explore the repo using the tools available to it. Right now that's occasionally worse than the repomap approach, but I think with time it will matter less and less.
Another thing that's probably glaringly missing is model selection and customization of keymappings, etc... I'll probably do some of this eventually, but if you use a different picker / completion plugin, or you would like to make something configurable that is not currently, I would welcome contributions.