rtk: cortar ruido sin cortar señal
Hace unos días rtk iba segundo en lo más visto de GitHub.
La promesa: un proxy de línea de comandos que recorta 60-90% de los
tokens que un asistente de código gasta leyendo git log,
ls, salidas de build, tests. Un binario en Rust, sin
dependencias, que se interpone entre el comando y lo que llega al
contexto del modelo.
Antes de instalar nada, algo no cuadraba: el mismo texto de descripción — palabra por palabra — aparecía copiado en media docena de repositorios distintos, de cuentas distintas. Patrón típico de spam inflando visibilidad, o peor, de binarios maliciosos disfrazados de herramienta de moda.
rtk-ai/rtk) resultó limpio: código
Rust real, licencia Apache 2.0, changelog y tests genuinos. El script de
instalación verifica el checksum SHA-256 del binario, rechaza rutas de
archivo inseguras al descomprimir, y no pide sudo ni
credenciales. Los repos duplicados eran ruido alrededor, no el proyecto
en sí — pero mirar antes de ejecutar un curl | sh
sigue mereciendo la pena, venga de donde venga.
Lo simple funciona
Instalado, lo probé primero contra este mismo repositorio: comandos
reales, no benchmarks ajenos. git log --stat se reduce
66.8%. Un ls -la verboso en node_modules, 82.8%.
Un docker ps, 65%. Donde hay ruido de verdad — cabeceras,
whitespace, líneas repetidas — lo corta bien, y el coste de filtrar es
de milisegundos. Donde ya no había ruido (un build de Astro de cuatro
páginas, un grep con dos resultados), el ahorro es 0%. Nada
raro hasta aquí: hace lo que dice, cuando la entrada es la que espera.
Subir la apuesta
Un repo de cuatro páginas no prueba nada a escala. Así que cloné facebook/react (500 commits reales) y corrí dos
herramientas de seguridad que rtk no soporta de forma
nativa: gitleaks y codeql. Para eso existen
sus comandos genéricos documentados — rtk err y rtk summary, pensados para envolver "cualquier comando" —
así que no es mal uso, es la vía oficial.
gitleaks encontró 5 posibles secretos en el historial
(los cinco resultaron falsos positivos reales — un token de GitHub
marcado en el propio código como "público a propósito", y una clave de
test repetida). rtk err redujo esa salida a un tamaño
cómodo, pero mostrando solo 1 de los 5 hallazgos — los otros 4 quedan
en un log en disco que nadie consulta salvo que sepa que existe.
Con codeql la escala cambia de orden de magnitud: 4471
archivos analizados, 1505 hallazgos reales, 61 de ellos etiquetados
como seguridad (inyección de código, filtración de información entre
ventanas). El SARIF resultante pesa 5.65 MB.
{
"runs": [
{
"results": [
{
"message": { "text": "[Sensitive data] is sent to another window without origin restriction." },
"rule": { "id": "js/cross-window-information-leak" }
}
// ... +1504 more
]
}
]
} Un ejemplo, y "+1504 more". Nadie pegaría 5.65 MB de SARIF crudo en un LLM — hay que comparar contra lo razonable, no contra lo absurdo. Pero "usar rtk para no gastar tokens en output verboso" es exactamente la recomendación que hace su propia documentación para cualquier comando ruidoso. Un agente que la sigue al pie de la letra, sobre el resultado de un escáner de seguridad, ve 1 de 1505 problemas y da la tarea por terminada.
El mismo patrón, tres veces
Monté un test de Vitest con dos fallos a propósito. rtk vitest
no llegó a correrlo: el proyecto usaba pnpm, y un aviso benigno de pnpm
(scripts de build sin aprobar) hizo que rtk abortara antes
de ejecutar nada. Arreglado ese aviso, rtk vitest sí corrió
— pero el resultado pesó más que el crudo (4703 contra 1754 bytes):
expandió rutas internas de node_modules que el reporter de
Vitest ya recorta por defecto.
En React probé lo mismo a escala real: un test roto de verdad, dentro
de su propio wrapper (yarn test → un script en scripts/jest/jest-cli.js). rtk jest no lo
entendió — intentó invocar Jest por su cuenta, ignorando el wrapper del
proyecto, y falló entero sin llegar a los tests. El wrapper genérico
(rtk test yarn test ...) sí ejecutó el comando real, pero
perdió el porqué: mostró qué dos tests fallaron, no el mensaje de error
ni el stack trace que hacía falta para arreglarlos. Añadí violaciones
de ESLint reales al mismo archivo y probé rtk lint — otra
vez ignoró el wrapper propio de React (scripts/tasks/eslint.js),
lanzó ESLint en crudo sobre el monorepo entero en vez del archivo
afectado, y el parseo del JSON resultante falló.
Tres herramientas distintas (test runner, linter, en dos proyectos
distintos), el mismo fallo: cuando el proyecto envuelve su comando con
un script propio — algo muy común en repos grandes — rtk
no lo detecta.
Lo que dice su propia documentación
Antes de escribir nada de esto como hallazgo, tocaba comprobar si ya
estaba avisado. La web de rtk lista con precisión qué
comandos optimiza — jest, vitest, eslint están todos en esa lista — y
dice explícitamente que lo no listado "va por passthrough, sin
cambios". Pero lo que rompimos no es el caso "no soportado": es un
fallo del analizador en comandos que ellos mismos dicen soportar,
cuando el proyecto los invoca a través de su propio wrapper. Su página
de troubleshooting no menciona wrappers, monorepos, ni scripts
personalizados de ningún tipo.
Buscando en sus Pull Requests apareció la explicación: hay soporte
"inteligente" para yarn y para pnpm run <script> en
desarrollo activo, todavía sin fusionar a main. El PR de
yarn (#867) cita telemetría real: 126 comandos yarn sin manejar en 615
sesiones de 30 días — yarn lint 19 veces, yarn vitest 14. Y en la revisión de ese mismo PR, uno de los maintainers encontró,
probando contra un proyecto real (babel/babel), un fallo de la misma
familia que el nuestro: un yarn install que fracasó de
verdad (código de salida 1, build de workspace roto) se colapsó a la
palabra "ok". El código de salida se preservó — pero un
agente viendo "ok" junto a exit 1 no tiene forma de saber
qué se rompió sin volver a correr el comando en crudo.
El contador no mide lo que crees
rtk lleva su propio panel de ahorro (rtk gain).
Su guía de uso publica la fórmula exacta: los tokens de entrada son len(salida_cruda_del_comando) / 4 — pero "salida cruda"
significa lo que rtk mismo capturó al ejecutar, no lo que
produciría el comando real del proyecto medido aparte. En la línea de rtk lint sobre React, el panel registró ~244.000 tokens de
entrada — muchísimo más que el yarn lint real (1155
bytes) — porque lo que de verdad ejecutó fue ESLint sobre el monorepo
entero por el fallo de detección. El 99.8% de "ahorro" que reporta es
real, matemáticamente, contra ese comando equivocado que él mismo
generó. No se puede comparar contra lo que un desarrollador obtendría
tecleando yarn lint, porque nunca llegó a correr eso.
La línea del SARIF de codeql es distinta: ahí sí hay comparación directa, mismo archivo de entrada. El 100% de ahorro que certifica el panel es, literalmente, el mismo hecho que "esconde 1504 de 1505 hallazgos" — no es interpretación, es la misma reducción de bytes vista desde dos ángulos.
Lo que ya sabían otros
Dos issues abiertas en el repositorio, sin resolver, confirman que esto no es un caso aislado de esta prueba:
Shell injection crítica: rtk err/test/summary pasan el comando a sh -c sin escapar, y el hook auto-aprueba cada reescritura sin pedir permiso. Además: el filtro global (~/.config/rtk) no lleva verificación de integridad — el propio informe dice que podría usarse para "esconder hallazgos de vulnerabilidades al LLM". Y en algunos casos rtk no propaga el código de salida de un test fallido: Claude Code puede leer éxito donde hubo fallo.
Un usuario, sin relación con esta prueba, señala que el "60-90%" solo cubre comandos de terminal — no las herramientas Read/Grep/Glob que dominan la mayoría de sesiones — y calcula que el ahorro real sobre una sesión completa probablemente ronda el 10%, no el titular.
El hook, de verdad
La vía "correcta" de integración no es escribir rtk a
mano delante de cada comando: es un hook (rtk init -g) que
reescribe los comandos de Bash de forma transparente. Lo instalé en mi
configuración real de Claude Code — parcheó settings.json
con una copia de seguridad automática, añadió un RTK.md de
diez líneas, nada invasivo — y funcionó exactamente como está
documentado, sin reiniciar nada. Dado el hallazgo de shell injection de
la issue #640, que afecta justo a ese hook, lo desinstalé después de
probarlo.
Conclusión
Nada de esto dice que rtk sea inútil. En los casos que
soporta bien — git, ls, docker, comandos invocados de forma directa —
corta ruido real sin coste apreciable. Pero el titular "60-90%" no
sobrevive intacto a mirar debajo, y no es lo único que importa a la
hora de decidir si algo se instala o no:
El ahorro depende de qué comando, de si el proyecto lo envuelve con un script propio, y el propio contador de la herramienta no está diseñado para avisarte cuando algo salió mal. La diferencia entre creer un número y medirlo tú mismo — con el comando real, a la escala real, contrastado contra la documentación, los PRs y las issues del propio proyecto — es exactamente ese trabajo el que vale la pena antes de escribir sobre cualquier herramienta.