Skip to content

Using Agents and Tools ​

IMPORTANT

The built-in tools are for HTTP adapters only, and not every LLM supports tool use. See compatibility

Using an agent in the chat buffer

An LLM acts as an agent when it can use tools, such as searching the web or running code (Agentic Design Patterns Part 3, Tool Use). In CodeCompanion, a tool is context and an action shared with the LLM, which the chat buffer runs inside Neovim on the LLM's behalf. Add a tool to the chat buffer by typing @.

IMPORTANT

Some tools need your approval before they run, making you the human in the loop

How They Work ​

Tools use an LLM's function calling ability. Every tool in CodeCompanion follows OpenAI's specification for defining functions.

For HTTP adapters, CodeCompanion is the harness: the system prompt, tools, approvals and context management that turn an LLM into an agent. ACP adapters such as Claude Code and Codex bring their own harness, which is why the built-in tools are for HTTP adapters only.

The harness runs the agent loop:

  1. You submit a prompt
  2. The LLM responds, optionally asking to run one or more tools
  3. CodeCompanion runs each tool in turn, asking for your approval where needed
  4. The tools' output is sent back to the LLM and the loop returns to step 2

The loop ends when the LLM responds without asking for a tool, or when you stop the request or cancel a tool. Rejecting a tool doesn't end the loop. The LLM is told you rejected it, along with your reason, and carries on.

The tool system architecture is outlined in the extending section.

Tool Groups ​

A tool group makes several tools available to the LLM with a single @{group_name} reference. CodeCompanion comes with two: @{agent} and @{files}.

By default, a group shows as a single <group>name</group> context item in the chat buffer. To list each of its tools as a context item instead, set opts.collapse_tools = false on the group.

A group's prompt replaces its reference in your message, so the LLM receives a sentence rather than the group's name. ${tools} in the prompt expands to the group's tools.

agent ​

The @{agent} group is CodeCompanion's agent mode. It has its own system prompt, which replaces the default chat and tool system prompts, and contains:

To use it:

md
@{agent} Can we create a todo list app in Vue.js?

files ​

The @{files} group carries out file operations in the current working directory. It contains:

To use it:

md
@{files} Can you scaffold out the folder structure for a python package?

Custom Agents ​

A group becomes an agent when it has its own system_prompt. With ignore_system_prompt and ignore_tool_system_prompt, it replaces the default system prompts entirely. This is how @{agent} works.

A system_prompt function receives the group's config and a context object with language, cwd, date, nvim_version, os and more:

lua
require("codecompanion").setup({
  interactions = {
    chat = {
      tools = {
        groups = {
          ["my_agent"] = {
            description = "My custom agent",
            system_prompt = function(group, ctx)
              return string.format("You are a coding agent. The date is %s. The user is on %s.", ctx.date, ctx.os)
            end,
            tools = { "read_file", "edit_file", "run_command" },
            opts = {
              collapse_tools = true,
              ignore_system_prompt = true,
              ignore_tool_system_prompt = true,
            },
          },
        },
      },
    },
  },
})

Built-in Tools ​

The built-in tools work with any adapter and model that supports tool use:

ToolDescription
ask_questionsAsk you clarifying questions before acting
create_fileCreate a file
delete_fileDelete a file in the current working directory
edit_fileEdit a buffer or file by replacing exact text
fetch_webpageFetch the content of a webpage
file_searchFind files by glob pattern
get_changed_filesGet git diffs of the current changes
get_diagnosticsGet LSP diagnostics for a file
grep_searchSearch for text in files
memoryStore and retrieve information across conversations
read_fileRead all or part of a file
run_commandRun shell commands
search_helpSearch the CodeCompanion docs
web_searchSearch the web

When you send a prompt, each tool reference is replaced with interactions.chat.tools.opts.tool_replacement_message, which defaults to "the ${tool} tool". So this:

md
Use @{grep_search} to find where the adapter is resolved

reaches the LLM as:

md
Use the grep_search tool to find where the adapter is resolved

ask_questions ​

NOTE

This tool is hidden from the completion menu and comes with the @{agent} group

The LLM asks you up to four clarifying questions before acting. It uses this when requirements are ambiguous, when it needs to choose between approaches or when it wants to check an assumption:

md
@{agent} Can you refactor the authentication module?

create_file ​

NOTE

By default, you see a preview of the file's contents and confirm it before the file is created

md
Can you create some test fixtures using @{create_file}?
OptionDefaultDescription
require_approval_beforefalseRequire approval before showing the preview
require_confirmation_aftertrueShow a preview of the contents and require confirmation before creating the file

delete_file ​

NOTE

By default, this tool requires your approval before it runs

md
Can you use @{delete_file} to delete the quotes.lua file?
OptionDefaultDescription
judgefalseLet the LLM judge decide in Auto mode
protecttrueAlways ask before deleting a file in Auto mode
require_approval_beforetrueRequire approval before deleting a file

edit_file ​

NOTE

By default, you confirm each edit in a diff before it's written

The LLM edits buffers and files by replacing an exact piece of text with new text:

md
Use @{edit_file} to refactor the code in #buffer

The text being replaced must match the file exactly, including indentation. If it can't be found, or it appears more than once, the edit fails and the LLM is told why so it can try again. A file that's open in Neovim is edited in its buffer and saved, and any other file keeps its line endings.

OptionDefaultDescription
require_approval_before.bufferfalseRequire approval before editing a buffer
require_approval_before.filefalseRequire approval before editing a file
require_confirmation_aftertrueRequire confirmation of the diff before the edit is written
file_size_limit_mb2Files larger than this aren't edited

fetch_webpage ​

The LLM fetches the content of a webpage, converted to text by the tool's adapter:

md
Use @{fetch_webpage} to tell me what the latest version on neovim.io is
OptionDefaultDescription
adapter"markitdown"The adapter that fetches and converts the page. Can be "markitdown" or "jina"

The LLM finds files in the current working directory by glob pattern, and receives the matching paths:

md
Use @{file_search} to list all the lua files in my project
OptionDefaultDescription
max_results500Maximum number of paths sent to the LLM

get_changed_files ​

The LLM gets git diffs of the changes in the current working directory, covering staged, unstaged and merge conflicted files:

md
Use @{get_changed_files} to see what's changed
OptionDefaultDescription
max_lines1000Maximum number of diff lines sent to the LLM

get_diagnostics ​

WARNING

This tool relies on language servers, so it may be unreliable for some filetypes

The LLM gets the LSP diagnostics for a file (errors, warnings, information and hints) along with the lines they refer to:

md
Use @{get_diagnostics} to check for any issues in the current file

The LLM can pass a minimum severity of ERROR, WARNING, INFORMATION or HINT. It defaults to HINT, which includes everything.

IMPORTANT

This tool requires ripgrep and is unavailable without it

The LLM searches for text in files in the current working directory, and receives the path and line number of each match:

md
Use @{grep_search} to find all occurrences of `buf_add_message`
OptionDefaultDescription
max_results100Maximum number of matches sent to the LLM
require_approval_beforetrueRequire approval before searching
respect_gitignoretrueSkip files ignored by git

memory ​

IMPORTANT

Every memory operation is restricted to the /memories directory and any whitelisted paths

The LLM stores and retrieves information across conversations in a memory directory, <cwd>/memories. With the Anthropic adapter, this tool is the client side of Anthropic's memory tool.

md
Use @{memory} to carry on our conversation about streamlining my dotfiles

The LLM can use these commands:

CommandDescription
viewList a directory, two levels deep, or show a file with an optional line range
createCreate a file, or overwrite an existing one
str_replaceReplace text in a file, which must match exactly once
insertInsert text at a line number
deleteDelete a file, or a directory and everything in it
renameMove or rename a file or directory

By default, the tool requires your approval before it runs (require_approval_before = true).

Whitelisted Paths

To give the LLM access to paths outside <cwd>/memories, map each one to a virtual prefix:

lua
require("codecompanion").setup({
  interactions = {
    chat = {
      tools = {
        ["memory"] = {
          opts = {
            whitelist = {
              { path = "~/.dotfiles", as = "/dotfiles" },
              { path = "/shared/notes", as = "/notes" },
            },
          },
        },
      },
    },
  },
})

The LLM then uses /dotfiles/.zshrc or /notes/todo.md just as it uses /memories/file.txt. A ~ is expanded, and directory traversal protection applies to every whitelisted path.

A single file can be mounted too, such as a personal profile the LLM learns from and updates over time:

lua
require("codecompanion").setup({
  interactions = {
    chat = {
      tools = {
        ["memory"] = {
          opts = {
            whitelist = {
              { path = "~/.dotfiles/PERSONAL.md", as = "/personal" },
            },
          },
        },
      },
    },
  },
})

read_file ​

The LLM reads all or part of a file, using an absolute path or one relative to the current working directory. This gives it context from files you haven't shared:

md
Use @{read_file} to read the README and summarise the project
OptionDefaultDescription
require_approval_beforetrueRequire approval before reading a file

run_command ​

The LLM runs shell commands on your machine:

md
Can you use @{run_command} to run my test suite with `pytest`?

If a command succeeds without writing to stdout, the LLM is told there was no output. If it fails, the LLM receives its stderr and stdout.

The LLM is instructed to flag a command that runs a test suite. CodeCompanion then records whether the tests passed as a flag on the chat buffer, which agentic workflows can hook into.

OptionDefaultDescription
judgefalseLet the LLM judge decide in Auto mode
require_approval_beforetrueRequire approval before running a command
safe_commands{ "git status", "ls", "pwd" }Commands that run without asking in Auto mode
timeout300000Milliseconds before a command is terminated

search_help ​

The LLM searches the CodeCompanion docs, grounding its answers in the plugin's documentation rather than its own, possibly out of date, knowledge:

md
Use @{search_help} to find out how I can do a code review in CodeCompanion

The LLM searches the web, so it can answer with up to date information:

md
Use @{web_search} to search neovim.io and explain how I can configure a new language server

By default, the tool uses DuckDuckGo, which needs no API key. Other search providers can be configured.

Adapter Tools ​

NOTE

Adapter tools are configured in the available_tools table on the adapter

Adapter tools are owned by LLM providers and run remotely, covering tasks such as web search and code execution. They were added in v17.30.0. You use them in the same way as the built-in tools, and an adapter tool takes precedence over a built-in tool of the same name.

AdapterToolDescription
anthropiccode_executionRun Bash commands and manipulate files in a sandbox
anthropicmemoryStore and retrieve information across conversations, using the memory tool as its client
anthropicweb_fetchRetrieve the full content of webpages and PDF documents
anthropicweb_searchSearch the web for up to date information
geminiweb_searchSearch the web with Google Search
openaiweb_searchSearch the web for up to date information
openrouterfetch_webpageFetch the content of a URL, with any model
openrouterweb_searchSearch the web, with any model

MCP ​

The tools from your configured MCP servers are available in the chat buffer once a server has started. Type @ to find them in the completion menu, prefixed with mcp:.

Security ​

Tools are designed to keep the LLM from making changes that are hard to recover from. delete_file refuses any path outside the current working directory, and memory is restricted to its own directory and any whitelisted paths.

Approvals ​

NOTE

This applies to CodeCompanion's built-in tools only. ACP agents have their own tools and approval systems

Approvals are kept per chat buffer and per tool. Approving a tool in one chat buffer doesn't approve it anywhere else, and approving it once means you're asked again next time.

When asked, you choose from:

KeymapChoiceDescription
g1Always acceptRun this tool without asking again in this chat buffer
g2AcceptRun this tool this one time
g3RejectDon't run the tool, and give the LLM a reason
g4CancelCancel this tool and every pending tool

Tools with require_cmd_approval = true, such as run_command and delete_file, are approved per command rather than per tool. If you always accept make format, you're still asked before make test.

Press gtx to reset the approvals for the chat buffer.

Approval Modes ​

Press gty in the chat buffer to choose how tools are approved:

ModeDescription
AskApprove each tool before it runs
AutoTools run without asking, apart from protected tools and commands that aren't on your safe list
YOLOEverything runs without asking

Every chat buffer starts in Ask. To start in a different mode:

lua
require("codecompanion").setup({
  interactions = {
    chat = {
      tools = {
        opts = {
          approval_mode = "auto", -- Can be "ask", "auto" or "yolo"
        },
      },
    },
  },
})

Resetting the approvals with gtx returns the chat buffer to this mode.

In Auto mode, a protected tool always asks first. delete_file is protected by default:

lua
require("codecompanion").setup({
  interactions = {
    chat = {
      tools = {
        ["delete_file"] = {
          opts = {
            protect = true,
          },
        },
      },
    },
  },
})

In Auto mode, run_command asks first unless the command is on its safe list:

lua
require("codecompanion").setup({
  interactions = {
    chat = {
      tools = {
        ["run_command"] = {
          opts = {
            safe_commands = { "git status", "git diff", "make test" },
          },
        },
      },
    },
  },
})

A command is safe if it starts with an entry on the list, so git status also covers git status --short. A command that chains, nests or redirects, with ;, &, |, >, <, $(, a backtick or a new line, is never treated as safe.

IMPORTANT

An entry covers every flag the command accepts. Only add commands whose flags can't write files or run other programs: git diff --output=notes.txt writes a file and rg --pre runs one

If you've enabled the LLM judge, it decides on commands that aren't on the safe list instead of asking you.

A prompt library item can start its chat buffer in a given mode with opts.approval_mode = "auto".

Approval modes also apply to ACP agents. In Auto mode, reads, searches, edits and fetches are approved, and everything else asks. Any shell command is checked against the run_command safe list, even when the agent labels it as a read or a search.

WARNING

YOLO mode runs every tool, including protected ones, without asking. Only use it where you can recover from lost data, as you're responsible for any damage it causes

Compatibility ​

Tool use by adapter:

AdapterSupportedNotes
Anthropic✅Dependent on the model
Azure OpenAI✅Dependent on the model
Copilot✅Dependent on the model
DeepSeek✅Dependent on the model
Gemini✅Dependent on the model
Gemini (Legacy)✅Dependent on the model
Hugging Face✅Dependent on the model
Kimi✅Dependent on the model
Mistral✅Dependent on the model
Novita✅Dependent on the model
Ollama✅Dependent on the model. Tested with Qwen3
OpenAI✅Dependent on the model
OpenAI (Legacy)✅Dependent on the model
OpenRouter✅Dependent on the model
xAI❌Not supported yet

Released under the Apache-2.0 License.

Sponsor
SponsoredKunjungi sekarang
Promo