return { "olimorris/codecompanion.nvim", branch = "main", dependencies = { { "ravitemer/mcphub.nvim", dependencies = { "nvim-lua/plenary.nvim", }, build = "bundled_build.lua", -- Bundles `mcp-hub` binary along with the neovim plugin config = function() require("mcphub").setup({ use_bundled_binary = true, -- Use local `mcp-hub` binary --- `mcp-hub` binary related options------------------- config = vim.fn.expand("~/.config/mcphub/servers.json"), -- Absolute path to MCP Servers config file (will create if not exists) port = 37373, -- The port `mcp-hub` server listens to shutdown_delay = 5 * 60 * 000, -- Delay in ms before shutting down the server when last instance closes (default: 5 minutes) use_bundled_binary = false, -- Use local `mcp-hub` binary (set this to true when using build = "bundled_build.lua") mcp_request_timeout = 60000, --Max time allowed for a MCP tool or resource to execute in milliseconds, set longer for long running tasks global_env = {}, -- Global environment variables available to all MCP servers (can be a table or a function returning a table) workspace = { enabled = true, -- Enable project-local configuration files look_for = { ".mcphub/servers.json", ".vscode/mcp.json", ".cursor/mcp.json" }, -- Files to look for when detecting project boundaries (VS Code format supported) reload_on_dir_changed = true, -- Automatically switch hubs on DirChanged event port_range = { min = 40000, max = 41000 }, -- Port range for generating unique workspace ports get_port = nil, -- Optional function returning custom port number. Called when generating ports to allow custom port assignment logic }, ---Chat-plugin related options----------------- auto_approve = false, -- Auto approve mcp tool calls auto_toggle_mcp_servers = true, -- Let LLMs start and stop MCP servers automatically extensions = { avante = { make_slash_commands = true, -- make /slash commands from MCP server prompts } }, --- Plugin specific options------------------- native_servers = {}, -- add your custom lua native servers here builtin_tools = { edit_file = { parser = { track_issues = true, extract_inline_content = true, }, locator = { fuzzy_threshold = 0.8, enable_fuzzy_matching = true, }, ui = { go_to_origin_on_complete = true, keybindings = { accept = ".", reject = ",", next = "n", prev = "p", accept_all = "ga", reject_all = "gr", }, }, }, }, ui = { window = { width = 0.8, -- 0-1 (ratio); "50%" (percentage); 50 (raw number) height = 0.8, -- 0-1 (ratio); "50%" (percentage); 50 (raw number) align = "center", -- "center", "top-left", "top-right", "bottom-left", "bottom-right", "top", "bottom", "left", "right" relative = "editor", zindex = 50, border = "rounded", -- "none", "single", "double", "rounded", "solid", "shadow" }, wo = { -- window-scoped options (vim.wo) winhl = "Normal:MCPHubNormal,FloatBorder:MCPHubBorder", }, }, json_decode = nil, -- Custom JSON parser function (e.g., require('json5').parse for JSON5 support) on_ready = function(hub) -- Called when hub is ready end, on_error = function(err) -- Called on errors end, log = { level = vim.log.levels.WARN, to_file = false, file_path = nil, prefix = "MCPHub", }, }) end, }, "nvim-lua/plenary.nvim", "nvim-treesitter/nvim-treesitter", "nvim-treesitter/nvim-treesitter", "jellydn/spinner.nvim", -- Show loading spinner when request is started "ravitemer/codecompanion-history.nvim", -- History management extension { "echasnovski/mini.diff", config = function() local diff = require "mini.diff" diff.setup { source = diff.gen_source.none() } end, }, { "HakonHarnes/img-clip.nvim", opts = { filetypes = { codecompanion = { prompt_for_file_name = false, template = "[Image]($FILE_PATH)", use_absolute_path = true, }, }, }, }, { "OXY2DEV/markview.nvim", lazy = false, opts = { preview = { filetypes = { "markdown", "codecompanion" }, ignore_buftypes = {}, }, }, }, }, opts = { log_level = "DEBUG", }, config = function() require("codecompanion").setup({ mcp = { servers = { ["duckduckgo-mcp"] = { cmd = { "npx", "-y", "duckduckgo-mcp" }, }, }, opts = { default_servers = { "duckduckgo-mcp" }, }, }, adapters = { http = { ["llama.cpp"] = function() return require("codecompanion.adapters").extend("openai_compatible", { env = { url = "http://127.0.0.1:8012", -- replace with your llama.cpp instance chat_url = "/v1/chat/completions", }, }) end, }, acp = { claude_code = function() return require("codecompanion.adapters").extend("claude_code", { env = { CLAUDE_CODE_OAUTH_TOKEN = "cmd:echo $CLAUDE_CODE_OAUTH_TOKEN", }, }) end, }, }, interactions = { chat = { -- opts = { -- system_prompt = function(ctx) -- return "You are a helpful coding assistant. Today is " .. ctx.date -- end, -- }, auto_scroll = false, tools = { opts = { default_tools = { "agent", "neovim", "files", "grep_search", "get_changed_files", "fetch_webpage", }, auto_submit_errors = true, -- Send any errors to the LLM automatically? auto_submit_success = true, -- Send any successful output to the LLM automatically? }, }, slash_commands = { ["file"] = { -- Use Snacks as the provider for the /file command opts = { provider = "snacks", -- Can be "default", "telescope", "fzf_lua", "mini_pick" or "snacks" }, }, ["image"] = { ---@param opts { adapter: CodeCompanion.HTTPAdapter } ---@return boolean enabled = function(opts) return opts.adapter.opts and opts.adapter.opts.vision == true end, -- Keep snacks for image-aware picker preview opts = { provider = "snacks", -- Can be "default", "telescope", "fzf_lua", "mini_pick" or "snacks" }, }, }, -- adapter = "llama.cpp", adapter = { name ="claude_code", -- model = "claude-opus-4-8", -- model = "claude-sonnet-4-6", model = "claude-haiku-4-5", }, -- adapter = { -- name = "copilot", -- model = "gpt-4.1", -- }, }, inline = { -- adapter = "llama.cpp", adapter = { name ="claude_code", model = "claude-haiku-4-5", -- model = "claude-sonnet-4-6", }, -- adapter = { -- name = "copilot", -- model = "gpt-4.1", -- }, }, cmd = { -- adapter = "llama.cpp", adapter = { name ="claude_code", model = "claude-haiku-4-5", -- model = "claude-sonnet-4-6", }, -- adapter = { -- name = "copilot", -- model = "gpt-4.1", -- }, }, background = { -- adapter = "llama.cpp" adapter = { name ="claude_code", model = "claude-haiku-4-5", -- model = "claude-sonnet-4-6", }, -- adapter = { -- name = "copilot", -- model = "gpt-4.1", -- }, }, cli = { agent = "claude_code", agents = { claude_code = { cmd = "claude", args = {}, description = "Claude Code CLI", provider = "terminal", }, }, }, }, extensions = { history = { enabled = true, opts = { keymap = "gh", save_chat_keymap = "sc", auto_save = true, expiration_days = 0, picker = "snacks", chat_filter = nil, picker_keymaps = { rename = { n = "r", i = "" }, delete = { n = "d", i = "" }, duplicate = { n = "", i = "" }, }, auto_generate_title = true, title_generation_opts = { adapter = nil, model = nil, refresh_every_n_prompts = 0, -- e.g., 3 to refresh after every 3rd user prompt max_refreshes = 3, format_title = function(original_title) return original_title end }, continue_last_chat = false, delete_on_clearing_chat = false, dir_to_save = vim.fn.stdpath("data") .. "/codecompanion-history", enable_logging = false, summary = { create_summary_keymap = "gcs", browse_summaries_keymap = "gbs", generation_opts = { adapter = nil, -- defaults to current chat adapter model = nil, -- defaults to current chat model context_size = 90000, -- max tokens that the model supports include_references = true, -- include slash command content include_tool_outputs = true, -- include tool execution results system_prompt = nil, -- custom system prompt (string or function) format_summary = nil, -- custom function to format generated summary e.g to remove tags from summary }, }, memory = { auto_create_memories_on_summary_generation = true, vectorcode_exe = "vectorcode", tool_opts = { default_num = 10 }, notify = true, index_on_startup = false, }, } } }, action_palette = { width = 95, height = 10, prompt = "Prompt ", -- Prompt used for interactive LLM calls provider = "snacks", -- Can be "default", "telescope", "fzf_lua", "mini_pick" or "snacks". If not specified, the plugin will autodetect installed providers. opts = { show_preset_actions = true, -- Show the preset actions in the action palette? show_preset_prompts = true, -- Show the preset prompts in the action palette? title = "CodeCompanion actions", -- The title of the action palette }, }, }) -- Show loading spinner when request is started local spinner = require "spinner" local group = vim.api.nvim_create_augroup("CodeCompanionHooks", {}) vim.api.nvim_create_autocmd({ "User" }, { pattern = "CodeCompanionRequest*", group = group, callback = function(request) if request.match == "CodeCompanionRequestStarted" then spinner.show() end if request.match == "CodeCompanionRequestFinished" then spinner.hide() end end, }) end, }