OpenCode
Open-source агентный CLI через AITUNNEL: тот же OpenCode, ключ в рублях, VPN не нужен.
OpenCode — open-source агентный CLI для терминала (есть и десктопное приложение). AITUNNEL подключается как custom provider по OpenAI Chat Completions: один ключ, модели из каталога.
Страница описывает OpenCode 2 — текущую версию (проверено на 2.2.2). Конфиг и команды версии 1.x отличаются — см. OpenCode 1.x и переход на 2.
Зачем через AITUNNEL
- Из России без VPN. Запросы идут на
api.aitunnel.ru. Зарубежный аккаунт не нужен. - Оплата в рублях, бюджет на ключе, расход в панели.
- Любая модель из каталога. Claude, GPT, Gemini, Kimi, GLM, Qwen, DeepSeek — id как на странице моделей.
- Кеш Claude без пресета. OpenCode 2 сам ставит
cache_control— вход повторяющегося префикса читается со скидкой (подробнее). - Запасные модели и провайдер. Если апстрим не ответил — fallback и выбор провайдера.
Какая у вас версия
opencode --version
# opencode v2.2.2v2.x— всё ниже работает как написано.1.x— старая ветка. Обновление:opencode upgrade --major(в TUI —/update) или установка из раздела ниже. Конфиг 1.x читается и в 2.x, но с оговорками — раздел про переход.
Быстрый старт
Установка
Ставьте именно версию 2 — команды ниже. Привычные
curl … opencode.ai/install,npm i -g opencode-aiиscoop install opencodeставят 1.x.curl -fsSL https://opencode.ai/v2/install | bashWindows. Пакетные менеджеры для 2.x не поддерживаются: скачайте архив CLI (
opencode-windows-x64.zipна opencode.ai/v2/docs), распакуйте и добавьте папку сopencode.exeвPATH. Либо используйте десктопное приложение или WSL с установщиком выше.Проверкаopencode --version # opencode v2.2.2Конфиг opencode.jsonc
Сначала опишите провайдера — ключ подключается к нему на следующем шаге. Глобально:
~/.config/opencode/opencode.jsonc(Windows:%USERPROFILE%\.config\opencode\opencode.jsonc). Илиopencode.jsoncв корне проекта. Подойдёт и.json.opencode.jsonc{ "$schema": "https://opencode.ai/config.json", "providers": { "aitunnel": { "name": "AITUNNEL", "env": ["AITUNNEL_API_KEY"], "package": "@opencode/ai/providers/openai-compatible", "settings": { "baseURL": "https://api.aitunnel.ru/v1" }, "models": { "claude-sonnet-4.6": { "name": "Claude Sonnet 4.6", "limit": { "context": 1000000, "output": 128000 }, "capabilities": { "tools": true, "input": ["text", "image", "pdf"], "output": ["text"], "reasoning": { "supported": true, "effort": ["low", "medium", "high"] } }, "compatibility": { "cacheFormat": "anthropic" } }, "gpt-6-astra": { "name": "GPT-6 Astra", "limit": { "context": 1050000, "output": 128000 }, "capabilities": { "tools": true, "input": ["text", "image"], "output": ["text"], "reasoning": { "supported": true, "effort": ["low", "medium", "high"] } } }, "gemini-3.7-flash": { "name": "Gemini 3.7 Flash", "limit": { "context": 1048576, "output": 65535 }, "capabilities": { "tools": true, "input": ["text", "image", "pdf"], "output": ["text"] } } } } }, "model": "aitunnel/claude-sonnet-4.6", "agents": { "title": { "model": "aitunnel/gemini-3.7-flash" } } }Поле Смысл providers.aitunnelId провайдера — часть ссылки на модель: aitunnel/claude-sonnet-4.6envПеременные окружения, из которых берётся ключ. Без этого поля провайдер не получит ключ из окружения package@opencode/ai/providers/openai-compatible—/v1/chat/completions. Для/v1/responses— отдельный пакетsettings.baseURLhttps://api.aitunnel.ru/v1(с/v1, без слеша в конце)modelsКлюч — id из каталога, name— подпись в UIlimitОкно контекста и максимум ответа. Без него OpenCode считает 200 000 и 32 000 capabilitiesЧто умеет модель: tools,input(text,image,pdf),reasoningcompatibility.cacheFormatanthropic— OpenCode ставитcache_controlдля Claude (кеш)modelМодель по умолчанию: providerID/modelIDagents.title.modelДешёвая модель для заголовков сессий (прежний small_model)Модели добавляйте по тому же образцу. Готовые блоки — в разделах рекомендуемые модели и рассуждения.
Ключ AITUNNEL
Создайте ключ в панели ключей — он начинается с
sk-aitunnel-.Самый надёжный способ — сохранить ключ в OpenCode. Он работает при любом способе запуска (терминал, десктоп, IDE) и не зависит от переменных окружения:
Терминалopencode auth login aitunnelВыберите Manually enter API Key и вставьте ключ. То же самое в TUI —
/connect→ AITUNNEL. Если провайдера в списке нет, он не описан вopencode.jsonc(шаг 2).Проверкаopencode auth list # AITUNNEL AITUNNEL storedЗапуск
Терминалcd /path/to/your/project opencodeВ TUI —
/models, выберите модель AITUNNEL. Запросы появятся в панели. Быстрая проверка без TUI:Проверкаopencode run "Ответь одним словом: OK"
Ключ и переменные окружения
OpenCode 2 устроен как клиент и сервер. Модели вызывает не окно терминала, а общий фоновый сервис: он стартует при первом запуске opencode и дальше живёт. Переменные окружения (env, {env:…}) читает сервис — из окружения того процесса, который его запустил.
Отсюда частая проблема. Вы сделали export AITUNNEL_API_KEY=… в новом окне терминала, но сервис уже работает (его запустили раньше — другим opencode, десктопом, IDE). Он ключа не видит, запрос уходит с пустым Authorization, и API отвечает 401:
Вы не указали токен в заголовке запроса (Authorization: Bearer sk-aitunnel-xxx). Токен должен быть создан в нашем сервисе aitunnel.ru
Способы подключить ключ — от надёжного к менее:
- Сохранить в OpenCode —
opencode auth login aitunnelили/connect. Работает всегда, ничего перезапускать не нужно. - Положить ключ в окружение сервиса. Сервис перезапустится сам:
opencode service set env AITUNNEL_API_KEY "sk-aitunnel-xxx"
opencode auth list
# AITUNNEL AITUNNEL_API_KEY environment- Перезапустить сервис из окна с переменной. Новый сервис унаследует окружение:
# macOS, Linux
export AITUNNEL_API_KEY="sk-aitunnel-xxx"
opencode service restart# Windows PowerShell
$env:AITUNNEL_API_KEY = "sk-aitunnel-xxx"
opencode service restart- Ключ в конфиге через подстановку (сам ключ в JSON не пишите):
{
"providers": {
"aitunnel": {
"settings": {
"apiKey": "{env:AITUNNEL_API_KEY}"
}
}
}
}{
"providers": {
"aitunnel": {
"settings": {
"apiKey": "{file:~/.secrets/aitunnel-key}"
}
}
}
}~/.secrets/aitunnel-key — одна строка, без перевода строки. Если переменной или файла нет, OpenCode молча подставит пустую строку — получится тот же 401.
- Разовый запуск без общего сервиса —
opencode --standalone: приватный сервер берёт окружение вашего процесса. Так удобно в CI.
Проверка: opencode auth list должен показать строку AITUNNEL — stored (сохранённый ключ) или environment (из окружения сервиса). Пусто — ключ не дошёл.
Кеш Claude
Claude кеш сам не включает: без маркера cache_control каждый шаг агента оплачивает вход целиком. OpenCode 2 умеет ставить маркеры сам — достаточно объявить формат на модели:
{
"providers": {
"aitunnel": {
"models": {
"claude-sonnet-4.6": {
"compatibility": { "cacheFormat": "anthropic" }
}
}
}
}
}OpenCode метит системные блоки, последнее сообщение и последнее описание инструмента (cache_control: { "type": "ephemeral" }, пять минут) — до четырёх точек на запрос, как допускает API. Проверено на реальном API: первый запрос записал 6200 токенов в кеш, второй их прочитал. Результат — в панели и в usage.cached_tokens.
Нужен кеш на час? Создайте пресет с «Кеширование промптов» и укажите имя пресета в поле модели. Подробнее — кеширование промпта.
У моделей, которые кешируют сами (GPT, Gemini, DeepSeek), cacheFormat не нужен.
Рассуждения
AITUNNEL отдаёт цепочку мыслей в формате OpenRouter: reasoning строкой и reasoning_details массивом (подробнее). OpenCode 2 читает эти поля сам и возвращает их модели на следующем шаге — вместе с подписью, которая нужна Claude при вызове инструментов. Менять пакет не нужно.
Старое "reasoning": true в 2.x игнорируется (в логе omitted unsupported legacy setting). Рассуждения объявляются через capabilities.reasoning. Список effort превращается в варианты модели:
{
"providers": {
"aitunnel": {
"models": {
"glm-5.3-flash": {
"name": "GLM 5.3 Flash",
"limit": { "context": 1048576, "output": 131072 },
"capabilities": {
"tools": true,
"input": ["text", "image"],
"output": ["text"],
"reasoning": { "supported": true, "effort": ["low", "high", "max"] }
}
}
}
}
}
}# усилие выбирается через #вариант
opencode run -m aitunnel/glm-5.3-flash#max "Найди гонку в src/queue.ts"Вариант выбирается в /models, через -m модель#вариант или в агенте. Корневой model вариант не хранит — для постоянного усилия задайте его агенту:
{
"agents": {
"build": {
"model": "aitunnel/claude-sonnet-4.6#high"
}
}
}OpenCode отправляет reasoning_effort, API превращает его в reasoning.effort. Мысли в консоли opencode run показывает флаг --thinking.
Картинки и PDF
Модель принимает то, что указано в capabilities.input. Если поле не задано, OpenCode 2 считает модель мультимодальной (текст и изображения) — и отправит картинку текстовой модели. Задавайте input честно:
{
"providers": {
"aitunnel": {
"models": {
"kimi-k2.7-code": {
"name": "Kimi K2.7 Code",
"capabilities": {
"tools": true,
"input": ["text"],
"output": ["text"]
}
}
}
}
}
}Для модели без image вместо картинки уходит короткая заметка. Видны модели: PNG, JPEG, GIF, WebP и PDF (нужна модель с pdf). SVG читается как текст, а AVIF, BMP, аудио и видео в запрос не попадают — конвертируйте в PNG. В десктопе и вебе: Attach file, вставка или перетаскивание. В консоли:
opencode run -f ./diagram.png "Что изображено на схеме?"Лимит вложения — 20 МиБ. OpenCode ужимает картинки до 2000×2000 и 5 МБ в base64 (media.image в конфиге: auto_resize, max_width, max_height, max_base64_bytes). Мультимодальные модели видны в каталоге.
Responses API
По умолчанию OpenCode ходит в /v1/chat/completions. Для /v1/responses переопределите пакет на модели:
{
"providers": {
"aitunnel": {
"models": {
"gpt-6-astra": {
"package": "@opencode/ai/providers/openai-compatible/responses"
}
}
}
}
}Заголовки сессий
OpenCode просит у модели короткие заголовки сессий. Ставьте на это быструю дешёвую модель — это заметно, если основная Opus или GPT Pro: agents.title.model = aitunnel/gemini-3.7-flash. Прежний "small_model" из 1.x тоже продолжает работать.
Конфиги и приоритет
OpenCode сливает конфиги, ближайший к проекту перекрывает дальний:
~/.config/opencode/opencode.jsonc— глобальный;opencode.jsoncв родительских папках и в корне проекта;.opencode/opencode.jsonc— перекрывает всеopencode.jsoncвыше;- системный (
/Library/Application Support/opencode,/etc/opencode,%ProgramData%\opencode) — перекрывает всё.
Держите провайдера AITUNNEL в глобальном файле, а в проекте переопределяйте только model. Конфиг перечитывается сам, перезапуск обычно не нужен; принудительно — opencode reload.
AGENTS.md
OpenCode читает AGENTS.md в корне проекта как системные инструкции. Есть и глобальный ~/.config/opencode/AGENTS.md. Файл CLAUDE.md версия 2 больше не подхватывает — перенесите правила в AGENTS.md.
# AITUNNEL API CF
## Стек
- Cloudflare Workers + Hono
- TypeScript, деплой через Wrangler
## Правила
- Все обращения к провайдерам идут через единый failover-слой
- Писать тесты для новых route handlers
- Не коммитить секреты и `.dev.vars`Рекомендуемые модели
Id — как в каталоге, без префикса провайдера.
claude-sonnet-4.6— баланс качества и tool calling, кеш черезcacheFormatgpt-6-astra— флагман OpenAI для кода и агентовkimi-k2.7-code— дешевле Claude и GPT, сильна в tool use (текстовая модель)glm-5.3-flash— рассуждения обязательны, вариантыlow,high,maxqwen3-coder-next— open-source, хорошая агентностьgemini-3.7-flash— быстрая и дешёвая, удобна для заголовков сессий
Команды
В TUI: /connect — ключ, /models — выбор модели и варианта.
В терминале:
| Команда | Что делает |
|---|---|
opencode run "промпт" | Один прогон без TUI. Флаги: -m провайдер/модель#вариант, -f файл, --thinking, --auto, --format json |
opencode auth login aitunnel / list / logout | Ключи и подключения |
opencode models | Список моделей, которые видит OpenCode |
opencode service status / restart / set env | Фоновый сервис |
opencode reload | Перечитать конфиг |
opencode --standalone | Приватный сервер вместо общего |
opencode upgrade | Обновление |
Headless для CI:
export AITUNNEL_API_KEY="sk-aitunnel-xxx"
opencode run --standalone --auto "Напиши unit-тесты для src/utils.ts и положи их в src/utils.test.ts"--standalone берёт окружение runner'а, --auto разрешает действия, не запрещённые правилами.
Права доступа
В отличие от 1.x, OpenCode 2 не спрашивает перед чтением и записью вне папки проекта (external_directory разрешён по умолчанию). Чтобы вернуть вопрос, добавьте правило:
{
"permissions": [
{ "action": "external_directory", "resource": "*", "effect": "ask" }
]
}OpenCode 1.x и переход на 2
Ветка 1.x (npm i -g opencode-ai, 1.19.x) использует другой формат: provider, npm, options.
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"aitunnel": {
"npm": "@openrouter/ai-sdk-provider",
"name": "AITUNNEL",
"options": {
"baseURL": "https://api.aitunnel.ru/v1"
},
"models": {
"claude-sonnet-4.6": {
"name": "Claude Sonnet 4.6",
"limit": { "context": 1000000, "output": 128000 }
}
}
}
},
"model": "aitunnel/claude-sonnet-4.6",
"small_model": "aitunnel/gemini-3.7-flash"
}В 1.x ключ добавляется через /connect → Other → id aitunnel и хранится в auth.json; рассуждения включает "reasoning": true, картинки — modalities и attachment; пакет @openrouter/ai-sdk-provider встроен в OpenCode.
Что происходит при обновлении до 2.x:
- Старый конфиг читается без правок: провайдер и модели видны, запросы уходят. Файл OpenCode не переписывает.
reasoning,attachment, булевinterleavedигнорируются. Мысли и варианты усилия пропадают, пока не добавитеcapabilities.reasoning.modalitiesпереходит вcapabilities.inputиcapabilities.output— это поле продолжает работать.- Ключи из
auth.jsonимпортируются в базу OpenCode. Шага «Other» в 2.x нет: провайдера описывают в конфиге, затем/connectс его id. - Переменные окружения нужны сервису, а не терминалу.
- Плагины 1.x не запускаются — их нужно переписать.
- Todo по умолчанию выключен (
experimental.todo), LSP не работает, настройки TUI переехали в~/.config/opencode/cli.json.
Конвертировать конфиг можно самим OpenCode: «Migrate my OpenCode configuration from the V1 format to the native V2 format». Держите копию файла: 1.x не понимает нативный формат 2.x.
Устранение неполадок
Начните с диагностики:
opencode --version
opencode service status
opencode auth list
opencode models --standalone --print-logs- 401: «Вы не указали токен в заголовке запроса». Ключ не дошёл до фонового сервиса.
opencode auth listпуст или без строки AITUNNEL. Выполнитеopencode auth login aitunnelили другие способы. В десктопе переменные из оболочки не видны. - 401 при ключе, который есть в auth list. Ключ неверный или отозван: проверьте его в панели ключей, и что баланс положительный.
auth logoutи сноваauth login. - Провайдера нет в
/models. Он не описан вopencode.jsonc(ключproviders, во множественном числе) или файл отброшен целиком. Запуститеopencode models --standalone --print-logs— ищитеWARN … rejected malformed JSON or JSONC documentиomitted unsupported legacy setting. Проверьте, что запускаете из нужной папки: провайдер из конфига другого проекта сюда не переносится. - «rejected malformed JSON or JSONC document». Файл в UTF-16: так сохраняют Блокнот и Windows PowerShell 5 (
>,Out-File). Пересохраните в UTF-8 (в VS Code — «UTF-8» справа внизу). UTF-8 с BOM версия 2 принимает. - Model unavailable: aitunnel/… Ключ в
modelsне совпадает с id в запросе или модель выключена (disabled). Для алиаса смотрите ключ, а неmodelID. - Model not found / 404. Id как в каталоге:
claude-sonnet-4.6, неanthropic/claude-sonnet-4.6.nameна запрос не влияет. - Сообщение
> build · модельповторяется без ответа. OpenCode молча повторяет запрос к недоступномуbaseURL. Проверьте адресhttps://api.aitunnel.ru/v1и сеть; логи —~/.local/share/opencode/log/opencode.log. - Нет мыслей. Объявите
capabilities.reasoning(староеreasoning: trueне работает) и запускайтеopencode runс--thinking. - Модель «не видит» картинку. В ответе заметка о неподдерживаемом вводе: добавьте
imageвcapabilities.input. Формат AVIF, BMP, видео и аудио в запрос не попадают. - Кеш не работает. Проверьте
compatibility.cacheFormat: "anthropic"на модели Claude. Читать кеш будут только повторные запросы в течение пяти минут. - Лимит контекста. Поднимите
limit.context— без него считается 200 000. Для больших репозиториев нужны модели с окном от 128k. - Ничего не помогает.
opencode service restartперезапустит сервис, а выводopencode service statusи логи пригодятся при обращении в поддержку.
Безопасность
- Сохранённый ключ лежит в локальной базе OpenCode (
~/.local/share/opencode/opencode.db), значение изopencode service set env— в локальной конфигурации сервиса. Не копируйте и не публикуйте эти файлы. - Не коммитьте
opencode.jsoncс прописанным ключом:{env:AITUNNEL_API_KEY}или{file:~/.secrets/…}. - В CI передавайте ключ только через переменные окружения runner'а.
- AITUNNEL не логирует исходный код промптов.