Skip to content

Coding with an Agent ​

An agent such as Claude Code or Codex brings its own tools, permissions and slash commands, but normally lives in a separate terminal. CodeCompanion runs the agent over the Agent Client Protocol (ACP), so the conversation, its permission requests and its edits all happen in a chat buffer. This guide uses Claude Code throughout. The steps are the same for any other agent once it's installed.

Installing Claude Code ​

  1. Install Claude Code
  2. Install claude-agent-acp, which lets CodeCompanion talk to Claude Code:
npm install -g @zed-industries/claude-agent-acp
  1. Authenticate with your Claude subscription or an API key:
lua
-- Run `claude setup-token` in your terminal to get the token
require("codecompanion").setup({
  adapters = {
    acp = {
      extend = {
        claude_code = {
          env = {
            CLAUDE_CODE_OAUTH_TOKEN = "cmd:op read op://personal/Claude/token --no-newline",
          },
        },
      },
    },
  },
})
lua
require("codecompanion").setup({
  adapters = {
    acp = {
      extend = {
        claude_code = {
          env = {
            ANTHROPIC_API_KEY = "cmd:op read op://personal/Anthropic/credential --no-newline",
          },
        },
      },
    },
  },
})

If CLAUDE_CODE_OAUTH_TOKEN is already exported in your shell, you can skip step 3. See Setup: Claude Code for screenshots of the token flow, and environment variables for other ways to supply a secret.

For other agents, follow their setup section instead: Codex, Gemini CLI, OpenCode, Copilot CLI and others.

Making It the Chat Adapter ​

To use Claude Code for every chat:

lua
require("codecompanion").setup({
  interactions = {
    chat = {
      adapter = "claude_code", -- Or "codex", "gemini_cli", "opencode", "copilot_acp"...
    },
  },
})

To try it without changing your config, run:

:CodeCompanionChat adapter=claude_code

The agent takes a few seconds to start. Once it's connected, you talk to it like any other chat, and send with <C-s> or <CR>.

Choosing a Default Model and Mode ​

When a session starts, the agent tells CodeCompanion which session config options it has, such as the model, the mode and the reasoning level. Every chat starts on the agent's own defaults unless you set your own.

The model can be set alongside the adapter:

lua
require("codecompanion").setup({
  interactions = {
    chat = {
      adapter = {
        name = "claude_code",
        model = "opus",
      },
    },
  },
})

The mode, and every other option, goes in the adapter's defaults.session_config_options:

lua
require("codecompanion").setup({
  adapters = {
    acp = {
      extend = {
        claude_code = {
          defaults = {
            session_config_options = {
              model = "opus",
              mode = "acceptEdits",
            },
          },
        },
      },
    },
  },
  interactions = {
    chat = {
      adapter = "claude_code",
    },
  },
})

Each key is an option's category (model, mode, thought_level) and each value is matched against the agent's values or their display names, ignoring case. The model is always set first, as some agents change their other options depending on the model. If a value doesn't match, CodeCompanion logs a warning and the chat stays on the agent's default.

To see which options and values your agent offers, press gd in a chat buffer to open the debug window, or run /acp_session_options.

NOTE

If you set the model in both places, session_config_options takes precedence

Changing Model and Mode Mid-Chat ​

Keymap / CommandAction
gaChange adapter, then pick a model from the agent's list
/acp_session_optionsChange any session config option, such as the mode or reasoning level
/commandRestart the agent with a different command from the adapter's commands, such as Claude Code's yolo. This starts a new conversation with the agent

The current model and option values are marked with *.

Permissions ​

The agent decides when it needs your permission, and CodeCompanion shows the request in the chat buffer. Only the options the agent offers are listed:

KeymapAction
gvView the proposed edit in a floating diff
g1Always accept. The agent remembers this, not CodeCompanion
g2Accept this time
g3Reject
g4Cancel the request

A proposed edit of six lines or fewer is shown in the chat buffer. A larger one opens in a floating diff if the chat buffer is visible, where the same keymaps apply and } and { move between hunks. See Diff to change the threshold.

Claude Code permission request

Your chat's approval mode also applies to the agent. Press gty to choose one:

  • Ask - Every request is shown to you
  • Auto - Reads, searches, fetches, edits and safe shell commands are accepted for you. Everything else is shown to you
  • YOLO - Every request is accepted for you

A request accepted by a mode is only ever accepted once, so the agent doesn't keep the permission after you leave that mode. See Controlling Tool Approvals for what counts as a safe command.

Using the Agent's Slash Commands ​

The agent's own slash commands are triggered with \, which keeps them apart from CodeCompanion's / slash commands:

md
\compact

CodeCompanion changes \compact to /compact before sending it. Commands are discovered from the agent, so they appear in completion one to five seconds after the chat opens. Not every command the agent has in its terminal is available over ACP.

Sharing Context ​

Editor context and CodeCompanion's slash commands work as they do with any other adapter:

md
Why does #{buffer} fail on the errors in #{diagnostics}?

A buffer or file is shared as its path, and the agent reads it from disk, so save your changes first. Everything else, such as #{selection}, #{diagnostics} and #{terminal}, is sent as text. /image works with agents that accept images, which includes Claude Code.

Passing MCP Servers to the Agent ​

To give the agent the MCP servers you've configured for CodeCompanion, or a separate list of its own:

lua
require("codecompanion").setup({
  adapters = {
    acp = {
      extend = {
        claude_code = {
          defaults = {
            mcpServers = "inherit_from_config",
          },
        },
      },
    },
  },
  mcp = {
    servers = {
      ["sequential-thinking"] = {
        cmd = { "npx", "-y", "@modelcontextprotocol/server-sequential-thinking" },
      },
    },
    opts = {
      default_servers = { "sequential-thinking" },
    },
  },
})
lua
require("codecompanion").setup({
  adapters = {
    acp = {
      extend = {
        claude_code = {
          defaults = {
            mcpServers = {
              {
                name = "sequential-thinking",
                command = "npx",
                args = { "-y", "@modelcontextprotocol/server-sequential-thinking" },
                env = {},
              },
            },
          },
        },
      },
    },
  },
})

With inherit_from_config, only the servers in mcp.opts.default_servers are passed. The agent starts and runs them itself, so they don't appear in the chat buffer's context. See Configuring MCP Servers for more.

Reviewing the Agent's Work ​

Once the agent has finished, run:

:CodeCompanionCodeReview

This shows every change made since your first message, and lets you accept, revert or comment on each hunk. Send your comments back with #{code_review} in your next message. See Reviewing an Agent's Changes for the full workflow.

ACP or the CLI Interaction ​

:CodeCompanionCLI runs the agent's own terminal interface inside Neovim, rather than a chat buffer. See CLI to set it up.

ACPCLI
Where you talk to the agentA chat bufferThe agent's own interface, in a Neovim terminal
Permission requestsIn the chat buffer, with CodeCompanion's approval modesIn the agent's interface
Agent featuresOnly what the agent exposes over ACPEverything the agent has
Switching agent or modelga in the same chatStart another CLI interaction
Sharing contextEditor context and slash commands in the promptEditor context sent from any buffer with require("codecompanion").cli()

Choose ACP if you want to read, search and yank the conversation like any other buffer. Choose the CLI if you rely on a feature the agent doesn't expose over ACP, such as its plan view or a particular slash command.

Limitations ​

  • Agents only work in the chat buffer, not in the inline interaction or for background tasks
  • CodeCompanion's own tools, such as @{files} and @{agent}, aren't offered to an agent. It uses its own
  • CodeCompanion's system prompt isn't sent to the agent
  • CodeCompanion doesn't compact an agent's conversation. The agent manages its own context, and \compact asks it to
  • /save and /rename aren't available. The agent keeps its own sessions, which /resume lists in a new chat if the agent supports it
  • An agent's plan isn't shown in the chat buffer, and agents can't use a Neovim terminal. See ACP Support

Released under the Apache-2.0 License.