TL;DR e veredito
Quando o limite do seu plano Claude estoura no meio de uma tarefa, você pode rodar o mesmo Claude Code contra um modelo no seu próprio notebook, via Ollama. Fizemos isso num M1 Pro com 16 GB, com o qwen3.5:9b, e demos a ele duas tarefas reais num pequeno pacote Python.
- Tarefa A, uma opção
--prefixem um arquivo: sem--bare, nada aconteceu por cerca de quinze minutos. Com--bare, passou em 93 s. - Tarefa B, uma renomeação entre arquivos: o modelo local informou os testes verdes, e um import estava quebrado nas duas execuções (contexto de 4k e de 64k). No plano, o Claude fez em 38 s com os imports funcionando.
- O Ollama dá a uma máquina como a nossa um contexto de 4k por padrão.
OLLAMA_CONTEXT_LENGTH=65536aumenta isso.
Veredito: vale configurar o alias para trabalhos de um arquivo que você confere num relance. Qualquer coisa entre arquivos espera o plano, e você sempre lê o diff. O pacote traz o bloco do alias e um cartão de regra de uma página.
Síntese com fontes
O setup são três variáveis de ambiente e um nome de modelo. O guia do Ollama aponta o Claude Code para http://localhost:11434 com ANTHROPIC_AUTH_TOKEN=ollama s1. A documentação do Claude Code diz que ANTHROPIC_BASE_URL substitui o endpoint da API s17. Como as variáveis ficam na linha do alias, o claude comum continua usando o seu plano.
Uma API key definida substitui a sua assinatura. A documentação do Claude Code diz que um ANTHROPIC_API_KEY definido é usado no lugar da sua assinatura, mesmo que você esteja logado s17. Por isso as variáveis pertencem ao alias e não ao perfil do seu shell.
O modelo precisa caber na memória. O qwen3.5:9b é listado com 6,6 GB a 7,6 GB, contexto de 256K e suporte a ferramentas s18. Na nossa máquina, ollama ps mostrou 7,6 GB no contexto padrão e 7,7 GB em 65536.
O contexto padrão é a primeira armadilha. O Ollama usa um contexto de 4k abaixo de 24 GiB de VRAM e diz que ferramentas de código devem ser configuradas com pelo menos 64000 s3. Você aumenta com OLLAMA_CONTEXT_LENGTH ao iniciar o servidor, e ollama ps mostra se pegou s3. O guia do Ollama também pede uma janela de 64k ou maior s1.
--bare é a segunda. Um texto mediu a primeira requisição padrão em 14,0k tokens e a com --bare em 0,75k s8. Nós não contamos tokens. O que vimos: a mesma tarefa com o mesmo contexto de 4k passou de nada em 900 s para um sucesso em 93 s. --bare também pula hooks, plugins, memória e CLAUDE.md, então o modelo local nunca vê as regras do seu projeto. No nosso Claude Code 2.1.294, a ajuda diz que a autenticação é estritamente ANTHROPIC_API_KEY ou apiKeyHelper, por isso o alias define ANTHROPIC_API_KEY=ollama. Não testamos uma key vazia com --bare.
Uma configuração de header está no alias, mas não a medimos. A documentação da Unsloth diz que o attribution header invalida o cache local e que CLAUDE_CODE_ATTRIBUTION_HEADER=0 resolve s5, e uma issue do Claude Code rastreia os mesmos cache misses s9. --bare já pula a atribuição, então não sabemos dizer o que a variável extra fez nas nossas execuções.
Modelos locais pequenos costumam falhar no contrato de ferramentas, não no código. Um benchmark encontrou modelos chamando write_file em vez de Write s7. O issue tracker do Ollama tem um relato de chamadas de ferramenta truncadas e descartadas s10. Não vimos erro de nome de ferramenta. Nossa falha foi mais silenciosa: uma renomeação que deixou um import quebrado.
Os primeiros turnos podem ser lentos. Um relato de campo com o qwen3.5:9b e contexto de 64k, num notebook de 32 GB, viu uma primeira requisição acima de 10 min e turnos seguintes de 1 a 3 min s6. Nossos tempos estão na tabela abaixo.
O que o endpoint não faz. A página de compatibilidade Anthropic do Ollama lista prompt caching e escolha forçada de ferramenta como não suportados s2. A documentação da Anthropic diz que não há suporte a rotear o Claude Code para modelos que não sejam Claude por nenhum gateway s4. Uma análise crítica chega ao mesmo lugar que nós: local só para trabalho de rotina s11.
Um alias simples vence um roteador que reutiliza o token da sua assinatura. Um guia de configuração relata esses roteadores falhando com um 401 s13.
Código
claude-alt.zsh
# claude-alt: one-file jobs I can check in a glance
# plan: anything across files, or that I can't check by reading the diff
# always: read the diff before committing
alias claude-alt='CLAUDE_CODE_ATTRIBUTION_HEADER=0 ANTHROPIC_AUTH_TOKEN=ollama ANTHROPIC_API_KEY=ollama ANTHROPIC_BASE_URL=http://localhost:11434 claude --bare --model qwen3.5:9b'
: o bloco do alias com a regra de troca como três comentários acima dele. Cole em `~/.zshrc` e depois rode `source ~/.zshrc`.
- switch-rule.md
# The switch rule
Keep this next to the claude-alt alias. Decide before your limit hits, not while you wait.
## Goes to claude-alt (local model)
- A job in one file that you can check at a glance
- Adding an option, explaining a function, testing one function
- Work where a wrong result is visible in one short diff
## Waits for the plan
- Anything that crosses files, such as a rename with callers in other modules
- Anything you cannot check by reading the diff
- Work that depends on your hooks or your project rules (the alias runs with --bare, which skips both)
- Long sessions
## Always
- Read the diff before you commit, whichever model wrote it
- After a rename, import the old names by hand. A green test run only covers what the tests cover
## Why this rule
Two tasks on a 16 GB M1 Pro with qwen3.5:9b:
- One file (add a --prefix option): passed in 93 s with --bare.
- Across files (rename a function, keep the old name as an alias): the model said the tests were green, and an import was broken in both runs.
- On the plan, Claude did the rename in 38 s with both the old and the new imports working.
Two tasks on one small package is a starting point. Widen the rule with your own runs.
: um cartão de regra de uma página sobre quais trabalhos vão para o local, quais esperam o plano e a checagem que você sempre faz.
- run-task.sh
#!/bin/zsh
# Usage: run-task.sh <name> <A|B> <plan|alt|alt-nobare> [timeout_s]
# Runs one task on a fresh copy of slugkit and records time, output, diff and the check.
set -u
NAME=$1; TASK=$2; MODE=$3; TO=${4:-1800}
SRC=${SLUGKIT:?set SLUGKIT to the slugkit repo}
OUT=${RUNS:?set RUNS to the output dir}/$NAME
rm -rf $OUT; mkdir -p $OUT; cp -R $SRC $OUT/repo; cd $OUT/repo
A='In slugkit/cli.py add a --prefix option: when given, the slug starts with the prefix and the separator (python3 -m slugkit --prefix blog Hello World prints blog-hello-world). Then run that command to check it.'
B='Rename the function smart_truncate to truncate_words everywhere in this repo (definition, imports, calls, tests, __all__). Keep smart_truncate as an alias of truncate_words in slugkit/truncate.py so old imports still work. Then run python3 -m unittest discover tests and make sure every test passes.'
[[ $TASK == A ]] && P=$A || P=$B
TOOLS=(--allowedTools "Read" "Edit" "Write" "Glob" "Grep" "Bash(python3:*)" "Bash(grep:*)" "Bash(ls:*)")
start=$(date +%s)
case $MODE in
plan) perl -e 'alarm shift; exec @ARGV' $TO claude -p "$P" --output-format json $TOOLS > $OUT/out.json 2> $OUT/err.log ;;
alt) CLAUDE_CODE_ATTRIBUTION_HEADER=0 ANTHROPIC_AUTH_TOKEN=ollama ANTHROPIC_API_KEY=ollama ANTHROPIC_BASE_URL=http://localhost:11434 \
perl -e 'alarm shift; exec @ARGV' $TO claude --bare --model qwen3.5:9b -p "$P" --output-format json $TOOLS > $OUT/out.json 2> $OUT/err.log ;;
alt-nobare) CLAUDE_CODE_ATTRIBUTION_HEADER=0 ANTHROPIC_AUTH_TOKEN=ollama ANTHROPIC_API_KEY="" ANTHROPIC_BASE_URL=http://localhost:11434 \
perl -e 'alarm shift; exec @ARGV' $TO claude --model qwen3.5:9b -p "$P" --output-format json $TOOLS > $OUT/out.json 2> $OUT/err.log ;;
esac
rc=$?; end=$(date +%s)
git diff --stat > $OUT/diff.stat; git diff > $OUT/diff.patch
if [[ $TASK == A ]]; then python3 -m slugkit --prefix blog Hello World > $OUT/check.txt 2>&1; else python3 -m unittest discover tests > $OUT/check.txt 2>&1; grep -rn smart_truncate slugkit tests >> $OUT/check.txt; fi
echo "{\"name\":\"$NAME\",\"task\":\"$TASK\",\"mode\":\"$MODE\",\"rc\":$rc,\"seconds\":$((end-start))}" > $OUT/meta.json
cat $OUT/meta.json; tail -3 $OUT/check.txt
: o script que usamos para cronometrar a tarefa A ou B no plano ou no alias, e para salvar o diff e a checagem. Defina `SLUGKIT` com o seu repositório de teste e `RUNS` com uma pasta de saída antes.Faça na segunda-feira
- Rode
ollama --versioneclaude --version. Usamos o Ollama 0.40.13 s19 e o Claude Code 2.1.294. - Baixe um modelo que caiba na sua memória. Para 16 GB, usamos o
qwen3.5:9b, que tem 7,6 GB. - Inicie o Ollama com
OLLAMA_CONTEXT_LENGTH=65536 ollama serve, depois rodeollama pse leia a coluna CONTEXT. - Cole o bloco de
claude-alt.zshem~/.zshrce rodesource ~/.zshrc. Confira que oclaudecomum ainda usa o seu plano. - Escolha uma tarefa de um arquivo numa cópia descartável de um repositório e rode com
claude-alt. - Leia o diff e rode a checagem você mesmo. Não confie no relato do próprio modelo.
- Tente uma renomeação em vários arquivos na mesma cópia. Importe os nomes antigos à mão depois.
- Mantenha o
switch-rule.mdjunto ao alias e edite com o que as suas próprias execuções mostrarem.
Medições
Máquina: MacBook Pro M1 Pro, 16 GB, Claude Code 2.1.294, Ollama 0.40.13, qwen3.5:9b (7,6 GB). O repositório era um pequeno pacote Python de 4 módulos com 12 testes unittest, escrito para este teste. A máquina esteve sob pressão de memória o tempo todo, então os tempos locais são um limite superior.
| Tarefa | Rota | Tempo | Resultado |
|---|---|---|---|
| A, adicionar --prefix (um arquivo) | Plano, Claude | 21 s | Passou, blog-hello-world |
| A, adicionar --prefix (um arquivo) | Alias, 4k, sem --bare | 900 s | Interrompida no limite de 15 minutos, sem edições, sem resposta |
| A, adicionar --prefix (um arquivo) | Alias, 4k, --bare | 93 s | Passou, blog-hello-world |
| A, adicionar --prefix (um arquivo) | Alias, 64k, --bare | 35 s | Passou, blog-hello-world |
| A, adicionar --prefix (um arquivo) | Alias, 64k, sem --bare | não concluída | Encerrada pelo sistema por pouca memória, sem resultado |
| B, renomear entre arquivos | Plano, Claude | 38 s | Passou, 12 testes OK, imports antigo e novo funcionam, testes renomeados |
| B, renomear entre arquivos | Alias, 4k, --bare | 464 s | Quebrou: "All 12 unit tests pass", mas from slugkit import truncate_words deu ImportError |
| B, renomear entre arquivos | Alias, 64k, --bare | 142 s | Quebrou: 12 testes OK e informou como concluído, mas o alias foi para o __init__.py, então from slugkit.truncate import smart_truncate deu ImportError |
A tarefa B pedia para manter smart_truncate como alias em slugkit/truncate.py. O Claude Code também avisou que não conhecia o modelo e assumiu uma janela de 200k tokens. Nossas sessões ficaram muito abaixo disso, e não testamos uma longa.
Para ir além
O que deixamos de fora e onde procurar, se você quiser.
- Rotas hospedadas. Provedores como DeepSeek, Z.AI ou OpenRouter usam o mesmo alias com outra URL base. Cobram por token e não tínhamos uma key, então não rodamos.
- Roteadores de plano gratuito. Roteadores que juntam planos gratuitos prometem Claude Code de graça. Não testamos. Confira os termos deles e para onde vão os seus prompts antes de tentar um.
- Modelos em nuvem do Ollama. Não existe mais plano gratuito, então são pagos por uso.
- Modelos locais maiores. Não tentamos modelos na faixa de 26b a 35b, que não cabem em 16 GB com contexto de 64k. Se você tem 32 GB ou mais, um relato de campo rodou um modelo de 35b em seis tarefas avaliadas e acertou as seis, com cerca de 8x o tempo dos modelos em nuvem s12.
- Roteamento híbrido. Local para subagentes e o plano para o loop principal é um setup que não tentamos.
- Outros modelos pequenos. O gemma4:e4b é uma alternativa que alguns guias usam. Não rodamos.
- Um benchmark de verdade. Duas tarefas em um pacote mostram um padrão, não um ranking. Para ampliar a regra, rode suas próprias tarefas com
run-task.she mantenha uma tabela como a de cima.
FAQ
O claude comum muda quando eu adiciono o alias?
Não. As variáveis ficam na linha do alias, então só o claude-alt conversa com o Ollama.
Por que o alias define ANTHROPIC_API_KEY=ollama e não uma key vazia?
Com --bare, o Claude Code lê a key só de ANTHROPIC_API_KEY ou apiKeyHelper. Nosso alias com ollama como key funcionou. Não testamos uma key vazia com --bare até o fim.
A Anthropic oferece suporte a isso? Não. A documentação da Anthropic diz que não há suporte a rotear o Claude Code para modelos que não sejam Claude por nenhum gateway s4.
Posso confiar num teste verde do modelo local? Só para o que os testes cobrem. Na tarefa B os testes passaram com um import quebrado, porque nada testava o caminho de import antigo. Leia o diff e importe os nomes antigos à mão.
Vai ser tão rápido quanto o plano? Não nas nossas execuções. A tarefa B levou 38 s no plano e de 142 s a 464 s no alias, e ainda assim quebrou.
AIDive