Saída longa de teste e build no Claude Code: por que gasta contexto e como cortar
Downshift por Tiago Vilas Boas. Atualizado em
Este Downshift é uma ferramenta em Go para agentes de código com IA, não a biblioteca React downshift de autocomplete.
Resumo
Toda saída de comando que o Claude Code lê entra na conversa e é enviada de novo em cada requisição seguinte. Uma suíte verde imprime uma linha por pacote ou teste que não diz nada além de PASS. Rode menos testes, use as flags silenciosas, cuidado com o | tail e deixe a falha inteira. O downshift compact automatiza a última parte: encurta só a saída de sucesso limpa, deixa a falha byte a byte e devolve o exit code real.
Por que a saída longa de teste gasta contexto no Claude Code?
Uma rodada verde de testes é um bolo de comprovantes iguais. Cada linha diz a mesma coisa, passou, e o Claude Code guarda o bolo inteiro no bolso até o fim da sessão.
É assim que o contexto funciona. Quando o Claude roda um comando pela ferramenta Bash, a saída entra na conversa como resultado de ferramenta. A página de custos da Anthropic diz que o Claude Code envia a conversa inteira em toda requisição, e cada chamada de ferramenta gera outra requisição com os resultados. O cache de prompt cobra menos por essa releitura, mas ela continua acontecendo, continua ocupando a janela de contexto e antecipa a compactação automática.
Saída de sucesso é quase toda repetição: uma linha por pacote no go test, uma linha ou um ponto por teste na maioria dos runners, tempos e um resumo. O modelo precisa de um fato só: tudo passou, com exit code 0. Na falha é o contrário. A asserção, o diff e o stack trace são a informação, então a falha precisa ficar inteira.
A regra do resto do guia é essa: encolher o sucesso, nunca a falha.
Como reduzir os tokens da saída de teste sem instalar nada?
Comece pelo que o Claude Code e o seu runner de testes já oferecem.
| Recurso | O que corta | O porém |
|---|---|---|
| Rodar só os testes do foco | go test ./pkg/ -run TestName, um nó do pytest, um arquivo de spec em vez da suíte inteira | Antes do merge a suíte completa continua obrigatória |
| Flags silenciosas | go test sem -v, pytest -q, reporter de pontos ou de resumo | Alguns modos silenciosos também encurtam a falha; veja como ela aparece antes |
| tail -N | Fica só com as últimas N linhas | O pipe devolve o exit code do tail, e a falha impressa acima das últimas N linhas some |
| Delegar a execução a um subagente | A saída longa fica no contexto do subagente; só o resumo volta (docs de subagentes) | As requisições do subagente também contam no seu uso |
| /compact e /clear | /compact resume a conversa; /clear recomeça do zero sem custo | Os dois agem depois do estrago. O /compact lê o contexto inteiro, e a próxima rodada longa enche de novo |
| Um hook que filtra a saída | A página de custos mostra um hook PreToolUse que reescreve comandos de teste para mostrar só as linhas de falha | O script é seu, e o pipe com grep e head decide quais linhas e qual exit code o Claude vê |
O porém do | tail merece atenção, porque agente usa isso o tempo todo. No bash e no zsh, um pipeline devolve o status do último comando, então uma suíte quebrada passando pelo tail parece verde se o pipefail estiver desligado:
go test ./... | tail -5 # status é o do tail, quase sempre 0
set -o pipefail; go test ./... | tail -5 # status é o do go test quando ele falhaNenhum desses recursos distingue sucesso de falha. Ou cortam os dois, ou não cortam nenhum.
O que o downshift compact faz com a saída de teste?
O Downshift é um binário Go open source que roda como hooks dentro de agentes de código. O Compactor dele é um comando: downshift compact -- <comando>. Ele roda o seu comando e olha o resultado antes do agente.
- Exit 0, stderr vazio e saída que ele reconhece: a saída vira um resumo PASS curto, mais uma linha de marcação dizendo quantos bytes foram cortados.
- Falha, exit diferente de zero ou saída que ele não reconhece: passa byte a byte.
- O exit code é sempre o do próprio comando.
Ele trabalha com uma allowlist: go test, pytest, vitest, jest, tsc, cargo test, phpunit, playwright test, cypress run, gradle, maven, flutter test e outros. Qualquer outro comando, inclusive npm test, não é envolvido. As formas exatas estão na matriz de harnesses. Para desligar, use "exec": false na configuração do Downshift ou DOWNSHIFT_EXEC=0 no ambiente.
Como fica numa execução real?
Execução única, 2026-10-24, no repositório do Downshift: três pacotes Go, go test simples sem -v, macOS.
Antes: saída crua, 202 bytes
$ go test ./internal/execwrap/ ./internal/telemetry/ ./internal/classify/
ok github.com/tiagovilasboas/downshift/internal/execwrap 26.559s
ok github.com/tiagovilasboas/downshift/internal/telemetry 1.732s
ok github.com/tiagovilasboas/downshift/internal/classify (cached)Depois: downshift compact, 167 bytes contando a linha de marcação
$ downshift compact -- go test ./internal/execwrap/ ./internal/telemetry/ ./internal/classify/
Go test: PASS (3 packages ok) under github.com/tiagovilasboas/downshift/internal/
ok execwrap
ok telemetry
ok classify
[downshift compact: compacted 205 to 119 bytes]De 202 para 167 bytes, cerca de 17% a menos, numa saída que já era curta. A linha de marcação conta a própria execução (205 para 119 bytes antes de a marcação entrar); os tempos dos pacotes mudam entre uma rodada e outra. O go test simples já é enxuto. Os cortes maiores vêm de runners que imprimem uma linha por teste, de flags verbosas e de ferramentas de build.
Fonte: os dois comandos acima, rodados uma vez em 2026-10-24 com downshift v0.1.2-65 (commit 480391dc). Bytes medidos com wc -c. A sua saída vai ser diferente.
O Claude Code reescreve os comandos de teste sozinho?
No Claude Code, sim. O hook PreToolUse do Downshift vê o comando Bash antes de ele rodar e reescreve os comandos da allowlist para a forma compacta, inclusive nos formatos que o agente mais digita:
| Comando que o agente escreve | O que roda |
|---|---|
cd api && go test ./... | cd api && downshift compact -- go test ./... |
go test ./... 2>&1 | tail -20 | downshift compact -- go test ./... 2>&1 | tail -20 |
go build ./... && go test ./... | cada trecho envolvido; o && continua parando na primeira falha |
gofmt -l .; go test ./pkg | só o trecho do go test é envolvido |
Uma regra de deny ou ask que bate com o comando, ou com qualquer parte dele, impede a reescrita. Um comando que já contém downshift compact nunca é envolvido duas vezes. Com | tail -N o pipe continua devolvendo o status do tail, como antes; a reescrita não muda o exit code.
Os outros harnesses, como Codex, Cursor, OpenCode, Antigravity e KiroCrew, não têm canal para reescrever um comando de shell. Neles o próprio agente roda downshift compact -- <comando>. É um comando de shell comum, então funciona igual em qualquer harness e em qualquer sistema operacional.
Quanto a compactação de saída economiza?
A única medição é uma contagem de bytes num corpus sintético, de 2026-10-21: 248 arquivos de saída de comando, dos quais 26 são compactados. Nesses 26 casos de sucesso limpo, 82,3% menos bytes. Nos 248, 23,7% menos, porque a maioria das fixtures é falha ou caso de borda feito para ficar cru. São bytes, não tokens do modelo, medidos em fixtures, não em sessões reais. O seu mix de comandos vai dar outro número. Leia o relatório do corpus.
Perguntas frequentes
Compactar a saída de teste esconde falhas do Claude?
Não. A compactação só roda quando o comando sai com 0, sem nada no stderr, e a saída é reconhecida como sucesso. Falha, exit diferente de zero ou saída desconhecida passam byte a byte.
O downshift compact muda o exit code?
Não. Ele devolve o exit code do próprio comando. Num pipe como | tail -N o shell continua devolvendo o status do último comando, igual a sem o Downshift.
Mandar a saída para o tail não resolve?
Corta o tamanho, mas o pipe devolve o exit code do tail se o pipefail estiver desligado, e uma falha impressa acima das últimas linhas se perde. Ele também apara a saída de falha, que é justamente a parte de que o modelo precisa.
Funciona fora do Claude Code?
Sim, como comando. Só o Claude Code reescreve comandos sozinho pelo hook. No Codex, no Cursor e nos outros harnesses o agente roda downshift compact -- <comando> diretamente.
Como desligo?
Use "exec": false na configuração do Downshift ou DOWNSHIFT_EXEC=0 no ambiente. Uma regra de deny ou ask que bate com um comando também impede a reescrita dele.
Pare de pagar contexto por check verde
Instale o Downshift, veja cada alteração antes com downshift setup --dry-run, e a próxima suíte verde volta como uma linha de resumo enquanto a falha fica inteira. downshift setup --undo restaura os backups.
curl -fsSL https://raw.githubusercontent.com/tiagovilasboas/downshift/main/install.sh | sh && downshift setupPlugin do Claude Code
/plugin install downshift --marketplace tiagovilasboas/downshiftGuias relacionados
Fontes
- Anthropic docsmedido
code.claude.com/docs/en/costs
conversa inteira enviada em toda requisição, /compact lê o contexto, /clear, delegar operações verbosas, exemplo de hook de saída de teste (consultado em 2026-10-24) - Anthropic docsmedido
code.claude.com/docs/en/sub-agents
isolar operações de alto volume num subagente - Anthropic docsmedido
code.claude.com/docs/en/hooks
hooks PreToolUse - Downshift repomedido
docs/evidence/compaction-corpus-2026-10-21.md
248 fixtures, 26 compactadas, 82,3% e 23,7%, bytes e não tokens - Downshift repomedido
docs/reference/harness-matrix.md
allowlist, formatos compostos e cadeias, reescrita só no Claude Code - Downshift repomedido
docs/features/compaction.md
compacta só com exit 0 e stderr vazio; falhas preservadas - Saída do Downshift CLImedido
go test e downshift compact, execução única em 2026-10-24
bytes antes e depois