Squelch — Menos Ruído, Menos Tokens

A maior parte do que um agente de programação lê é saída de comandos, e a maior parte da saída de comandos é ruído: centenas de linhas PASSED à volta do único teste que falhou, uma barra de progresso para cada pacote que uma instalação descarrega, uma linha Compiling para cada ficheiro de uma compilação, os contadores de objetos do git. O modelo lê tudo isso, em cada turno, e tudo conta para a janela de contexto e para a fatura.

O Squelch retira esse ruído antes de o modelo o ler. Mantém aquilo sobre que o agente age — erros, falhas, avisos, resumos — e deixa de fora o resto. Funciona para todos os agentes (Claude Code, Codex, Kimi Code, Grok, omp) sem instalar nada na máquina: o proxy do seu Mac apara os resultados de comandos que cada pedido transporta, da mesma forma que a Proteção de dados pessoais troca dados pessoais. O Squelch define-se por máquina (um espaço de trabalho, no editor de definições) e está desligado por predefinição; a referência dos campos está em Definições → Squelch.

Crédito: o Squelch inspira-se no rtk (Rust Token Killer, github.com/rtk-ai/rtk, Apache-2.0), que faz o mesmo reescrevendo os comandos de shell do agente na sua máquina. A ideia, as suas estratégias de filtragem por família e o seu relatório de «tokens poupados» (rtk gain) vêm do rtk; os filtros do Bromure são próprios e correm no proxy, pelo que chegam a todos os agentes sem hooks.

Ativá-lo

Duas formas, ambas imediatas — o pedido seguinte dos agentes já vai aparado, nada reinicia:

  • No cabeçalho de uma sessão, clique no ícone do Squelch (três linhas que se estreitam, a seguir à contagem de tokens) e ligue o interruptor no popover.
  • Nas definições da máquina, selecione Squelch em Modelos, marque Tirar o ruído da saída dos comandos antes que o modelo a leia e clique em Guardar.

Para que seja a predefinição das novas máquinas, ative-o em Bromure → Preferências… (o modelo Predefinições).

O que retira

O Squelch olha para o comando de onde veio uma saída — o último comando de uma cadeia que faz o trabalho, atravessando os prefixos sudo, timeout, env e VAR=value — e aplica o filtro dessa família:

FamíliaComandos (exemplos)Deixado de foraSempre mantido
Testespytest, jest, vitest, mocha, go test, cargo test, swift test, xcodebuild test, npm test, dotnet test, rspec, phpunitUma linha por teste bem-sucedido, pontos de progresso, progresso de compilaçãoFalhas, tracebacks, diffs de asserções, o resumo
Instalaçõesnpm/pnpm/yarn/bun install, pip/uv/poetry, apt, brew, cargo fetch, go mod download, docker pullLinhas de descarregamento, de descompactação e de «already satisfied», barras de progresso, avisos de descontinuaçãoErros, conflitos, a linha de resultado
Compilaçõescargo build, swift build, xcodebuild, make, cmake, gradle, mvn, tsc, docker buildLinhas de compilação por ficheiro, os blocos de passos do xcodebuild, a conversa de diretórios do make, o mesmo aviso impresso de novoCada erro e cada aviso, com o seu excerto de código
gitgit push, pull, fetch, clone, status, commitContadores de objetos, dicas (use "git add"…), longas listas create modeRamos, refs, conflitos, os ficheiros
Registosdocker logs, kubectl logs, journalctlSequências de linhas que só diferem nos números (carimbos de data/hora, ids) — a primeira é mantida, com uma contagemTudo o que difere
Pesquisagrep, rg, ag, git grepO final de linhas muito longas (ficheiros minificados)Cada correspondência e a sua localização
Tudo o resto—Sequências de escape do terminal, linhas de progresso redesenhadas, barras de progresso, a mesma linha seis ou mais vezes seguidasO resto

Uma linha que mencione um erro, uma falha, um aviso, um pânico ou um tempo esgotado nunca é deixada de fora, seja qual for o padrão a que corresponda.

Uma desinstalação (pip uninstall, uv pip uninstall, npm remove, brew uninstall, apt remove…) não é uma instalação: o que imprime é a lista do que saiu, por isso só recebe a limpeza genérica de «tudo o resto».

Algumas saídas nunca são tocadas, porque o agente as lê como a própria coisa — normalmente para copiar delas para uma edição: cat, head, tail, sed, less, jq, awk, diff, git diff, git show, git log, git blame (sejam quais forem as opções que venham antes: git --no-pager diff, git -C repo log), gh pr diff, gh api, hg diff, curl, python -c e afins. Também não é tocado um pipeline que o próprio agente montou (pytest -v | tail -40): ele já escolheu o que ver. Os resultados das ferramentas de ficheiros dos próprios agentes (ferramentas Read, Edit, Grep) também nunca são tocados — apenas comandos de shell.

Uma saída com menos de cerca de 300 bytes, ou que encolheria menos de 10%, passa sem alterações.

O que o modelo vê

Uma saída aparada termina com uma linha que diz o que ficou de fora e como obter tudo:

FAILED tests/test_api.py::test_retry_budget - assert 2 == 3
========================= 1 failed, 120 passed in 4.12s =========================
[Bromure Squelch left out 120 noise lines (passing tests 120). Run the command again prefixed with BROMURE_FULL_OUTPUT=1 to see all of it.]

Quando o agente precisa da saída completa, volta a executar o comando com BROMURE_FULL_OUTPUT=1 à frente — inofensivo para a shell, e o Squelch deixa passar a saída desse comando por inteiro.

Só o modelo do agente vê o texto aparado. A transcrição do próprio agente, a vista de chat e o seu terminal mantêm a saída completa. O Squelch altera o pedido cadeia a cadeia e deixa todos os outros bytes tal como o agente os enviou, e a mesma saída é sempre aparada da mesma forma, por isso uma conversa reenviada turno após turno mantém a sua cache de prompt. (Ligar ou desligar o Squelch a meio de uma conversa altera os turnos anteriores uma vez, pelo que o pedido seguinte falha a cache.)

Ver o que poupou

O cabeçalho de cada sessão mostra o que o Squelch poupou nessa conversa (12K economizados). Clique nele para abrir o popover:

  • Esta conversa — tokens poupados, a parte da saída de comandos que ficou de fora, quantas saídas de comandos foram enviadas ao modelo e quantas foram aparadas.
  • Todo o "…" (a máquina inteira) — o mesmo, para todas as conversas da máquina.
  • De onde veio — os comandos que mais pouparam (pytest, npm install, …).
  • Últimas duas semanas — tokens poupados por dia.

O painel de definições Squelch da máquina mostra a lista completa de comandos e o mesmo gráfico.

Os tokens são estimados como caracteres ÷ 4, tal como faz o rtk — não há nenhum tokenizador no circuito, pelo que a parte poupada é fiável e a contagem absoluta aproximada. Cada saída de comando conta uma vez, na primeira vez que um pedido a transporta, mesmo que o agente reenvie toda a conversa em cada turno — a poupança real numa sessão longa é maior do que o número mostrado.

As poupanças são guardadas por máquina em ~/Library/Application Support/BromureAC/squelch/ledger.json (por conversa, comando, família e dia, para os últimos 90 dias). Num cliente pesado (um Mac, iPhone ou iPad ligado a outro Mac), os números vêm do servidor que executa a máquina, e o interruptor do popover liga ou desliga o Squelch lá.

Limites

  • Só máquinas. O Squelch vive no proxy por onde passa todo o tráfego de IA de cada máquina. Uma máquina nativa (um Mac a executar o Bromure Sidecar) envia o tráfego dos seus agentes diretamente para o fornecedor, por isso o Squelch não se aplica aí.
  • Padrões, não discernimento. Os filtros reconhecem os formatos de saída das ferramentas comuns. Um executor de testes invulgar ou um script de compilação personalizado recebe apenas a limpeza genérica (escapes, barras de progresso, linhas repetidas).
  • Um comando que o pedido não nomeia. Quando um turno do Codex continua um anterior no servidor, um resultado pode chegar sem a chamada que o produziu. O Squelch associa-o à chamada que o modelo anunciou na sua resposta; um resultado cuja chamada nunca viu — depois de um reinício do Bromure, por exemplo — fica como está, já que só pelo seu texto não se distingue uma execução de testes de um cat de um registo de testes.