Inteligencia Artificial

Medí si el shunt de Spotify recorta de verdad un 90% de tokens en Claude Code

Autorangel cruz
Publicado
Lectura12 min de lectura
Medí si el shunt de Spotify recorta de verdad un 90% de tokens en Claude Code

Shunt es un plugin de Claude Code, publicado por Spotify, que intercepta las lecturas de archivos grandes antes de que entren al contexto y las delega a un modelo trabajador más barato. Su README declara un ahorro de entre el 82% y el 94% en esas lecturas, con una media del 90%. La cifra es real y está medida. Lo que no dice el anuncio es la otra parte de la cuenta: qué porcentaje de tu contexto son lecturas grandes de archivos. El 90% se aplica solo a eso.

En mi caso, medido sobre 30 días de transcripts reales, la respuesta es 0,366%. El plugin me ahorraría un 0,33% del mes. Así llegué a ese número, y así puedes calcular el tuyo, que puede ser diez veces mayor.

Qué es shunt y cómo funciona

Shunt vive en el repositorio spotify/portal-ai-plugins, con licencia Apache 2.0, escrito en TypeScript y creado el 23 de julio de 2026. Al consultar la API de GitHub el 7 de septiembre de 2026 tenía 203 estrellas y 11 forks. Es el segundo plugin del marketplace, junto al plugin portal del que depende.

La arquitectura son tres capas, en palabras de su propio README: los hooks bloquean, los scripts invocan al modelo trabajador y las skills le explican a Claude cuándo llamarlos. Toda la lógica de intercepción son dos scripts de bash de menos de cuarenta líneas cada uno, así que se puede auditar entera.

El primero se registra como PreToolUse sobre la tool Read:

MIN_LINES="${SHUNT_MIN_LINES:-350}"
 
# Allow targeted reads (offset or limit set) — Claude already knows what it needs
if [ -n "$offset" ] || [ -n "$limit" ]; then
  echo '{"decision": "allow"}'
  exit 0
fi
 
lines=$(wc -l < "$file_path" 2>/dev/null | tr -d ' ' || echo "0")
if [ "$lines" -le "$MIN_LINES" ]; then
  echo '{"decision": "allow"}'
  exit 0
fi

Si el archivo pasa de 350 líneas y la lectura no está acotada con offset o limit, el hook devuelve block con un motivo que redirige a la skill bulk-reader. El umbral se cambia con la variable de entorno SHUNT_MIN_LINES.

El segundo hook cubre la vía de escape obvia, que es leer el archivo con la tool Bash:

# Skip piped commands (cat file | grep) — those are targeted reads
echo "$command" | grep -qE '\|' && { echo '{"decision": "allow"}'; exit 0; }
 
# Skip redirections (cat file > out) — not a read-into-context operation
echo "$command" | grep -qE '>' && { echo '{"decision": "allow"}'; exit 0; }
 
if echo "$command" | grep -qE '^(cat|head|tail|less|more) '; then

Ese último grep define la superficie entera del plugin: solo se intercepta un comando que empiece por cat, head, tail, less o more, y que no contenga ni una tubería ni una redirección. Un sed -n '1,400p' archivo, un grep -A20, un awk o un script de Python que imprime medio archivo pasan sin que el hook los mire. Tiene sentido, porque esos comandos casi siempre son lecturas acotadas, pero cambia el cálculo de tu ahorro.

Cuando el hook bloquea, el trabajo se va a un modo de AiKA a través del registro de acciones del Portal CLI, con una llamada aika:invoke-chat por delegación. Hay dos modos: bulk-reader, que lee varios archivos y responde una pregunta en viñetas, y code-writer, que genera boilerplate contra un archivo de referencia. En el anuncio del blog de ingeniería de Spotify, firmado por Dimitri Mazmanov el 3 de septiembre de 2026, el modelo trabajador de los dos modos de ejemplo es Gemini 2.5 Flash, aunque el modo se resuelve del lado del servidor y el modelo depende de tu instancia de Portal.

Antes del ahorro hay un filtro más duro: shunt necesita una instancia de Spotify Portal con AiKA habilitado. Los prerequisitos del README son jq, el plugin portal y un /portal:setup autenticado contra tu instancia. Si no trabajas en una organización que ya tiene Portal desplegado, el plugin no se instala y el debate sobre el 90% es teórico.

Los benchmarks de Spotify

El README publica los cuatro escenarios que midieron, contra un monorepo Java de 162.000 líneas:

Escenario Líneas Sin shunt Con shunt Ahorro
Archivo grande único 4.014 33.684 tokens 5.737 tokens 82%
Par fuente y test 7.408 75.990 tokens 4.148 tokens 94%
Multiarchivo entre servicios 1.281 16.221 tokens 821 tokens 94%
Code-write 3.667 40.614 tokens más generación 833 líneas a disco sin dato

La media de ahorro en bulk-read que declaran es del 90%. Los números son creíbles y la metodología está en el repositorio: bash evals/run.sh --benchmark los vuelve a medir contra los modos reales.

La columna "Líneas" es la que importa. El escenario más favorable son 7.408 líneas en dos archivos, justo la lectura que shunt existe para evitar y justo la que un monorepo Java de 162.000 líneas produce todo el tiempo. Si tu trabajo no se parece a eso, el ahorro tampoco.

Cómo medir tu propio perfil

Claude Code guarda cada sesión como JSONL en ~/.claude/projects/. Cada bloque tool_use de un mensaje del asistente tiene su tool_result correspondiente en el mensaje de usuario siguiente, emparejados por tool_use_id. Sumando caracteres por nombre de herramienta sale el reparto real de tu contexto.

La forma más rápida de sacar ese reparto es pedírselo a Claude Code, que ya tiene permiso de lectura sobre tus propios transcripts. Este es el prompt que usé, tomado del análisis de ai.rundatarun.io que cito más abajo:

claude "Measure where my Claude Code context actually goes.
Walk every transcript under ~/.claude/projects/*/*.jsonl modified in the last 30 days.
Pair each tool_use block in assistant messages with its tool_result in the following user message by tool_use_id.
Sum result characters by tool name and report each tool as a share of all message content.
For Read results, record line count and character count, then report what fraction of calls and what
fraction of bytes come from results of 350 lines or more. Do the same for Bash results whose command
starts with cat, head, tail, less or more, and separately for all Bash results.
Print one table: tool, calls, chars, share of context, and a second: thresholds of 50, 100 and 350 lines
against calls and bytes for Read and for Bash. Estimate tokens at 4 characters per token and label it an estimate."

Va en inglés a propósito: es el original, y las instrucciones técnicas con nombres de campo literales como tool_use_id sobreviven mejor sin traducir. No sale nada de tu máquina, porque el propio Claude lee los archivos locales y hace las cuentas ahí.

Los tokens salen a cuatro caracteres por token. Es una estimación, no tu factura: el tokenizador real agrupa distinto, y el código y el JSON tienden a gastar más tokens por carácter que la prosa. Para comparar herramientas entre sí sirve, porque el sesgo se aplica parecido a todas.

Dos decisiones de conteo cambian bastante el resultado, así que las digo: cuento el resultado completo de cada herramienta, incluidas las imágenes en base64 que devuelven las tools del navegador, y mido la parte de contexto sobre todo el contenido de mensajes, no solo sobre los resultados de herramientas. Si tu medición cuenta solo texto, o solo tool_result, los porcentajes te van a salir más altos que los míos.

Mis 30 días

Sobre 77 transcripts y 131.964.208 caracteres de contenido de mensajes, unos 33 millones de tokens estimados, el reparto sale así:

Herramienta Llamadas Caracteres Porcentaje del contexto
claude-in-chrome__computer 548 41.268.505 31,27%
claude-in-chrome__browser_batch 170 27.147.578 20,57%
Bash 15.419 19.564.983 14,83%
Read 345 3.844.410 2,91%
WebFetch 317 766.126 0,58%
WebSearch 100 285.261 0,22%
Edit 1.136 208.867 0,16%

Los resultados de herramientas son el 72,2% de todo el contenido de mensajes. Y el 52% de mi contexto son capturas de pantalla del navegador: la tool computer y el browser_batch de la extensión de Chrome devuelven imágenes en base64 dentro del resultado, a razón de unos 95.000 caracteres por llamada. Ahí no hay nada que interceptar con un umbral de líneas.

Read es el 2,91%. Y dentro de ese 2,91%, las lecturas de 350 líneas o más son el 2,9% de las llamadas y el 6,0% de los bytes. Los umbrales completos:

Corpus Mediana ≥50 líneas ≥100 líneas ≥350 líneas
Read (345 calls, 3,84M chars) 45 líneas 47,0% calls / 30,2% bytes 25,2% / 23,4% 2,9% / 6,0%
Bash todo (15.419 calls, 19,56M) 10 líneas 14,3% / 54,3% 5,1% / 31,5% 0,3% / 4,4%
Bash cat y familia (784 calls, 1,91M) 14 líneas 28,7% / 81,2% 17,5% / 65,6% 1,7% / 13,3%

La cuenta final, aplicando exactamente los dos hooks del plugin: las lecturas interceptables son el 0,174% de mi mes por la vía de Read y el 0,193% por la vía de cat y compañía. Total interceptable: 0,366%. Ahorro al 90%: 0,330%. Antes de restar las llamadas al modelo trabajador y la latencia, que el anuncio de Spotify sitúa entre 10 y 30 segundos por respuesta.

Incluso si el plugin interceptara cualquier resultado de Bash de 350 líneas o más, no solo los cinco comandos de lectura, la superficie total subiría al 0,83% del mes y el ahorro al 0,75%.

Otro perfil da un número muy distinto. En un análisis con la misma metodología publicado en ai.rundatarun.io, sobre 574 sesiones y 174,1 millones de caracteres, Bash sale al 28,5% y Read al 14,3%, con una superficie interceptable del 3,48% y un ahorro estimado del 3,1%. Diez veces mi cifra, con la misma herramienta y el mismo umbral. La diferencia no está en el plugin: está en el perfil de uso.

Por qué mi Read es tan pequeño

En mis sesiones, Bash supera a Read por 45 a 1 en número de llamadas. Eso no es normal en una instalación por defecto y tiene una causa concreta: trabajo con instrucciones que empujan a resolver la lectura de archivos con sed -n, grep y head acotados en vez de con la tool Read. Cada llamada devuelve una mediana de 506 caracteres, unas 10 líneas.

El efecto secundario es que las lecturas grandes que shunt intercepta, en mi caso ya no existen: se convirtieron en cientos de lecturas pequeñas y dirigidas. Y las que sobreviven pasan por comandos que el hook no mira, porque llevan tubería o no empiezan por cat.

Hay dos formas de no gastar tokens en lecturas grandes. Una es delegarlas a un modelo barato. La otra es no hacerlas. La segunda es gratis y no añade 30 segundos de latencia, aunque cuesta más disciplina en el prompt.

Dónde está mi gasto real

El corte útil en mi perfil no está en 350 líneas, está en 50. El 14,3% de las llamadas a Bash que devuelven 50 líneas o más aportan el 54,3% de todos los bytes de Bash. En la familia cat, ese 28,7% de llamadas aporta el 81,2% de los bytes. Ahí sí se nota pasar la salida por head -50, contar con wc -l antes de imprimir, o filtrar con grep en lugar de volcar el archivo.

Y por encima de todo eso, las capturas de pantalla. Cada llamada a la tool computer cuesta el equivalente a diez lecturas largas de archivo. Sustituir capturas por get_page_text, find o read_console_messages, que en mi mes juntas no llegan al 0,1% del contexto, recortaría más que cualquier plugin de intercepción de lecturas. Si te interesa el resto del inventario, lo tengo desglosado en cómo ahorrar tokens en Claude Code.

Cuándo sí instalar shunt

El plugin está bien construido: 51 evals en el repositorio, los hooks fallan hacia allow en todos los casos dudosos, hay un tope de payload configurable porque la entrada viaja por argv y el README declara explícitamente qué no se delega. El problema no es la calidad, es que la superficie donde aplica es muy estrecha.

Instálalo si se cumplen las tres condiciones:

  1. Tienes acceso a una instancia de Spotify Portal con AiKA. Sin eso no hay nada que instalar.
  2. Read es una fracción grande de tu contexto, del orden del 40%, con medianas en cientos de líneas. Un monorepo Java, un proyecto Android, cualquier base de código con archivos de miles de líneas.
  3. Tu trabajo dominante es análisis y resumen, no edición ni depuración. El propio anuncio de Spotify cuenta que el modelo trabajador encontró los patrones superficiales pero se le pasó un bug sutil de concurrencia. Para editar, Claude necesita el contenido exacto en contexto.

Si Read te sale por debajo del 10%, como a mí, corre el prompt antes de instalar nada. La cifra del 90% es cierta y sigue siendo irrelevante para tu factura.

Preguntas frecuentes

¿Qué es el plugin shunt de Spotify?

Un plugin de Claude Code, distribuido en el marketplace spotify/portal-ai-plugins bajo Apache 2.0, que usa hooks PreToolUse para bloquear las lecturas de archivos de más de 350 líneas y redirigirlas a un modelo trabajador más barato a través del Portal CLI de Spotify.

¿De verdad ahorra un 90% de tokens?

Sí, en las lecturas que intercepta. El README publica un rango del 82% al 94% sobre cuatro escenarios contra un monorepo Java de 162.000 líneas. Lo que no dice, porque depende de ti, es qué parte de tu contexto son esas lecturas. En mis 30 días fue el 0,366%.

¿Se puede usar shunt sin Spotify Portal?

No. La delegación va por el registro de acciones del Portal CLI con una llamada aika:invoke-chat, y los prerequisitos incluyen un /portal:setup autenticado contra una instancia con AiKA habilitado.

¿Cómo sé cuánto contexto consume cada herramienta en Claude Code?

Parseando los JSONL de ~/.claude/projects/: emparejas cada tool_use con su tool_result por tool_use_id y sumas caracteres por nombre de herramienta. El prompt de este artículo se lo pide a Claude directamente. Para la sesión en curso, /context y /usage dan la foto rápida.

¿Qué modelo usa el trabajador?

En los dos modos de ejemplo del anuncio de Spotify, Gemini 2.5 Flash. Los modos se resuelven del lado del servidor, así que el modelo real lo decide la instancia de Portal contra la que invoques.

¿Cómo cambio el umbral de 350 líneas?

Con la variable de entorno SHUNT_MIN_LINES en el bloque env de tu .claude/settings.json. Bajarlo mete más lecturas en la delegación, a costa de pagar los 10 a 30 segundos de latencia en lecturas cada vez más pequeñas, que es justo el punto donde el propio README dice que la delegación deja de compensar.

Fuentes

¿Tienes un proyecto en mente?

Trabajo con Laravel, WordPress, SEO técnico y servidores MCP. El primer paso es una llamada de descubrimiento, sin costo ni compromiso, donde me cuentas qué necesitas y te digo con honestidad si puedo ayudarte.

Hablemos