# Вайб-кодинг в Neovim: настройка CodeCompanion.nvim через RouterAI (Claude, Qwen, DeepSeek)

**[CodeCompanion.nvim](https://github.com/olimorris/codecompanion.nvim)** — AI-плагин для Neovim (Apache-2.0, около 6,9 тыс. звёзд на GitHub): чат прямо в буфере, inline-правки с diff, командный режим и агент с инструментами (tools) для чтения и правки файлов. В этой статье мы подключим его к **[RouterAI](/)** через адаптер `openai_compatible`: один ключ для Claude, Qwen, DeepSeek и GLM, работа из России без VPN и оплата в рублях.

Статья написана для версии плагина v20.0.1 (октябрь 2026) и Neovim 0.12.6.

## Требования {#trebovaniya}

* Neovim 0.12 или новее (так сказано в [документации установки](https://codecompanion.olimorris.dev/installation));
* `curl` в системе;
* плагины [plenary.nvim](https://github.com/nvim-lua/plenary.nvim) и [nvim-treesitter](https://github.com/nvim-treesitter/nvim-treesitter) (последний нужен для `yaml`-парсера — разбора markdown-промптов и skills);
* менеджер плагинов, в примерах — [lazy.nvim](https://github.com/folke/lazy.nvim);
* ключ RouterAI: зарегистрируйтесь на [routerai.ru](/), пополните баланс и создайте ключ в разделе **«Ключи API»**. Ключ показывают один раз, скопируйте его сразу.

## Установка {#ustanovka}

Добавьте плагин в конфигурацию lazy.nvim. Документация рекомендует закрепить версию, чтобы обновления не ломали конфиг:

```lua
{
  "olimorris/codecompanion.nvim",
  version = "^20.0.0",
  opts = {},
  dependencies = {
    "nvim-lua/plenary.nvim",
    "nvim-treesitter/nvim-treesitter",
  },
},
```

Перезапустите Neovim, выполните `:Lazy sync` и проверьте зависимости командой `:checkhealth codecompanion`.

![Результат :checkhealth codecompanion: версия Neovim 0.12.6, plenary.nvim и curl найдены, предупреждения по необязательным yaml parser, markitdown и sqlite3](https://b51bc417-3ee0-451a-a83b-8a681d027a96.selstorage.ru/public/4f6ad52aad7a95df80cbdaa16717bdab.png)

Предупреждения (WARNING) о `yaml parser`, `markitdown` и `sqlite3` относятся к необязательным зависимостям: они нужны для markdown-промптов, загрузки веб-страниц и токенов Copilot и на работу с RouterAI не влияют.

## Подключение к RouterAI {#podklyuchenie}

В CodeCompanion HTTP-адаптеры лежат в `adapters.http`. Для любого OpenAI-совместимого сервиса расширяют `openai_compatible` под собственным именем.

### Шаг 1. Ключ в переменной окружения

Не храните ключ в конфиге: адаптер читает его из переменной окружения при каждом запросе.

```bash
export ROUTERAI_API_KEY="sk-xxxxxxxxxxxxxxxx"
```

Добавьте строку в `~/.bashrc` или `~/.zshrc` и запускайте Neovim из этого же окружения.

### Шаг 2. Адаптер `routerai`

Создайте файл `~/.config/nvim/lua/plugins/codecompanion.lua`:

```lua
return {
  "olimorris/codecompanion.nvim",
  version = "^20.0.0",
  dependencies = {
    "nvim-lua/plenary.nvim",
    "nvim-treesitter/nvim-treesitter",
  },
  opts = {
    adapters = {
      http = {
        routerai = function()
          return require("codecompanion.adapters").extend("openai_compatible", {
            formatted_name = "RouterAI",
            env = {
              url = "https://routerai.ru/api",
              api_key = "ROUTERAI_API_KEY",
            },
            schema = {
              model = {
                default = "anthropic/claude-sonnet-5.5",
              },
            },
          })
        end,
      },
    },
    interactions = {
      chat = { adapter = "routerai" },
      inline = { adapter = "routerai" },
      cmd = { adapter = "routerai" },
    },
  },
}
```

![Конфиг адаптера routerai для CodeCompanion в Neovim: url, api_key как имя переменной окружения и модель по умолчанию](https://b51bc417-3ee0-451a-a83b-8a681d027a96.selstorage.ru/public/a64fc648b27dd314a1a14b859d493ddf.png)

Что здесь важно:

| Поле | Значение | Пояснение |
|---|---|---|
| `formatted_name` | `RouterAI` | Название в заголовке чата и в списке адаптеров |
| `env.url` | `https://routerai.ru/api` | **Без `/v1`** — см. ниже |
| `env.api_key` | `ROUTERAI_API_KEY` | Имя переменной окружения, а не сам ключ |
| `schema.model.default` | `anthropic/claude-sonnet-5.5` | Модель по умолчанию, id из [каталога](/models) |
| `interactions.*.adapter` | `routerai` | Чат, inline и `cmd` используют этот адаптер |

**Почему `url` без `/v1`.** Адаптер собирает адрес как `url` + `chat_url`, а `chat_url` по умолчанию равен `/v1/chat/completions`. Мы проверили: с `url = "https://routerai.ru/api"` запросы уходят на `https://routerai.ru/api/v1/chat/completions` и `https://routerai.ru/api/v1/models`. Если указать `https://routerai.ru/api/v1`, получится `/api/v1/v1/chat/completions` и ответ 404. В других инструментах Base URL RouterAI — `https://routerai.ru/api/v1`, но здесь `/v1` добавляет сам адаптер.

Если не задать `api_key`, адаптер отправит значение `OPENAI_API_KEY` — ваш ключ OpenAI уйдёт не туда. Всегда задавайте `api_key` явно.

## Команды и режимы {#komandy}

Ни одна команда по умолчанию не привязана к клавишам; список — в [справочнике команд](https://codecompanion.olimorris.dev/commands).

| Команда | Что делает |
|---|---|
| `:CodeCompanionChat` | Открывает чат-буфер |
| `:CodeCompanionChat Toggle` | Показывает или скрывает последний чат |
| `:CodeCompanionChat adapter=routerai model=qwen/qwen3-coder` | Чат с конкретным адаптером и моделью |
| `:CodeCompanion <запрос>` | Inline-правка текущего буфера или выделения |
| `:CodeCompanionCmd <запрос>` | Генерирует команду для командной строки Neovim |
| `:CodeCompanionActions` | Палитра действий и библиотека промптов |

Режимы (interactions) настраиваются отдельно: `chat`, `inline` и `cmd`. Так можно отдать чат мощной модели, а `cmd` — быстрой:

```lua
interactions = {
  chat = { adapter = { name = "routerai", model = "anthropic/claude-sonnet-5.5" } },
  inline = { adapter = { name = "routerai", model = "qwen/qwen3-coder" } },
  cmd = { adapter = { name = "routerai", model = "z-ai/glm-5.3-flash" } },
},
```

### Чат {#chat}

Откройте файл и выполните `:CodeCompanionChat`. Сообщение отправляется по `<C-s>` в режиме вставки или `<CR>` в нормальном режиме. Чтобы модель увидела код, добавьте контекст `#{buffer}` — без него модель отвечает только по тексту сообщения (в нашей проверке на вопрос «какие функции экспортирует этот файл?» без `#{buffer}` модель попросила прислать код):

```md
Какие функции экспортирует #{buffer:invoices.js}? Ответь коротко, списком.
```

![Окно чата CodeCompanion с адаптером RouterAI: слева вопрос с #{buffer:invoices.js} и один ответ модели со списком функций allInvoices и totalAmount, справа файл invoices.js](https://b51bc417-3ee0-451a-a83b-8a681d027a96.selstorage.ru/public/7779580bf46041bee973bf12e237d228.png)

### Inline {#inline}

Выделите код и выполните:

```
:'<,'>CodeCompanion Добавь JSDoc к totalAmount
```

Модель правит выделение, а изменения показываются как diff по блокам (hunk): `ga` принимает блок, `gr` отклоняет, `g2` принимает все оставшиеся, `g3` отклоняет все оставшиеся. Список клавиш открывается по `?` в diff. Для inline модель обязана поддерживать tool calling — именно через него она правит буфер.

![Inline-правка CodeCompanion в invoices.js: выделена функция totalAmount, модель добавила JSDoc, изменение показано зелёным блоком diff с пометкой Hunk 1/1](https://b51bc417-3ee0-451a-a83b-8a681d027a96.selstorage.ru/public/6487f676f46cc5aa97c8ba3f35f73f19.png)

## Агентный режим и подтверждения {#agent}

Чтобы модель могла читать и менять файлы, добавьте в сообщение инструменты: `@{files}` даёт чтение, создание и правку файлов, `@{agent}` — полный набор, включая запуск команд:

```md
@{files} Добавь docstring к каждой функции в #{buffer}
```

По умолчанию каждый чат стартует в режиме **Ask** (описано в [руководстве по подтверждениям](https://codecompanion.olimorris.dev/guides/tool-approvals)):

| Инструмент | До выполнения | После выполнения |
|---|---|---|
| `read_file`, `grep_search` | Спрашивает | — |
| `run_command` | Спрашивает для каждой команды | — |
| `delete_file` | Спрашивает для каждого файла | — |
| `create_file`, `edit_file` | Выполняется | Просит подтвердить изменение (diff) |

Ответы на запрос: `g1` — всегда разрешать в этом чате, `g2` — разрешить один раз, `g3` — отклонить с причиной, `g4` — отменить всё. Режим чата меняется клавишей `gty`: **Ask**, **Auto** (всё, кроме `run_command` и защищённых инструментов вроде `delete_file`) и **YOLO** (всё без вопросов). Режим Auto пишет правки сразу на диск, поэтому проверяйте результат командой `:CodeCompanionCodeReview` и держите проект под git.

Режим по умолчанию меняется так:

```lua
interactions = {
  chat = {
    tools = { opts = { approval_mode = "ask" } }, -- "ask", "auto" или "yolo"
  },
},
```

## Выбор модели {#vybor-modeli}

Идентификаторы сверены с [каталогом RouterAI](/models); все пять моделей отвечают через `/api/v1/chat/completions` и объявляют поддержку `tools`. Цены смотрите в каталоге — они зависят от модели и объёма контекста.

| Модель | Для чего |
|---|---|
| `anthropic/claude-sonnet-5.5` | Рефакторинг и сложные многофайловые правки, основной вариант |
| `anthropic/claude-haiku-5.5` | Быстрые ответы и мелкие правки |
| `qwen/qwen3-coder` | Генерация и правка кода, inline-запросы |
| `deepseek/deepseek-v4.1-flash-1017` | Дешёвые массовые задачи: тесты, комментарии, мелкие правки |
| `z-ai/glm-5.3-flash` | Недорогие быстрые запросы, например для `cmd` |

Модель в чате переключается клавишей `ga` (адаптер и модель), а при пустом `default` адаптер возьмёт первую модель из `/v1/models`. Чтобы список был коротким и не зависел от каталога, задайте его вручную:

```lua
schema = {
  model = {
    default = "anthropic/claude-sonnet-5.5",
    choices = {
      "anthropic/claude-sonnet-5.5",
      "qwen/qwen3-coder",
      "deepseek/deepseek-v4.1-flash-1017",
      "z-ai/glm-5.3-flash",
    },
  },
},
```

## Проверка подключения {#proverka}

1. Запустите `nvim` в каталоге проекта из того же терминала, где задан `ROUTERAI_API_KEY`.
2. Выполните `:CodeCompanionChat` — в заголовке ответа должно быть **CodeCompanion (RouterAI)**.
3. Отправьте `Привет! Какая ты модель? #{buffer}` по `<C-s>`.
4. Через несколько секунд придёт ответ. Если его нет, откройте `:checkhealth codecompanion` и лог (`stdpath("log")`, файл `codecompanion.log`).

## Решение проблем {#problemy}

* **404 на запросе.** В `env.url` стоит `https://routerai.ru/api/v1`. Уберите `/v1`: адаптер добавляет его сам.
* **Ответ не приходит.** Возможно, Neovim не видит переменную `ROUTERAI_API_KEY` (например, запущен из GUI-ярлыка). Проверьте `:lua print(vim.env.ROUTERAI_API_KEY ~= nil)` (должно вывести `true`; сам ключ не печатается) и запускайте Neovim из терминала с экспортированной переменной.
* **Модель «не видит» файл.** Добавьте `#{buffer}` или `#{buffer:имя_файла}`; для правок — `@{files}`.
* **Inline не вносит правки.** Модель должна поддерживать tool calling. Выберите одну из моделей из таблицы выше.
* **В списке моделей не те варианты или адаптер ждёт `/v1/models` слишком долго.** Задайте `schema.model.choices` вручную. Если определены два адаптера на `openai_compatible`, у каждого задайте `default` и `choices`: кэш моделей у них общий.
* **Нужен подробный лог.** Включите `opts = { log_level = "DEBUG" }` в `setup()`, повторите запрос и посмотрите `codecompanion.log`; после отладки верните `ERROR`.

## Чем отличается от Avante {#otlichiya}

CodeCompanion шире по режимам: чат, inline, `cmd`, агент с инструментами и подтверждениями, библиотека промптов и подключение ACP-агентов. Цена — ручная конфигурация на Lua: адаптер, модели и подтверждения вы задаёте сами. Если нужен другой подход к AI в Neovim, посмотрите [гайд по Avante](/pages/vibe-coding-neovim-avante).

## Что дальше {#dalshe}

* [Каталог моделей RouterAI](/models) — актуальные id и контекст;
* [Вайб-кодинг в Neovim с Avante](/pages/vibe-coding-neovim-avante) — альтернативный плагин;
* [Вайб-кодинг в Zed](/pages/vibe-coding-zed-dev) — другой редактор с нативным AI;
* [Что такое вайб-кодинг](/pages/vibe-coding);
* [Документация CodeCompanion](https://codecompanion.olimorris.dev/) — rules, skills, MCP и prompt library.
