TL;DR
- Os "90%" da Spotify são a média de cenários de leitura em massa medidos em tokens de entrada estimados num monorepo Java. O post não traz valor em dólar nem nota de qualidade.
- Reconstruído no Claude Code padrão (um hook PreToolUse, dois subagentes baratos, uma regra de roteamento de três linhas) e medido no Fastify em quatro cenários e 16 execuções, o padrão cortou o contexto do modelo principal em 59.6% e o custo total em 33.1%.
- Os hooks de bloqueio dispararam zero vezes nas execuções medidas. A economia veio da regra de roteamento no CLAUDE.md; os hooks são a rede de segurança para o dia em que o modelo a ignorar.
- A delegação foi mais lenta todas as vezes, +65.3% de tempo real em média. No cenário pequeno de escrever teste, custou 2.6% a mais.
- Duas armadilhas: hooks também disparam dentro dos subagentes, então isente seus workers, e leituras por intervalo com
sed -npassam direto por um hook que só observacat,headetail. - O resumo do leitor Haiku trouxe erros factuais em duas das oito execuções delegadas. Mantenha o turno de verificação do modelo principal.
O que as medições dizem
O plugin da Spotify, o Shunt, desvia o trabalho em massa do modelo principal por dois "modos": um leitor em massa e um escritor de código, ambos rodando Gemini 2.5 Flash nos exemplos, com o campo model aceitando qualquer modelo configurado na instância do Portal s1. O roteamento tem três camadas. Um hook check-file-size dispara em todo Read e bloqueia arquivos acima de um limite de linhas configurável, 350 por padrão, apontando o modelo para a skill de leitura em massa; um hook check-bash-read pega cat, head, tail, less e more em arquivos grandes, enquanto comandos com pipe passam s1. O código dos hooks e as duas skills estão no repositório público s2, e a verificação de tamanho pode ser lida sozinha s3. Os modos em si vivem no Portal, a plataforma interna da Spotify, e por isso o plugin não roda fora da empresa do jeito que é distribuído s4.
A alegação do benchmark é fraca. A Spotify testou quatro cenários num monorepo Java, "medindo os tokens que o Claude consumiria lendo os arquivos diretamente contra consumir o resumo do leitor em massa", e reporta economia média de leitura em massa de cerca de 90% s1. O próprio post diz que o cenário de escrita de código é mais difícil de medir em tokens, que os resumos dos workers não trazem números de linha confiáveis e por isso a edição não pode ser delegada, que o worker deixou passar um bug sutil de thread-safety que o modelo principal pegou, e que cada delegação soma de 10 a 30 segundos, com o Portal limitando uma invocação a 30 segundos s1. O thread do Hacker News levantou as mesmas dúvidas sobre o que os 90% medem s7.
A reconstrução troca os modos do Portal por dois subagentes do Claude Code cujos arquivos de definição fixam o modelo: um leitor Explore no Haiku e um escritor de código no Sonnet s6. O bloqueio é um hook PreToolUse que devolve a decisão deny no formato JSON de hook atual s5. O repositório testado foi o fastify/fastify no commit ac28821d, 294 arquivos .js/.ts, 78270 linhas, 63 arquivos com mais de 350 linhas. IDs de modelo conforme o JSON da sessão: conversa principal claude-opus-5[1m], leitor claude-haiku-4-5-20251001, escritor claude-sonnet-5. Cada cenário rodou duas vezes por configuração, 16 execuções medidas, sessões claude -p de um único turno com configurações só do projeto para que os dois lados tivessem prompt de sistema idêntico s5.
Onde o padrão ganhou: S2, uma pergunta de grafo de chamadas sobre três arquivos, lib/route.js (691 linhas), lib/reply.js (1090) e lib/request.js (398), foi de um contexto principal médio de 357165.5 tokens para 73440.0 (-79.4%) e de 0.5810500000000001 USD para 0.21823605000000001 USD (-62.4%). Onde não ganhou: S4, escrever um teste para uma fonte de 45 linhas a partir de uma referência de 19, custou 0.29465575 USD sem delegação e 0.3022213 USD com ela (+2.6%), porque o Sonnet é um segundo contexto completo (13004 a 18729 tokens de cache-read) e o modelo principal ainda releu o arquivo gerado e rodou o teste s6.
Três achados pesam mais que as porcentagens. Primeiro, os hooks dispararam zero vezes nas 16 execuções medidas: com a regra de roteamento no CLAUDE.md, o modelo principal rodou wc -l e delegou por conta própria. O único bloqueio observado veio de uma execução de verificação sem CLAUDE.md, em que o modelo teve o Read negado, depois o cat -n, e respondeu só com grep -n sem nunca chamar a ferramenta Agent s5. Segundo, hooks rodam dentro dos subagentes: em duas execuções descartadas o próprio leitor Haiku foi bloqueado pela verificação de tamanho e recorreu a leituras em pedaços com offset/limit. A correção é uma saída case "$agent_type" in Explore|code-writer) exit 0 no topo do hook, com o nome do campo confirmado no stdin registrado em log s5. Terceiro, na configuração de base o modelo principal nunca usou a ferramenta Read. Ele leu cada arquivo pelo Bash (cat -n, sed -n '1,200p', sed -n '200,560p'), então um hook que só observa o Read não pega nada, e um hook de Bash que só casa cat, head e tail sem pipe ainda deixa os intervalos sed -n passarem s3.
A qualidade foi conferida contra a fonte com grep. A base produziu números de linha errados em uma execução do S2 (despejou os arquivos com sed -n sem números de linha e contou à mão). A configuração delegada produziu três erros factuais na outra execução do S2 e dois numa do S3, todos rastreados a tomar o resumo do Haiku ao pé da letra: chamadores errados de buildRequest/buildReply, uma constante não exportada listada como export, um iterador coberto marcado como não coberto. Onde o modelo principal gastou tokens de saída reverificando com grep (S3, 4534 a 4738 tokens de saída), as respostas se sustentaram s6. No cenário de escrita de teste, todo arquivo gerado passou: 12/12, 6/6, 7/7 e 10/10 testes. Um relato no Reddit mostra o modo de falha parente de um modelo principal que dispara workers no modelo errado quando nada o fixa s8, que é o que o hook require-model e o campo model: nos arquivos de agente evitam.
Medições
Médias das 2 execuções por célula. "Main context" é input + cache_creation + cache_read tokens cobrados do modelo principal na sessão, o número comparável aos "tokens no contexto principal" da Spotify. A = Claude Code padrão, B = hook + subagentes + regra no CLAUDE.md.
| cenário | contexto principal A | contexto principal B | variação | saída principal A | saída principal B | variação | custo total A | custo total B | variação | duração A s | duração B s | variação |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| S1 | 88693.0 | 51551.5 | -41.9% | 1424.5 | 1060.5 | -25.6% | 0.13910675 | 0.08653685 | -37.8% | 21.817500000000003 | 43.799499999999995 | +100.8% |
| S2 | 357165.5 | 73440.0 | -79.4% | 3835.0 | 2555.5 | -33.4% | 0.5810500000000001 | 0.21823605000000001 | -62.4% | 51.637 | 129.036 | +149.9% |
| S3 | 303807.5 | 114135.5 | -62.4% | 6192.0 | 4636.0 | -25.1% | 0.451037 | 0.3738534 | -17.1% | 93.321 | 124.64099999999999 | +33.6% |
| S4 | 143431.5 | 121818.0 | -15.1% | 5275.5 | 3340.0 | -36.7% | 0.29465575 | 0.3022213 | +2.6% | 65.7125 | 86.857 | +32.2% |
| all 4 | 223274.375 | 90236.25 | -59.6% | 4181.75 | 2898.0 | -30.7% | 0.366462375 | 0.2452119 | -33.1% | 58.122 | 96.08337499999999 | +65.3% |
Protocolo: dois clones rasos idênticos byte a byte do fastify/fastify em ac28821d; repo-shunt adiciona .claude/ (configurações, dois arquivos de agente, três hooks) e uma regra de roteamento no CLAUDE.md, nada mais. Cada sessão: claude -p "<prompt>" --output-format json --setting-sources project --strict-mcp-config com config MCP vazia, sem --model, timeout de 600 s. Quatro prompts, idênticos nos dois lados: S1 exports de lib/reply.js, S2 grafo de chamadas entre três arquivos de lib, S3 métodos de lib/hooks.js contra a cobertura de test/hooks.test.js, S4 escrever test/head-route.test.js seguindo test/noop-set.test.js. Os números são lidos de modelUsage e total_cost_usd no JSON da sessão, sem arredondar. As respostas foram conferidas contra a fonte com grep; os testes gerados foram rodados com node --test.
Faça isto na segunda
- Rode
wc -lno seu repositório e conte os arquivos com mais de 350 linhas. Se a contagem for perto de zero, pare por aqui: o limite existe porque delegar custa mais do que economiza em arquivos pequenos. - Adicione ao seu CLAUDE.md uma regra de roteamento de três linhas: arquivos acima do limite vão para um subagente leitor, código que segue um padrão vai para um subagente escritor, depuração e arquitetura ficam com o modelo principal. Nas medições, essa regra fez todo o trabalho.
- Crie
.claude/agents/Explore.mdcommodel: haikue.claude/agents/code-writer.mdcommodel: sonnetno frontmatter, para que o modelo do worker fique fixado no arquivo e não entregue ao orquestrador. - Escreva o hook PreToolUse no Read como rede de segurança, devolvendo a decisão deny no formato JSON de hook atual, e faça as primeiras linhas darem exit 0 quando
agent_typefor um dos seus workers. - Estenda o hook de Bash além de
cat,headetail: case intervalossed -necat -nem arquivos grandes, deixe passar comandos com pipe e grep. - Rode uma pergunta real com e sem a pasta
.claude/, comclaude -p --output-format json, e comparetotal_cost_usdeduration_ms, não só a coluna de entrada. - Confira duas respostas delegadas contra a fonte com grep antes de confiar no resumo do leitor; inclua o turno de verificação do modelo principal no orçamento de custo.
- Meça também uma sessão de vários turnos: os resultados de turno único deixam o contexto principal em 50k a 119k tokens contra 84k a 414k sem delegação, então a segunda pergunta deveria começar mais barata, mas isso não foi medido.
Para ir além
- Leia o formato de hook e o campo
agent_typena referência oficial antes de copiar um hook de um post de blog; o formato do deny e os campos no stdin são o que torna possível a isenção dos subagentes s5. - A documentação de subagentes cobre o campo de frontmatter
modele as restrições de ferramentas, que é como manter um leitor somente leitura e barato s6. - A seção "What doesn't work" da própria Spotify é a parte mais útil do post: sem edição delegada (sem números de linha confiáveis nos resumos), sem raciocínio delegado (um bug de thread-safety deixado passar), idas e vindas de 10 a 30 segundos s1.
- O README do Shunt mostra a estrutura de três camadas (hooks, scripts, skills) e os textos das skills que dizem ao modelo quando delegar; a prosa das skills é a parte que vale adaptar, não o hook s2.
- Os modos do Portal são uma camada de configuração sobre um modelo mais um prompt de sistema; a mesma ideia se traduz num arquivo de agente do Claude Code com um campo
models4. - O thread do Hacker News é onde as dúvidas de medição apareceram primeiro, e serve de checklist do que perguntar a qualquer alegação de economia de tokens s7.
- Um thread no Reddit documenta um orquestrador disparando cinco workers no próprio modelo caro; fixe o modelo no arquivo de agente e, se quiser garantia firme, bloqueie chamadas a Agent sem campo
models8.
Fontes
- Portal by Spotify cut my Claude Code token usage by 90%, Spotify Engineering. Por que ler: a alegação original, o design em três camadas e uma seção honesta de limitações que enfraquece a manchete.
- Shunt plugin (spotify/portal-ai-plugins), GitHub. Por que ler: os hooks, scripts e textos de skills reais, curtos o bastante para ler inteiros.
- check-file-size hook source, GitHub. Por que ler: a verificação de 350 linhas em poucas linhas de shell, o modelo para o seu próprio deny.
- Portal Modes documentation, Spotify. Por que ler: o que é um "modo", para ver por que ele equivale a um arquivo de subagente.
- Claude Code hooks reference, Anthropic. Por que ler: o formato de deny atual e os campos do stdin, incluindo o que identifica um subagente.
- Claude Code subagents, Anthropic. Por que ler: o campo de frontmatter
modele as listas de ferramentas permitidas para um worker barato e somente leitura. - Hacker News discussion of the Spotify post, Hacker News. Por que ler: as perguntas sobre o que os 90% medem, feitas antes de alguém medir de novo.
- Fable spawned five Fable agents instead of Opus (r/ClaudeCode), Reddit. Por que ler: o modo de falha que um campo
modelfixado evita.
FAQ
O número de 90% está errado?
Ele mede uma coisa só: tokens de entrada estimados no contexto principal em cenários de leitura em massa de arquivos Java grandes. Numa métrica do mesmo tipo, a reconstrução viu de 41.9% a 79.4% nos cenários de leitura. Ele não diz nada sobre custo, tempo ou qualidade das respostas, e o post não alega o contrário.
Preciso do Portal para conseguir isso?
Não. O roteamento vive numa regra do CLAUDE.md, dois arquivos de agente com modelo fixado e um hook PreToolUse. O Portal fornece os modelos dos workers na Spotify; uma linha model: haiku faz o mesmo trabalho no Claude Code padrão.
Quando delegar custa mais?
Quando os arquivos são pequenos. O cenário de escrever teste para 45 linhas custou 2.6% a mais com delegação, porque o escritor é um segundo contexto completo e o modelo principal ainda releu e testou o resultado. Toda execução delegada também foi mais lenta, +65.3% em média.
Por que o hook nunca disparou?
Porque a regra de roteamento no CLAUDE.md fez o modelo principal checar wc -l e delegar antes de tentar ler. O hook só importa quando o modelo ignora a regra, o que aconteceu na execução de verificação sem CLAUDE.md.
AIDive