← claude-core
Recursos
▮ CLAUDE-CORE · ACADEMY CLAUDE CODE v2.1.143 CCROUTER · MODEL LAYER ▮

ROTEIE A CAMADA DE MODELO

Use a UX do Claude Code com qualquer modelo — sem perder o loop. Quatro módulos de teoria, oito configs de roteamento copy-paste. ~25 minutos.

Por que essa class existe

O Claude Code fala com um modelo por padrão — o da Anthropic. Mas o turn mais caro da sua sessão (um file walk, um resumo de output de grep, uma limpeza de comentários) não precisa de raciocínio nível Opus. O CCRouter senta entre o cliente do CC e qualquer provider, roteia cada request pro modelo que se encaixa no trabalho, e fica invisível pro agent loop. A assimetria de custo sozinha já paga o setup. A diversidade de modelos destrava workflows que o caminho single-vendor não alcança.

O que você vai aprender

Validado contra

Claude Code v2.1.143 · @musistudio/claude-code-router v1.0.x. O CCRouter é um projeto open-source de terceiros (26.4k stars em maio de 2026) e se move rápido — os shapes de config aqui foram validados contra os docs canônicos, mas confira os nomes dos campos contra a versão que você tem instalada antes de fazer copy-paste.

§1

Por que rotear?

fundamentos

TL;DR — três pressões te tiram do single-vendor: assimetria de custo (Opus pricing em trabalho rotineiro), diversidade de modelo (contexto longo do Gemini, raciocínio-por-dólar do DeepSeek, Ollama local pra privacidade) e vendor lock-off (mantém a UX do CC, escolhe o modelo). O CCRouter é a forma mais barata de atacar as três de uma vez.

▸ Assimetria de custo — a conta que ninguém faz

Uma sessão típica do Claude Code mistura uns poucos turns pesados de raciocínio com muitos turns baratos — leituras de arquivo, walks de diretório, resumos de output de tool. Tratar cada turn como classe Opus é pagar preço de Opus por trabalho classe Haiku. Medições de comunidade pra heavy users de CC caem rotineiramente na faixa de 50–99% de economia quando o tráfego rotineiro é desviado — o número exato depende do seu ratio read/write.

▸ Diversidade de modelo — capacidades que a Anthropic não entrega

  • Gemini 2.5 Pro — contexto de 2M tokens. Útil quando você precisa raciocinar sobre um monorepo inteiro, um log longo, ou um transcript gigante.
  • DeepSeek V3 / R1 — qualidade alta de raciocínio por uma fração do preço de Opus. Boa pra rotas "think".
  • Ollama (local) — roda offline, nunca manda bytes da sua máquina. A jogada de privacidade / indústria regulada.
  • Groq / SiliconFlow / Together — latência muito baixa pro caminho "default" quando responsividade importa mais que qualidade de topo.

▸ Vendor lock-off — mesma UX, qualquer modelo

O valor do CC é o loop, o permission model, o sistema de hooks, os slash commands — não o modelo. O CCRouter te deixa manter tudo isso enquanto você escolhe a camada de inferência por tarefa. A posição oficial é "Use o Claude Code como base pra infraestrutura de coding, te permitindo decidir como interage com o modelo enquanto aproveita os updates da Anthropic" — mesma UX, suas decisões de modelo.

▸ Quando NÃO instalar o CCRouter

Se sua sessão é pequena, seu gasto é <$20/mês, ou você nunca pensou nisso — não se incomoda. O CCRouter é superfície operacional; a hora certa pra adotar é quando sua conta de CC é grande o suficiente pra custo de setup < economia de um mês. Pra a maioria dos hobby users, a resposta é "não". Pra quem roda /goal headless em CI todas as noites, a resposta é "provavelmente sim".

Deep dive → /goal headless (o caso de uso canônico de gasto pesado)
Próximo → §2 · A arquitetura
§2

A arquitetura

internos

TL;DR — o CCRouter é um proxy local em 127.0.0.1:3456. Ele fala o shape da API da Anthropic do lado client e o shape da API de qualquer provider do lado server. O CC acha que tá falando com a Anthropic; o provider acha que tá falando com seu client nativo. Os transformers fazem a tradução.

▸ O caminho do request

Claude Code (com ANTHROPIC_BASE_URL=http://127.0.0.1:3456) │ ▼ CCRouter (proxy local, sua máquina) │ │ 1. parse do request no shape Anthropic │ 2. classifica rota: default | background | think | longContext | webSearch | image │ 3. consulta Router[route] → provider + modelo │ 4. aplica transformers (lado request) │ ▼ Provider (OpenRouter · DeepSeek · Ollama · Gemini · Groq · …) │ ▼ response CCRouter (transformers — lado response) │ ▼ Claude Code (vê response no shape Anthropic, nunca soube)

▸ O que o CCRouter vê

  • Todo POST /v1/messages que o CC faz — o prompt completo, system message, definições de tool.
  • Contagens de tokens (pra decisão do longContextThreshold).
  • Tool calls e seus argumentos — pros transformers que precisam reescrever shapes de tool por provider.

▸ O que o CCRouter NÃO vê

  • Seu filesystem. O CC lê arquivos; o CCRouter só vê o que o CC já serializou pro request.
  • Hooks. Eles rodam dentro do processo do CC, antes/depois da fronteira de request que o CCRouter intercepta.
  • Sua API key da Anthropic — quando rota pra um provider não-Anthropic, a chave da Anthropic nunca é mandada.

▸ Transformers — a cola entre os shapes de API

Cada provider tem suas quirks: DeepSeek retorna um campo reasoning_content, Gemini quer safetySettings, OpenRouter espera um header HTTP-Referer. Os transformers built-in (deepseek, gemini, openrouter, groq, maxtoken, tooluse, reasoning, sampling, enhancetool, cleancache, vertex-gemini) cuidam dos casos conhecidos. Transformers custom cuidam do resto — veja a receita R8.

▸ Por que isso é seguro

O proxy faz bind em 127.0.0.1, não 0.0.0.0 — nenhum tráfego externo alcança. O campo top-level opcional APIKEY exige que clients (incluindo o CC) mandem um header Authorization que bata, protegendo contra outros processos locais batendo no endpoint. A env var NO_PROXY=127.0.0.1 que o ccr activate seta impede que seu proxy HTTP corporativo bisbilhote tráfego de localhost.

Deep dive → docs oficiais do CCRouter
Próximo → §3 · Instalação + primeira config
§3

Instalação + primeira config

prática

TL;DRnpm install -g @musistudio/claude-code-router, escreve um ~/.claude-code-router/config.json mínimo, sobe com ccr code ao invés de claude. Cinco minutos do zero ao primeiro turn roteado.

▸ Instalar

# install global
npm install -g @musistudio/claude-code-router

# verifica
ccr --version

▸ Localização da config

A config fica em ~/.claude-code-router/config.json (atenção: não em ~/.config/ — erro comum). Cria o diretório se ele não existir.

▸ Uma config mínima — DeepSeek pra tudo

{
  "LOG": false,
  "API_TIMEOUT_MS": 600000,
  "Providers": [
    {
      "name": "deepseek",
      "api_base_url": "https://api.deepseek.com/v1/chat/completions",
      "api_key": "sk-...your-deepseek-key...",
      "models": ["deepseek-chat", "deepseek-reasoner"],
      "transformer": { "use": ["deepseek"] }
    }
  ],
  "Router": {
    "default":     "deepseek,deepseek-chat",
    "background":  "deepseek,deepseek-chat",
    "think":       "deepseek,deepseek-reasoner",
    "longContext": "deepseek,deepseek-chat",
    "webSearch":   "deepseek,deepseek-chat"
  }
}

▸ Subir — três caminhos

  • ccr code — sobe o router E lança o Claude Code num único comando. O caminho mais simples.
  • ccr start e depois claude — roda o proxy como processo separado, usa o binário claude normal. Útil quando várias instâncias de CC compartilham o mesmo router.
  • eval "$(ccr activate)" — exporta ANTHROPIC_BASE_URL, ANTHROPIC_AUTH_TOKEN, NO_PROXY no seu shell. Depois disso, qualquer claude rodado nesse shell usa o router até você sair.

▸ Verifica se tá funcionando

# em outro terminal, com o CCR rodando
curl -s http://127.0.0.1:3456/health
# → {"ok":true}

# na sua sessão do CC
/cost
# → olha o campo "model"; se aparecer "deepseek-chat" ao invés de
#   um nome de modelo Anthropic, você tá roteado.

▸ Outros comandos CLI úteis

  • ccr ui — editor web de config em http://127.0.0.1:3456/ui. Mais fácil que editar JSON na mão.
  • ccr model — picker interativo de modelo pra sessão atual (sobrescreve o Router.default).
  • ccr stop — mata o proxy.
Deep dive → README oficial (install + primeira config)
Próximo → §4 · As seis rotas
§4

As seis rotas

prática

TL;DR — o CCRouter classifica cada request entrando numa das seis rotas e mapeia a rota pra um par provider+modelo. default é o fallback; as outras cinco disparam em features observáveis do request.

▸ As seis rotas — quando cada uma dispara

default todo request que não bate numa rota mais específica background dispatches de sub-agent; reads/writes em massa; trabalho não-interativo think requests onde o system prompt ou tools implicam profundidade de raciocínio longContext contagem de tokens prompt+histórico > longContextThreshold (default 60000) webSearch request usa a tool WebSearch image request contém imagem (beta) Rotas são avaliadas em ordem de especificidade. longContext ganha de default; webSearch ganha de default. Específicos ganham de genéricos — exatamente uma rota dispara por request.

▸ Um bloco Router multi-provider

"Router": {
  "default":     "anthropic,claude-sonnet-4-6",
  "background":  "deepseek,deepseek-chat",
  "think":       "deepseek,deepseek-reasoner",
  "longContext": "gemini,gemini-2.5-pro",
  "longContextThreshold": 60000,
  "webSearch":   "openrouter,perplexity/sonar-pro",
  "image":       "anthropic,claude-sonnet-4-6"
}

Lê como cascata: o que for pesado/raciocínio fica nos modelos premium; rotina e trabalho em massa vai pro caminho barato; long-context vai pro modelo com a maior janela.

▸ O campo longContextThreshold

Um campo numérico no objeto Router — a contagem de tokens acima da qual a rota longContext dispara. Default 60000. Abaixa pra (40000) se quiser viesar pro modelo long-context mais cedo, sobe se chamadas pra Gemini estão comendo seu budget em requests de tamanho de fronteira.

▸ Config de provider — anatomia

{
  "name": "gemini",                                       // unique slug
  "api_base_url": "https://generativelanguage.googleapis.com/v1beta/openai/chat/completions",
  "api_key": "AIza...your-key...",
  "models": ["gemini-2.5-pro", "gemini-2.5-flash"],       // models you'll route to
  "transformer": { "use": ["gemini"] }                    // request/response adapter
}

O campo name é o que você referencia no bloco Router (ex.: "longContext": "gemini,gemini-2.5-pro" — a vírgula separa nome do provider e nome do modelo).

▸ Onze transformers built-in

deepseek, gemini, openrouter, groq, maxtoken (limita tokens de output), tooluse (reescreve tool calls), reasoning (trata reasoning_content), sampling (altera temperature/top_p), enhancetool, cleancache, vertex-gemini. Aplica no nível do provider via transformer.use, ou escopa a modelos específicos via transformer.<model-name>.use.

Continua → 8 receitas do cookbook de roteamento
▮ COOKBOOK 8 RECEITAS · COPY-PASTE

RECEITAS DE ROTEAMENTO

Cada receita: Quando · Config · Configuração · Pegadinha. Todas as configs são fragmentos — encaixa no slot certo do seu config.json.

R1

Mande tarefas background pra um modelo barato

custo

Quando — dispatches de sub-agent, passes de indexing, reads de arquivo em massa — trabalho necessário mas que não precisa de raciocínio nível Opus. Mantém o agent parent no premium, manda tudo marcado como background pro DeepSeek (ou outro modelo barato-e-bom).

▸ Fragmento de config

"Providers": [
  { "name": "anthropic", "api_base_url": "https://api.anthropic.com/v1/messages",
    "api_key": "sk-ant-...", "models": ["claude-opus-4-7", "claude-sonnet-4-6"] },
  { "name": "deepseek", "api_base_url": "https://api.deepseek.com/v1/chat/completions",
    "api_key": "sk-...", "models": ["deepseek-chat"],
    "transformer": { "use": ["deepseek"] } }
],
"Router": {
  "default":    "anthropic,claude-sonnet-4-6",
  "background": "deepseek,deepseek-chat"
}

▸ Configuração

Cola no ~/.claude-code-router/config.json. Sobe com ccr code. Os dispatches normais de sub-agent do CC agora rodam no DeepSeek — sem mudança nas suas chamadas da tool Agent.

Pegadinha — o comportamento de tool-use do DeepSeek difere do da Anthropic; o transformer deepseek trata os casos comuns mas se um sub-agent espera output JSON bem estrito você pode precisar do transformer tooluse também: "transformer": { "use": ["deepseek", "tooluse"] }.

R2

Roteia long-context pro Gemini 2.5 Pro

capacidade

Quando — você tá raciocinando sobre um monorepo inteiro, um log de muitas milhares de linhas, ou um transcript gigante. A janela da Anthropic é larga mas o Gemini 2.5 Pro com 2M tokens é mais larga. Roteia só os requests que precisam.

▸ Fragmento de config

"Providers": [
  { "name": "anthropic", "api_base_url": "https://api.anthropic.com/v1/messages",
    "api_key": "sk-ant-...", "models": ["claude-sonnet-4-6"] },
  { "name": "gemini",
    "api_base_url": "https://generativelanguage.googleapis.com/v1beta/openai/chat/completions",
    "api_key": "AIza...", "models": ["gemini-2.5-pro"],
    "transformer": { "use": ["gemini"] } }
],
"Router": {
  "default":     "anthropic,claude-sonnet-4-6",
  "longContext": "gemini,gemini-2.5-pro",
  "longContextThreshold": 60000
}

▸ Configuração

O threshold é uma contagem de tokens de entrada (prompt + histórico). Uma vez que cruza, todo turn pelo resto da sessão provavelmente fica acima — então o Gemini fica em jogo. Abaixa o threshold pra 40000 se quiser handoff mais cedo; sobe pra 120000 se você só quer tarefas repo-wide de verdade indo pra fora.

Pegadinha — os safety filters do Gemini podem recusar conteúdo que a Anthropic aceita (ex.: pesquisa de segurança, certos samples de código). O transformer gemini desativa os defaults mais agressivos, mas código de produção mexendo com qualquer coisa adversarial — testes de auth, fuzzing — pode quicar. Mantém uma cadeia de fallback (receita R5).

R3

Local-first via Ollama (offline / privado)

privacidade

Quando — trabalho air-gapped, indústria regulada (saúde, defesa, finanças com dados de cliente), viagem offline, ou só preferência: nenhum token sai da sua máquina. O Ollama roda um server OpenAI-compatible local; o CCRouter roteia pra ele como pra qualquer outro provider.

▸ Pré-requisitos

# instala ollama + puxa um modelo de coding
brew install ollama
ollama serve &
ollama pull qwen2.5-coder:32b      # ou deepseek-coder-v2, llama3.3:70b, etc.

▸ Fragmento de config

"Providers": [
  { "name": "ollama",
    "api_base_url": "http://127.0.0.1:11434/v1/chat/completions",
    "api_key": "ollama",                          // any string; ollama ignores it
    "models": ["qwen2.5-coder:32b"] }
],
"Router": {
  "default":    "ollama,qwen2.5-coder:32b",
  "background": "ollama,qwen2.5-coder:32b",
  "think":      "ollama,qwen2.5-coder:32b"
}

▸ Configuração

O Ollama precisa tá rodando antes do ccr start (ou ccr code). No macOS, a formula do brew instala um serviço launchd; no Linux você vai querer um unit systemd. Confirma que tá no ar com curl localhost:11434/api/tags.

Pegadinha — modelos locais ficam substancialmente atrás dos modelos de frontier em tool-use e raciocínio. Espera mais loops de "vou ter que pensar nisso", tool calls malformados ocasionais, e throughput mais lento. Um modelo 32B num Mac M-series entrega 20–40 tokens/seg; modelos menores são mais rápidos mas piores. O ganho de privacidade/custo é real, o gap de qualidade também é real.

R4

Sub-agents pra Haiku, parent pra Opus

custo

Quando — seu agent parent dispara muitos sub-agents (pesquisa, file walks, validação) e cada sub-agent só precisa seguir um handoff bem apertado. Roda o parent no Opus pra orquestração; roda sub-agents no Haiku. Mesmo vendor, split dramático de custo.

▸ Fragmento de config

"Providers": [
  { "name": "anthropic",
    "api_base_url": "https://api.anthropic.com/v1/messages",
    "api_key": "sk-ant-...",
    "models": ["claude-opus-4-7", "claude-haiku-4-5-20251001"] }
],
"Router": {
  "default":    "anthropic,claude-opus-4-7",
  "background": "anthropic,claude-haiku-4-5-20251001"
}

▸ Configuração

Dispatches de sub-agent são classificados como background automaticamente pelo shape do request do CC (eles carregam um system prompt diferente e tem parent_tool_use_id). Nenhuma config necessária no lado do CC — o parent fica no Opus, dispatches downgradam transparentemente.

Pegadinha — se você enforce um handoff de delegação de 5 campos (ver cookbook R6), Haiku é OK. Se seus handoffs são frouxos, Haiku vai preencher as lacunas com chutes que Opus não teria dado. A disciplina na fronteira do dispatch é o que faz isso ser seguro.

R5

Cadeia de failover: Anthropic → OpenRouter

confiabilidade

Quando — cargas headless de produção onde uma queda de um provider não devia matar sua sessão de /goal. O CCRouter não tem um operador de chain built-in, mas o OpenRouter é ele próprio um meta-provider com semântica de fallback — encadeia no nível do OpenRouter, aponta a rota secundária do CC pra lá.

▸ Fragmento de config

"Providers": [
  { "name": "anthropic",
    "api_base_url": "https://api.anthropic.com/v1/messages",
    "api_key": "sk-ant-...",
    "models": ["claude-sonnet-4-6"] },
  { "name": "openrouter",
    "api_base_url": "https://openrouter.ai/api/v1/chat/completions",
    "api_key": "sk-or-...",
    "models": ["anthropic/claude-sonnet-4.6", "openai/gpt-5", "google/gemini-2.5-pro"],
    "transformer": { "use": ["openrouter"] } }
],
"Router": {
  "default":     "anthropic,claude-sonnet-4-6",
  "longContext": "openrouter,anthropic/claude-sonnet-4.6"
}

▸ Configuração

Quando a Anthropic direta tá no ar, seu caminho default bate direto nela (mais barato, menos latência). Se ela falhar (raro), você pode trocar "default" pra rota do OpenRouter com uma edição de config + ccr stop && ccr start (ou usa ccr ui pra edição ao vivo). Failover automático de verdade precisa de um script de router custom — fora do escopo dessa receita.

Pegadinha — o OpenRouter adiciona uma margem própria (~5%) em cima do pricing do provider, e adiciona um network hop. Não faz dele seu caminho primário a não ser que valorize especificamente a semântica de chain. É uma camada de seguro, não um daily driver.

R6

Teto diário com API_TIMEOUT_MS

custo

Quando — você tá rodando sessões de /goal desatendidas e um loop fora de controle podia queimar um budget de semana numa noite. O CCRouter não tem enforcer de budget em $ built-in, mas combinar API_TIMEOUT_MS com claude -p --max-budget-usd no nível do CC te dá dois tetos.

▸ Fragmento de config

{
  "API_TIMEOUT_MS": 120000,                       // teto de 2 min por request
  "LOG": true,
  "LOG_LEVEL": "info",
  "Providers": [ /* ... */ ],
  "Router": { /* ... */ }
}

▸ Configuração — pareando com teto de budget do CC

# /goal headless com budget E timeout por request
ccr start &
claude -p \
  --permission-mode bypassPermissions \
  --max-turns 40 \
  --max-budget-usd 2.00 \
  --output-format json \
  "/goal todo issue marcado 'needs-triage' é processado. Para depois de 40 turns."

Pegadinha — o API_TIMEOUT_MS do CCRouter só limita um único request. Um loop fora de controle de 100 turns ainda pode acumular gasto se cada turn for rápido. A flag --max-budget-usd no claude -p é o teto hard de verdade; trata o API_TIMEOUT_MS como guarda de "não trava num provider flaky", não como primitiva de budget.

R7

Override de roteamento por projeto

escopo

Quando — a maioria dos projetos quer a cadeia cheap-default, mas um projeto específico (dados regulados, refactor de alto risco) precisa ficar na Anthropic pra tudo. Desliga o CCR só pra esse workspace sem desinstalar.

▸ Abordagem 1 — env escopada por workspace

# no .envrc (direnv) do projeto ou no rc do shell
unset ANTHROPIC_BASE_URL
unset ANTHROPIC_AUTH_TOKEN
# neste workspace, claude fala direto com a Anthropic

▸ Abordagem 2 — configs distintas por path

# sobe CCR com uma config específica do projeto
CCR_CONFIG_PATH=~/.claude-code-router/configs/regulated.json ccr code
# (ou symlink ~/.claude-code-router/config.json antes de cada sessão)

▸ Configuração — exemplo direnv

# .envrc no projeto de alto risco
export ANTHROPIC_API_KEY="sk-ant-..."   # direto
unset ANTHROPIC_BASE_URL                 # pra claude não bater no CCR
unset ANTHROPIC_AUTH_TOKEN
# todos os outros projetos mantém o ccr activate ativo

Pegadinha — não tem "config por projeto" como primeira-classe no CCRouter hoje; a abordagem de env escopada por workspace é a resposta pragmática. Se você troca com frequência, mantém duas configs nomeadas (config-cheap.json, config-direct.json) e symlink — mais fácil que lembrar de unset/reset env toda hora.

R8

Transformer custom — descarta reasoning tokens

compat

Quando — você tá roteando pra um reasoning model (DeepSeek R1, estilo o3) e o output de reasoning_content tá vazando pro transcript do CC, comendo contexto. Um transformer custom pode descartar isso no lado server antes do CC ver o response.

▸ Fragmento de config — registra o transformer

{
  "transformers": [
    {
      "path": "~/.claude-code-router/plugins/strip-reasoning.js",
      "options": { "preserveOnError": true }
    }
  ],
  "Providers": [
    { "name": "deepseek-reasoner",
      "api_base_url": "https://api.deepseek.com/v1/chat/completions",
      "api_key": "sk-...",
      "models": ["deepseek-reasoner"],
      "transformer": { "use": ["deepseek", "strip-reasoning"] } }
  ],
  "Router": { "think": "deepseek-reasoner,deepseek-reasoner" }
}

▸ O script do transformer — shape mínimo

// ~/.claude-code-router/plugins/strip-reasoning.js
module.exports = {
  name: "strip-reasoning",
  transformResponse(response, _request, _options) {
    if (response?.choices) {
      for (const c of response.choices) {
        if (c.message && c.message.reasoning_content) {
          delete c.message.reasoning_content;
        }
      }
    }
    return response;
  }
};

▸ Configuração

Reinicia o CCR depois da edição (ccr stop && ccr start). Testa emitindo um request que bate na rota think e inspecionando o transcript do CC — a chain de raciocínio deve ter sumido, só a resposta fica.

Pegadinha — descartar reasoning ajuda no budget de contexto mas você perde visibilidade do porquê o modelo tomou uma decisão. Pra trabalho de alto risco, loga o reasoning_content num arquivo no transformer (não só apaga) pra post-mortems serem possíveis. O transformer built-in reasoning trata os casos oficiais; este é pra controle fino.