O RTK (Rust Token Killer) é um proxy de linha de comando que intercepta os comandos de shell que um agente de código executa (git status, cargo test, ls, grep) e devolve uma versão filtrada e compacta da saída antes que ela chegue ao contexto do LLM. Ele serve para quem usa Claude Code, Cursor, Codex, Gemini CLI e afins no dia a dia e percebe que boa parte da janela de contexto é gasta com barra de progresso, teste que passou e listagem de diretório. Funciona como um binário único em Rust, ativado por um hook que reescreve os comandos sem o agente perceber.

Este post se baseia na leitura do código e da documentação do repositório rtk-ai/rtk. Na data deste post, o projeto tem 83104 estrelas e licença Apache-2.0.

O que é o RTK e que problema ele resolve?

Quem trabalha com agente de código já viu a cena: o agente roda a suíte de testes, recebe 300 linhas de ok, um traceback no meio e mais 50 linhas de resumo. Tudo isso entra no contexto como token de entrada, a unidade que o modelo lê e que você paga. Multiplique por dezenas de comandos por sessão e a conversa fica cara e lenta, além de empurrar o que importa para fora da janela.

O RTK ataca exatamente esse pedaço. Segundo o README, ele aplica quatro estratégias por tipo de comando:

  1. Filtragem: remove ruído, como comentários, espaços e boilerplate.
  2. Agrupamento: junta itens parecidos, como arquivos por diretório e erros por tipo.
  3. Truncamento: mantém o contexto relevante e corta redundância.
  4. Deduplicação: colapsa linhas de log repetidas com um contador.

Na prática, git push vira ok main, cargo test mostra só as falhas e git log mostra hash, autor e assunto. A documentação lista mais de 100 comandos suportados, de pytest e go test a docker ps, kubectl logs, aws e pulumi.

Para quem é do mundo PHP, existe uma pasta src/cmds/php/ com módulos para artisan, phpunit, pest, paratest, phpstan, pint e ecs, além de um filtro TOML para composer install. O README só documenta explicitamente o rtk phpt (testes .phpt, com -99% de saída). Como fica a saída filtrada de um php artisan test ou de um phpstan analyse não está descrito na documentação principal; está apenas no código desses módulos.

Como o RTK funciona por dentro?

A arquitetura é descrita no CLAUDE.md do próprio repositório como um proxy de comandos. O fluxo é este:

  1. O hook do agente recebe o comando antes da execução. Um hook PreToolUse é um gancho que o Claude Code dispara antes de rodar uma ferramenta, e que pode alterar a entrada dela. O hook troca git status por rtk git status.
  2. O src/main.rs roteia o subcomando por um enum Commands do Clap até o módulo especializado em src/cmds/<ecossistema>/, como git_cmd.rs, cargo_cmd.rs ou pytest_cmd.rs.
  3. O módulo executa o comando real, captura stdout e stderr, aplica o filtro e imprime o resultado. O código de saída do processo filho é propagado com std::process::exit(code).
  4. A economia é registrada em SQLite (src/core/tracking.rs), e é dali que sai o painel do rtk gain.

Algumas peças merecem atenção:

  • Filtros TOML em src/filters/: para saídas de texto previsíveis (make, terraform plan, rsync, helm), o filtro é declarativo, baseado em regex por linha. Filtros em Rust ficam para saídas estruturadas (JSON, NDJSON) ou que exigem uma máquina de estados, como as fases do pytest. O CONTRIBUTING.md traz uma tabela clara de quando usar cada um.
  • Regras de reescrita em src/discover/rules.rs e src/discover/registry.rs: é ali que se decide qual comando vira rtk <cmd>.
  • Init por agente em src/hooks/init/: há um arquivo por integração (claude.rs, cursor.rs, codex.rs, gemini.rs e outros). Desde a 0.24 o hook é um "delegador fino" que chama rtk rewrite, então a lógica de reescrita mora no binário e não no script.
  • guard::never_worse(raw, filtered): garante que o RTK nunca emite mais bytes que o comando cru.
  • Fallback: se o filtro falha, a regra do projeto é devolver a saída original. Os hooks saem com código 0 em qualquer erro, para o comando do agente rodar sem modificação.
  • Recuperação: quando um comando falha ou é truncado, o RTK guarda a saída completa e imprime algo como [full output: rtk recall 3f9c2a81d4e7], para o LLM recuperar o conteúdo sem reexecutar o comando.

O projeto tem metas explícitas de menos de 10 ms de inicialização e menos de 5 MB de memória, sem runtime assíncrono e sem I/O de configuração no caminho crítico. O Cargo.toml proíbe unsafe_code e trata warnings como erro.

Como instalar o RTK?

As opções documentadas no README:

# Homebrew (recomendado)
brew install rtk

# Linux/macOS via script (instala em ~/.local/bin)
curl -fsSL https://raw.githubusercontent.com/rtk-ai/rtk/refs/heads/master/install.sh | sh

# Cargo, direto do repositório
cargo install --git https://github.com/rtk-ai/rtk

No Windows existe winget install rtk-ai.rtk, e também há binários pré-compilados nas releases.

Um detalhe que pega muita gente: existe outro projeto chamado rtk no crates.io (Rust Type Kit), que não tem nada a ver com este. Por isso a documentação recomenda cargo install --git em vez de cargo install rtk e pede para validar com:

rtk --version
rtk gain   # se falhar, você instalou o pacote errado

Como ativar o hook no Claude Code?

O comando principal é o rtk init. Para o Claude Code, no modo global:

rtk init -g                 # hook + RTK.md (recomendado)
rtk init -g --auto-patch    # sem prompt, útil em automação
rtk init -g --hook-only     # só o hook, sem RTK.md
rtk init -g --no-patch      # só imprime as instruções para editar à mão
rtk init --show             # verifica a instalação

Segundo o INSTALL.md, o rtk init -g instala o hook em ~/.claude/hooks/rtk-rewrite.sh, cria ~/.claude/RTK.md, adiciona uma referência @RTK.md no ~/.claude/CLAUDE.md e pergunta se pode alterar o ~/.claude/settings.json, guardando um backup em settings.json.bak. Depois disso, é preciso reiniciar o Claude Code. Se você já organiza o agente por projeto, vale cruzar com o que escrevi sobre configurar o Claude Code em projetos Laravel com CLAUDE.md, hooks e comandos: o RTK entra como mais um hook PreToolUse na mesma cadeia.

Para os outros agentes, a sintaxe muda pouco: rtk init -g --agent cursor, rtk init -g --codex, rtk init -g --gemini, rtk init --agent cline. A tabela do README mostra que nem todos têm hook de verdade. Windsurf, Cline, Kilo Code e Kimi recebem apenas um arquivo de regras pedindo que o modelo prefixe os comandos com rtk. Isso depende de o modelo obedecer, o que é bem menos confiável que uma reescrita transparente.

Exemplo de uso no dia a dia

Com o hook ativo, você não muda nada no fluxo. O agente roda git status e recebe a versão compacta. Mas os comandos também funcionam direto no terminal:

rtk git status                  # status agrupado por estado
rtk git diff                    # diff com contexto reduzido
rtk grep "Idempotency-Key" app/ # resultados agrupados por arquivo
rtk read app/Services/Gateway.php -l aggressive  # só assinaturas
rtk test vendor/bin/phpunit     # wrapper genérico: só falhas
rtk err composer install        # só erros e warnings

O rtk test <cmd> e o rtk err <cmd> são os curingas para ferramentas sem filtro dedicado: executam o argv diretamente e mostram só falhas ou só erros. Eles não expandem globs, variáveis nem operadores de shell por padrão. Se precisar de sintaxe de shell, a documentação manda usar rtk run -c '<script>' ou --shell <nome>.

Para ver o efeito acumulado:

rtk gain                 # resumo
rtk gain --history       # histórico por comando
rtk discover             # comandos que poderiam ter sido filtrados

E quando um comando não deve ser mexido, há três saídas: rtk proxy <cmd> roda sem filtro mas registra no histórico, RTK_DISABLED=1 <cmd> pula o hook para aquele comando e o config.toml aceita exclusões permanentes:

[hooks]
exclude_commands = ["curl", "playwright"]

Uma limitação importante: o hook só pega chamadas da ferramenta Bash. As ferramentas nativas do Claude Code, como Read, Grep e Glob, não passam por ele. Se o agente lê arquivos pelo Read, o RTK não economiza nada ali.

Quanto o RTK economiza de verdade?

Aqui o próprio repositório é honesto, e vale ler com atenção. O README insiste que os percentuais medem redução de saída do bash, não da fatura. A saída do shell é só uma parte dos tokens de entrada, que convivem com o system prompt, o histórico e o seu prompt. E os tokens de entrada são só parte do custo, porque os de saída também entram na conta. Além disso, o RTK não traz tokenizador: as contagens são estimadas como bytes / 4, então os percentuais são confiáveis e os números absolutos, aproximados.

O arquivo FIX_PERF.md vai além e documenta um benchmark interno com 10 pares de VMs com o RTK ligado e desligado. Nessa tarefa, a diferença de custo em dólar foi de −0,2%, praticamente empate. O documento atribui isso a comandos extras que o agente rodou para se recuperar de saídas quebradas. Também é um documento de investigação, não uma conclusão final, mas ele mostra que "90% menos saída" não se converte automaticamente em "90% mais barato".

Se a sua preocupação é custo de LLM, as alavancas maiores costumam ser outras, como as que descrevi em prompt caching e Batch API do Claude. Sobre cache, o README afirma que o RTK não quebra o prompt cache do Claude, porque filtra a saída uma única vez e o resultado fica no histórico normalmente.

Quando vale a pena e quando não?

Vale a pena quando:

  1. Suas sessões são dominadas por comandos verbosos: suítes de teste grandes, builds, docker logs, kubectl, git log longo.
  2. O problema principal é contexto estourando ou o agente se perdendo em ruído, mais do que o custo em si.
  3. Você usa um agente com hook real (Claude Code, Cursor, Codex, Gemini CLI, Copilot no VS Code), em que a reescrita é transparente.

Provavelmente não vale quando:

  1. O agente lê arquivos e busca código pelas ferramentas nativas, sem passar pelo Bash.
  2. Seu fluxo depende de pipelines de shell para contar, ordenar e filtrar (mais sobre isso abaixo).
  3. Você usa um agente que só aceita arquivo de regras, em que a ativação depende do modelo lembrar de prefixar rtk.

Cuidados antes de instalar

Como toda ferramenta que se pluga no agente, o RTK roda com as suas permissões e executa comandos em seu nome. Pelo que dá para ver no código e na documentação, ele acessa:

  • Arquivos de configuração do agente: o rtk init -g altera ~/.claude/settings.json (com backup), cria ~/.claude/hooks/rtk-rewrite.sh, ~/.claude/RTK.md e mexe no ~/.claude/CLAUDE.md. Para outros agentes, escreve em ~/.factory/hooks.json, .trae/hooks.json, ~/.gemini/... e equivalentes. Para desfazer: rtk init -g --uninstall.
  • Banco SQLite local: o histórico de comandos e a saída completa de comandos que falharam ou foram truncados ficam guardados para o rtk recall. Se você roda env, curl contra APIs autenticadas ou testes que imprimem credenciais, isso pode parar em disco. O [retriever] mode aceita disabled. Em ambiente que mexe com dado de cliente, o raciocínio é o mesmo que uso para proteger dados e ações em agentes de IA: saiba onde cada saída vai parar.
  • Rede: o Cargo.toml inclui o cliente HTTP ureq, usado pela telemetria. Ela é desativada por padrão e exige opt-in no rtk init ou via rtk telemetry enable. Dá para travar de vez com export RTK_TELEMETRY_DISABLED=1. Um ponto de atenção: o DISCLAIMER.md ainda diz que a coleta é ativa por padrão, contradizendo o README. Na dúvida, rode rtk telemetry status.
  • Instalação via curl | sh: execute só depois de ler o install.sh, ou prefira Homebrew ou cargo install --git.
  • Pipelines: o FIX_PERF.md registra que rtk find src -name "*.rs" | xargs wc -l falhou em todas as VMs do benchmark, porque a saída compacta não é uma lista de caminhos. Registra também um caso pior: cargo clippy ... | tee /tmp/clippy.log gravou o resumo filtrado, e o agente contou zero warnings sem erro nenhum. É um bug de corretude, não de economia. Se você depende de saída parseável por outro programa, adicione esses comandos ao exclude_commands ou use rtk proxy.
  • Formato diferente do original: o projeto diz buscar saídas que pareçam "uma versão mais curta do comando real", mas git push virar ok main é, objetivamente, outro formato. Scripts e CIs que fazem parse de saída não devem passar pelo RTK.

Conclusão prática

Se eu fosse adotar o RTK num projeto Laravel com Claude Code, faria assim: instalaria via Homebrew ou cargo install --git, rodaria rtk init -g --no-patch para revisar o JSON antes de aplicar e começaria com exclude_commands para tudo que alimenta pipe ou parse (find, wc e qualquer coisa que vá para tee). Deixaria [retriever] mode = "disabled" em máquinas com acesso a dados sensíveis e conferiria rtk telemetry status. Depois de uma ou duas semanas, compararia o rtk gain com a fatura real do provedor, não com o painel do próprio RTK. Se o ganho aparecer em contexto mais limpo e menos compactação de conversa, mantenha. Se o agente começar a reexecutar comandos para entender a saída, a economia já foi embora, e o exclude_commands é o lugar de ajustar.