Skip to content

Upgrading CodeCompanion ​

CodeCompanion follows semantic versioning, so breaking changes only arrive in a major version. Each section below lists what changed and how to update your config.

To upgrade when you're ready rather than when your plugin manager decides, pin CodeCompanion to a version. See the installation guide.

v19.27.0 to v20.0.0 ​

IMPORTANT

The openai and gemini adapters now use different APIs. If you use either of them, read the Adapters section before upgrading

Adapters ​

  • openai now uses OpenAI's Responses API and gemini uses Google's Interactions API. The previous adapters are now openai_legacy and gemini_legacy
  • Adapters built with extend("openai") or extend("gemini") use the new APIs too
  • openai_responses and gemini_interactions are removed. Use openai and gemini instead
  • In your own plugins, change require("codecompanion.adapters.http.openai") to require("codecompanion.adapters.http.openai_legacy")
  • The GitHub Models adapter is removed

To keep using the previous APIs:

lua
require("codecompanion").setup({
  interactions = {
    chat = {
      adapter = "openai_legacy", -- Can be "openai_legacy" or "gemini_legacy"
    },
    inline = {
      adapter = "openai_legacy",
    },
  },
})
lua
require("codecompanion").setup({
  adapters = {
    http = {
      openai = function()
        return require("codecompanion.adapters").extend("openai_legacy", { 
          env = {
            api_key = "OPENAI_API_KEY",
          },
        })
      end,
    },
  },
})
  • HTTP adapter handlers in the nested format (lifecycle, request, response and tools) now take a single args table after self, in place of positional arguments. New fields can be added without breaking your handlers, and a handler that wraps another can pass args straight through. If you've written or extended an adapter in this format, update each handler:
lua
require("codecompanion").setup({
  adapters = {
    http = {
      openai = function()
        return require("codecompanion.adapters").extend("openai", {
          handlers = {
            response = {
              parse_chat = function(self, data, tools) 
              parse_chat = function(self, args) 
                local data, tools = args.data, args.tools
                -- ...
              end,
            },
          },
        })
      end,
    },
  },
})

The fields in args match the old positional arguments:

Handlerargs
lifecycle.on_exitdata
request.build_parametersparams, messages
request.build_messagesmessages
request.build_toolstools
request.build_structured_outputschema
request.build_reasoningdata
request.build_bodypayload
response.parse_chatdata, tools
response.parse_tokensdata
response.parse_metadata
tools.format_callstools
tools.format_responsetool_call, output

lifecycle.setup and lifecycle.teardown still take only self. Handlers in the flat format, such as form_messages and chat_output, are unaffected.

  • ACP adapters now use the same nested format, with lifecycle.setup, lifecycle.auth, lifecycle.on_exit and request.build_messages. Flat handlers still work, and take precedence over nested ones when you extend an adapter. helpers.form_messages is now helpers.build_messages, though the old name still works:
lua
require("codecompanion").setup({
  adapters = {
    acp = {
      claude_code = function()
        return require("codecompanion.adapters").extend("claude_code", {
          handlers = {
            form_messages = function(self, messages, capabilities) 
            request = { 
              build_messages = function(self, args) 
                -- args.messages, args.capabilities
              end,
            }, 
          },
        })
      end,
    },
  },
})

Slash Commands ​

  • The /image slash command is removed. Select an image with /file, or use the new /file-from-url slash command for an image at a URL. Move any opts.dirs you set for /image to /file, and delete opts.filetypes and opts.provider, which have no equivalent:
lua
require("codecompanion").setup({
  interactions = {
    chat = {
      slash_commands = {
        ["image"] = { 
        ["file"] = { 
          opts = {
            dirs = { "~/Pictures" },
          },
        },
      },
    },
  },
})

Tools ​

  • The insert_edit_into_file tool is replaced by edit_file (#3427). It takes the same options, so rename it in your config, custom groups and prompts:
lua
require("codecompanion").setup({
  interactions = {
    chat = {
      tools = {
        ["insert_edit_into_file"] = { 
        ["edit_file"] = { 
          opts = {
            require_confirmation_after = false,
          },
        },
      },
    },
  },
})
  • The web_search tool now uses DuckDuckGo by default, which doesn't need an API key. Previously it used Tavily
  • The fetch_webpage tool and /fetch slash command now use MarkItDown by default. Previously they used Jina

IMPORTANT

MarkItDown runs the markitdown CLI on your machine, so it must be installed. :checkhealth codecompanion reports if it's missing

To keep the previous defaults:

lua
require("codecompanion").setup({
  interactions = {
    chat = {
      slash_commands = {
        ["fetch"] = {
          opts = {
            adapter = "jina",
          },
        },
      },
      tools = {
        ["fetch_webpage"] = {
          opts = {
            adapter = "jina",
          },
        },
        ["web_search"] = {
          opts = {
            adapter = "tavily",
          },
        },
      },
    },
  },
})
  • interactions.chat.tools.opts.auto_submit_errors and interactions.chat.tools.opts.auto_submit_success are removed. A tool's output is always sent back to the LLM, as part of the agent loop

Chat ​

Chat buffer methods that took several positional arguments now take a table. Update any calls from a custom tool, slash command or callback:

MethodBeforeAfter
add_tool_output(tool, for_llm, for_user)(tool, { content, display? })
add_context(data, source, id, opts)(data, { source, id, bufnr?, path?, tag?, visible?, context_opts? })
change_adapter(adapter, callback)({ adapter, model?, callback? })
done(output, reasoning, tools, meta, opts)({ output?, reasoning?, tools?, meta?, status?, error? })
update_buf_line(line_number, content, opts)({ line_number, content, status?, icon_id?, priority?, virt_text_pos? })

For example, in a tool's output handler:

lua
chat:add_tool_output(self, "The result is 42", "Calculated 6 * 7") 
chat:add_tool_output(self, { content = "The result is 42", display = "Calculated 6 * 7" }) 

Inline ​

The inline interaction now edits the buffer with the edit_file tool, rather than asking the LLM where to place a block of code. See How Edits Work.

IMPORTANT

The default inline adapter is now copilot with the gpt-5.4-mini model, as editing through a tool needs a capable model to be reliable. This makes inline unusable on Copilot's free and student plans, so change the adapter if you're on one

Update your config

If you've customised inline:

  • Delete the #{buffer} editor context from your inline prompts. The current buffer is always shared with the LLM, up to a context limit
  • Delete placement from your inline prompts. Writing code into a new buffer is no longer an option
  • Delete display.inline.layout
  • Delete the response.parse_inline and inline_output handlers from your adapters. Inline now uses response.parse_chat (or chat_output) and the tool handlers, the same as the chat buffer
  • pre_hook no longer runs for inline prompts
  • The Unit tests prompt (/tests) has been removed from the prompt library

What's changed

  • The adapter's model must support tool calling. Inline prompts sent with an adapter that doesn't, such as xai, are refused with an error
  • With a visual selection, the LLM can only edit the selected lines
  • A reply that doesn't edit the buffer, such as an answer to a question, opens in a float rather than a chat buffer
  • :CodeCompanion with no prompt, and prompts with user_prompt, now open CodeCompanion's input box rather than vim.ui.input
  • The inline diff can be reviewed a hunk at a time with the new accept_hunk (ga), reject_hunk (gr) and undo_hunk (u) keymaps in interactions.shared.keymaps. reject_change now rejects only the hunks that are left

IMPORTANT

Your default rules group, including AGENTS.md and CLAUDE.md, is sent with every inline prompt to an HTTP adapter, on top of the context limit. Set rules.opts.inline.autoload = {} to stop it. See Rules and Skills

v18.7.0 to v19.0.0 ​

  • The Super Diff is removed (#2600)
  • CodeCompanion only supports its built-in diff, which is enabled by default. Mini.Diff is no longer supported (#2600)
  • The full_stack_dev group is renamed to agent (#2786)
  • The next_edit_suggestion and list_code_usages tools are removed

Adapters ​

  • The Claude Code adapter needs Zed's claude-agent-acp installed, which was previously named claude-code-acp (#2779)

Config ​

  • Diff keymaps have moved from interactions.inline.keymaps to interactions.shared.keymaps (#2600)
  • All diff config has moved to display.diff (#2600)
  • variables are renamed to editor_context, at interactions.chat.editor_context and interactions.inline.editor_context (#2719)
  • Across editor context, slash commands and tools, string values for callback (module paths and file paths) move to path. callback is still used for functions

Prompt Library ​

  • Rules in a prompt library item move from opts.rules to rules:
markdown
---
name: Oli's test workflow
strategy: chat
description: Workflow test prompt
rules:
  - test_rule
---

v17.33.0 to v18.0.0 ​

Config ​

  • strategies is renamed to interactions. This only breaks your config if it references codecompanion.strategies, which becomes codecompanion.interactions (#2485)
  • The /catalog folders for built-in slash commands and tools are renamed to /builtin. Update any paths in your config that point at them (#2482)
  • Workspaces are removed. Use rules instead

Adapters ​

  • In a custom adapter, rename condition to enabled on any schema items (#2439):
lua
return {
  schema = {
    ["reasoning.effort"] = {
      ---@type fun(self: CodeCompanion.HTTPAdapter): boolean
      condition = function(self) 
      enabled = function(self) 
        --
      end,
    },
  }
}
  • The default models for the anthropic and gemini adapters are now claude-sonnet-4-5-20250929 and gemini-3-pro-preview (#2494)
  • To hide the adapters that come with CodeCompanion, adapters.[acp|http].opts.show_defaults is renamed to adapters.[acp|http].opts.show_presets (#2497)

Chat ​

  • Memory is renamed to rules. Rename any memory references in your config to rules (#2440)
  • default_memory is renamed to autoload (#2509)
  • #{buffer}{watch} is renamed to #{buffer}{diff}, as the LLM receives a diff of the buffer's changes with each request (#2444)
  • #{buffer}{pin} is renamed to #{buffer}{all}, as the entire buffer is sent with each request (#2444)
  • To pass an adapter to :CodeCompanionChat, use :CodeCompanionChat adapter=<adapter_name> (#2437)
  • A chat system prompt at opts.system_prompt moves to interactions.chat.opts.system_prompt (#2484)

Prompt Library ​

If you define prompts in your config:

  • Rename opts.short_name to opts.alias on each item, so you can still call it with require("codecompanion").prompt("my_prompt") or as a slash command in the chat buffer (#2471):
lua
["my custom prompt"] = {
  strategy = "chat",
  description = "My custom prompt",
  opts = {
    short_name = "my_prompt", 
    alias = "my_prompt", 
  },
  prompts = {
    -- ...
  },
},
  • In workflow prompts, replace strategy = "workflow" with interaction = "chat" and set opts.is_workflow = true (#2487):
lua
["my_workflow"] = {
  strategy = "workflow", 
  interaction = "chat", 
  description = "My custom workflow",
  opts = {
    is_workflow = true, 
  },
  prompts = {
    -- ...
  },
},
  • To hide the built-in prompt library items, display.action_palette.show_default_prompt_library is renamed to display.action_palette.show_preset_prompts (#2499)

Tools ​

If you configure tools, rename:

  • requires_approval to require_approval_before (#2439)
  • user_confirmation to require_confirmation_after (#2450)

UI ​

  • display.chat.child_window is renamed to display.chat.floating_window (#2452)
  • display.action_palette.opts.show_default_actions is renamed to display.action_palette.opts.show_preset_actions (#2499)

Released under the Apache-2.0 License.