<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Grego</title>
    <description>The latest articles on DEV Community by Grego (@yodev_grego).</description>
    <link>https://dev.to/yodev_grego</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3681920%2F8d052aa4-a1fd-4175-b0b1-a479895229da.png</url>
      <title>DEV Community: Grego</title>
      <link>https://dev.to/yodev_grego</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/yodev_grego"/>
    <language>en</language>
    <item>
      <title>Chrome DevTools MCP para agentes: lo probamos y así maneja diálogos y consola ✅ yoDEV Tested</title>
      <dc:creator>Grego</dc:creator>
      <pubDate>Tue, 03 Nov 2026 16:13:28 +0000</pubDate>
      <link>https://dev.to/yodev_grego/chrome-devtools-mcp-para-agentes-lo-probamos-y-asi-maneja-dialogos-y-consola-yodev-tested-7cg</link>
      <guid>https://dev.to/yodev_grego/chrome-devtools-mcp-para-agentes-lo-probamos-y-asi-maneja-dialogos-y-consola-yodev-tested-7cg</guid>
      <description>&lt;h1&gt;
  
  
  Chrome DevTools MCP para agentes: lo probamos y así maneja diálogos y consola ✅ yoDEV Tested
&lt;/h1&gt;

&lt;p&gt;Chrome DevTools MCP 1.12 avisa a tu agente de IA cuando la página abre un alert de JavaScript y conserva la consola al cambiar de ruta. Lo probamos con un Chrome real.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.chrome.com/blog/new-in-devtools-november-2026" rel="noopener noreferrer"&gt;https://developer.chrome.com/blog/new-in-devtools-november-2026&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;✅ yoDEV Tested&lt;/strong&gt; · 3 de noviembre de 2026&lt;/p&gt;

&lt;p&gt;chrome-devtools-mcp 1.12.0 con Chrome for Testing 153 headless en Linux, y el menú de DevTools en Chrome 156 en macOS. Los resultados que reportamos como nuestros salen de esa prueba.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;El post "New in DevTools: November 2026" de Google, publicado el 20 de octubre, abre con una sección llamada &lt;strong&gt;DevTools for Agents&lt;/strong&gt;. A pesar del nombre, casi nada es interfaz nueva de DevTools: son cambios en &lt;code&gt;chrome-devtools-mcp&lt;/code&gt;, el servidor MCP de código abierto que permite a Claude Code, Gemini CLI, Copilot, Cursor y otros agentes controlar e inspeccionar un Chrome real. Lo único nuevo dentro de DevTools es una entrada de menú.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué es Chrome DevTools MCP?
&lt;/h2&gt;

&lt;p&gt;Chrome DevTools MCP es un servidor Model Context Protocol, mantenido por el equipo de Chrome DevTools, que le da a un agente de IA las mismas herramientas que usa un desarrollador front-end a mano: navegar, hacer clic, llenar formularios, leer la consola y el registro de red, tomar snapshots y capturas, grabar trazas de rendimiento y ejecutar Lighthouse. Por dentro usa Puppeteer para controlar el navegador. Tu agente lo lanza en local con &lt;code&gt;npx&lt;/code&gt;, y el servidor arranca y controla su propia instancia de Chrome.&lt;/p&gt;

&lt;p&gt;En la versión que probamos (1.12.0, publicada en npm el 22 de octubre), el servidor expone 32 herramientas, entre ellas &lt;code&gt;click&lt;/code&gt;, &lt;code&gt;fill_form&lt;/code&gt;, &lt;code&gt;handle_dialog&lt;/code&gt;, &lt;code&gt;list_console_messages&lt;/code&gt;, &lt;code&gt;get_css_styles&lt;/code&gt;, &lt;code&gt;list_network_requests&lt;/code&gt;, &lt;code&gt;performance_start_trace&lt;/code&gt;, &lt;code&gt;lighthouse_audit&lt;/code&gt; y &lt;code&gt;take_heapsnapshot&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Lo cubrimos por primera vez cuando salió como public preview en 2025: &lt;a href="https://www.yodev.dev/t/give-your-ai-eyes-introducing-chrome-devtools-mcp/543" rel="noopener noreferrer"&gt;Give your AI eyes: Introducing Chrome DevTools MCP&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué cambió para los agentes en Chrome 155 y 156?
&lt;/h2&gt;

&lt;p&gt;El blog de Chrome lista seis novedades bajo DevTools for Agents:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Manejo de diálogos:&lt;/strong&gt; los diálogos de JavaScript que se abren durante una acción de entrada se manejan automáticamente.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consola persistente:&lt;/strong&gt; el historial de mensajes de consola se conserva en las navegaciones dentro del mismo documento.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inspección de CSS:&lt;/strong&gt; una herramienta nueva, &lt;code&gt;get_css_styles&lt;/code&gt;, devuelve los estilos calculados y las reglas que aplican, con paginación.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Archivo de configuración y control de rutas:&lt;/strong&gt; un archivo para los flags del servidor y raíces de sistema de archivos personalizadas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trazas por partes:&lt;/strong&gt; las grabaciones de rendimiento grandes se procesan por bloques, con un buffer de traza de 1,2 GB por defecto.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Menú de configuración:&lt;/strong&gt; una entrada &lt;strong&gt;Get Chrome DevTools for agents&lt;/strong&gt; en el menú principal de DevTools.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Chrome 155 y 156 están en el canal estable, no solo en Canary o Beta. El servidor se publica en npm con su propio calendario, así que los cambios del servidor los obtienes actualizando el paquete, no actualizando Chrome.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo lo probamos?
&lt;/h2&gt;

&lt;p&gt;Ejecutamos &lt;code&gt;chrome-devtools-mcp@1.12.0&lt;/code&gt; en Linux con Node 22 contra Chrome for Testing 153 en modo headless, usando el SDK oficial de MCP para TypeScript como cliente, el mismo protocolo que habla Claude Code. La página de prueba tenía botones que abren un &lt;code&gt;alert&lt;/code&gt;, un &lt;code&gt;confirm&lt;/code&gt; y un &lt;code&gt;prompt&lt;/code&gt;, y otro que llama a &lt;code&gt;history.pushState&lt;/code&gt;. La entrada de menú la revisamos por separado en Chrome 156.0.8078.80 en macOS.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué pasa cuando la página abre un alert, confirm o prompt de JavaScript?
&lt;/h2&gt;

&lt;p&gt;El servidor detecta el diálogo y le devuelve el control al agente de inmediato, pero no lo acepta ni lo cierra por su cuenta. "Manejado automáticamente" significa eso, y es la decisión correcta.&lt;/p&gt;

&lt;p&gt;Cuando nuestro agente hizo clic en el botón del alert, la llamada a &lt;code&gt;click&lt;/code&gt; respondió en unos 100 ms con:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The element was clicked and it opened a dialog.
# Open dialog
alert: hola desde la página.
Call handle_dialog to handle it before continuing.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hasta que el agente responde, cualquier otra acción falla con &lt;code&gt;Error: A dialog is open&lt;/code&gt;. El agente llama entonces a &lt;code&gt;handle_dialog&lt;/code&gt; con &lt;code&gt;action: "accept"&lt;/code&gt; o &lt;code&gt;"dismiss"&lt;/code&gt;, y puede pasar &lt;code&gt;promptText&lt;/code&gt; para responder a un &lt;code&gt;prompt()&lt;/code&gt;. En nuestra prueba, aceptar un prompt con el texto "Greg" y rechazar un confirm dejó &lt;code&gt;prompt=Greg&lt;/code&gt; y &lt;code&gt;confirm=false&lt;/code&gt; en la consola, tal como se esperaba.&lt;/p&gt;

&lt;p&gt;Por qué importa: el changelog de la versión 1.7.0 corrigió un bloqueo de 180 segundos cuando se abría un diálogo durante una acción. Antes, un &lt;code&gt;alert()&lt;/code&gt; inesperado podía congelar al agente tres minutos. Ahora lo ve en la misma respuesta y decide qué hacer, que es justo lo que quieres cuando el diálogo es un "¿Eliminar esto?".&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿El agente conserva la consola de Chrome al navegar?
&lt;/h2&gt;

&lt;p&gt;Sí en las navegaciones dentro de la página, y sí bajo pedido en las cargas completas.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Navegación en el mismo documento&lt;/strong&gt; (un cambio de &lt;code&gt;#hash&lt;/code&gt; o &lt;code&gt;history.pushState&lt;/code&gt;, que es como la mayoría de los routers de SPA cambian de página): &lt;code&gt;list_console_messages&lt;/code&gt; siguió devolviendo todos los mensajes anteriores. No se perdió nada.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Navegación completa&lt;/strong&gt; a otra URL: la lista por defecto empieza de cero con la página nueva. Con &lt;code&gt;includePreservedMessages: true&lt;/code&gt; devuelve los mensajes de las últimas tres navegaciones, con los IDs de mensaje en secuencia. El flag &lt;code&gt;--maxNavigationSaved&lt;/code&gt; cambia esa ventana, de 1 a 25.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para depurar una app en React o Vue, esto significa que un error registrado en la ruta anterior sigue ahí cuando el agente lo va a buscar.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué devuelve get_css_styles?
&lt;/h2&gt;

&lt;p&gt;Devuelve las reglas CSS que aplican a un elemento, en orden de cascada y con la ubicación en la hoja de estilos. Le pasas el &lt;code&gt;uid&lt;/code&gt; del elemento que obtienes con &lt;code&gt;take_snapshot&lt;/code&gt;. En nuestra prueba, para un botón con una regla de clase y otra dentro de un media query, devolvió primero el bloque &lt;code&gt;@media (min-width: 100px)&lt;/code&gt;, luego la regla &lt;code&gt;.btn&lt;/code&gt; con &lt;code&gt;index:1&lt;/code&gt; como ubicación, y después la hoja de estilos del navegador con las propiedades sobrescritas marcadas como &lt;code&gt;[overloaded]&lt;/code&gt;. Los resultados vienen en páginas de 10 reglas por defecto (&lt;code&gt;pageSize&lt;/code&gt;, &lt;code&gt;pageIdx&lt;/code&gt;), lo que evita que una hoja de estilos grande llene el contexto del agente.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo funciona el nuevo archivo de configuración?
&lt;/h2&gt;

&lt;p&gt;Ahora puedes poner las opciones del servidor en un archivo JSON en lugar de una lista larga de argumentos. El servidor busca, en este orden: un archivo indicado con &lt;code&gt;--config&lt;/code&gt;, luego &lt;code&gt;cd4a.config.json&lt;/code&gt; en &lt;code&gt;$PLUGIN_DATA&lt;/code&gt; cuando corre como plugin de un agente, y luego un archivo global:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;macOS y Linux: ~/.config/cd4a/config.json
Windows:       %LOCALAPPDATA%/Google/cd4a/config.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usa solo el primero que encuentra (no combina archivos) y los flags de la línea de comandos tienen prioridad sobre el archivo. Los nombres de las opciones van en camelCase.&lt;/p&gt;

&lt;p&gt;Probamos el archivo global con:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"headless"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"isolated"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"viewport"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"800x600"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"usageStatistics"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sin ninguna de esas opciones en la línea de comandos, la página reportó una ventana de 800×600 y un navegador headless, así que el archivo se aplicó. La documentación advierte que ni el archivo ni su carpeta deberían ser editables por el agente; si no, el agente podría reescribir sus propios permisos.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué errores vas a encontrar al usarlo?
&lt;/h2&gt;

&lt;p&gt;Hay dos cambios de comportamiento que conviene conocer antes de conectarlo a tus scripts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Todas las herramientas ahora piden un &lt;/strong&gt;&lt;strong&gt;&lt;code&gt;pageId&lt;/code&gt;&lt;/strong&gt;&lt;strong&gt;.&lt;/strong&gt; El enrutamiento por ID de página viene activado por defecto (&lt;code&gt;--pageIdRouting&lt;/code&gt;). Nuestra primera ejecución falló en cada llamada con &lt;code&gt;pageId: Invalid input: expected number&lt;/code&gt;. Agentes como Claude Code leen el esquema de las herramientas y lo resuelven solos, pero si usas el servidor directamente desde un script, llama primero a &lt;code&gt;list_pages&lt;/code&gt; y pasa el ID.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;El acceso a archivos se limita a la carpeta temporal si tu cliente no soporta MCP roots.&lt;/strong&gt; Al arrancar, el servidor avisó que el cliente "did not negotiate the MCP roots capability" y que las herramientas que leen o escriben archivos locales quedan restringidas a la carpeta temporal del sistema. Esto afecta, por ejemplo, a guardar capturas, trazas y heap snapshots en tu proyecto. La solución es permitir carpetas concretas con &lt;code&gt;--filesystemRoot&lt;/code&gt; (se puede repetir) o, solo con un cliente local de confianza, &lt;code&gt;--allowUnrestrictedPaths&lt;/code&gt;. El blog de Google dice que la CLI separada &lt;code&gt;chrome-devtools&lt;/code&gt; activa las rutas sin restricción por defecto; la documentación del servidor MCP indica &lt;code&gt;false&lt;/code&gt; como valor por defecto, que es lo que vimos.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Puede el agente medir el LCP de tu página?
&lt;/h2&gt;

&lt;p&gt;Sí, con una sola llamada. &lt;code&gt;performance_start_trace&lt;/code&gt; con &lt;code&gt;reload: true&lt;/code&gt; y &lt;code&gt;autoStop: true&lt;/code&gt; recargó nuestra página, se detuvo sola después de unos seis segundos y devolvió el LCP (Largest Contentful Paint: 440 ms, divididos en 7 ms de TTFB y 433 ms de retraso de renderizado), el CLS y una lista de insights que el agente puede explorar en detalle. El procesamiento por bloques ocurre por dentro y no se ve desde fuera: con una página de prueba pequeña no podemos verificar el buffer de 1,2 GB ni el troceado, así que eso es la descripción de Google.&lt;/p&gt;

&lt;p&gt;Por defecto, las URLs de las trazas se envían a la API de CrUX de Google para traer datos de usuarios reales. Desactívalo con &lt;code&gt;--no-performance-crux&lt;/code&gt; si pruebas URLs internas.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué hace "Get Chrome DevTools for agents"?
&lt;/h2&gt;

&lt;p&gt;En Chrome 156, la entrada está en el menú de tres puntos de DevTools. Al hacer clic abre el repositorio del proyecto en GitHub. Es un atajo a las instrucciones de instalación, no un instalador dentro de DevTools.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo instalar Chrome DevTools MCP en Claude Code, Gemini CLI y VS Code?
&lt;/h2&gt;

&lt;p&gt;Necesitas Node.js en versión LTS actual, npm y Chrome estable o más reciente.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Claude Code:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/plugin marketplace add ChromeDevTools/chrome-devtools-mcp
/plugin install chrome-devtools-mcp@chrome-devtools-plugins
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Gemini CLI:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gemini extensions &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--auto-update&lt;/span&gt; https://github.com/ChromeDevTools/chrome-devtools-mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Copilot en VS Code:&lt;/strong&gt; ejecuta "Chat: Install Plugin From Source" e ingresa &lt;code&gt;ChromeDevTools/chrome-devtools-mcp&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cualquier otro cliente MCP&lt;/strong&gt; (Cursor, Codex y otros), con el bloque de configuración estándar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"chrome-devtools"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"chrome-devtools-mcp@latest"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Flags útiles para añadir: &lt;code&gt;--isolated&lt;/code&gt; para un perfil temporal que se borra al cerrar el navegador, &lt;code&gt;--headless&lt;/code&gt; para no abrir ventana, &lt;code&gt;--slim&lt;/code&gt; para un conjunto reducido de tres herramientas (navegación, ejecución de scripts y capturas) y &lt;code&gt;--no-usage-statistics&lt;/code&gt; para no enviar datos de uso.&lt;/p&gt;

&lt;p&gt;Una advertencia del propio proyecto: el servidor expone el contenido de su navegador al cliente MCP. No lo apuntes a sesiones con datos que no compartirías con tu agente, y prefiere &lt;code&gt;--isolated&lt;/code&gt; antes que tu perfil de todos los días.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Chrome DevTools MCP o Playwright MCP?
&lt;/h2&gt;

&lt;p&gt;Si tu trabajo es depurar y medir una app en Chrome, Chrome DevTools MCP; si necesitas Firefox o WebKit, Playwright MCP. Según su README, Playwright MCP (de Microsoft) soporta Chromium, Firefox y WebKit, trabaja sobre el árbol de accesibilidad y también tiene herramientas para diálogos (&lt;code&gt;browser_handle_dialog&lt;/code&gt;) y consola (&lt;code&gt;browser_console_messages&lt;/code&gt;); las trazas son opcionales con &lt;code&gt;--caps=devtools&lt;/code&gt; y no menciona Lighthouse ni análisis de rendimiento. Chrome DevTools MCP solo soporta oficialmente Google Chrome y Chrome for Testing, pero trae lo que viene de DevTools: insights de rendimiento con LCP, &lt;code&gt;lighthouse_audit&lt;/code&gt;, heap snapshots y ahora &lt;code&gt;get_css_styles&lt;/code&gt;. Playwright MCP no lo probamos para esta nota.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Vale la pena actualizarlo?
&lt;/h2&gt;

&lt;p&gt;Sí. Los cambios en diálogos y consola resuelven dos situaciones reales en las que un agente se quedaba trabado o ciego al probar una app web, y ambos se comportaron como describe Google en nuestra prueba. El archivo de configuración hace que el setup sea reproducible en todo el equipo. Solo ten en cuenta el &lt;code&gt;pageId&lt;/code&gt; obligatorio y la restricción a la carpeta temporal antes de integrarlo en tus scripts.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Al momento de publicar esta nota, el número de herramientas (32), los valores por defecto y el comportamiento del menú corresponden a la versión 1.12.0 y a Chrome 156; el proyecto publica versiones con frecuencia, así que revisa el changelog antes de depender de un valor por defecto concreto.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;¿Y tú?&lt;/strong&gt; ¿Qué es lo primero que le pedirías revisar a tu agente en el navegador: un error de consola, una petición de red o el rendimiento?&lt;/p&gt;

&lt;p&gt;Relacionado: &lt;a href="https://www.yodev.dev/t/browserskill-como-darle-a-claude-code-tu-navegador-real-con-la-sesion-ya-iniciada/5455" rel="noopener noreferrer"&gt;BrowserSkill: cómo darle a Claude Code tu navegador real con la sesión ya iniciada&lt;/a&gt;&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>mcp</category>
    </item>
    <item>
      <title>Permisos asistidos en GitHub Copilot CLI: el término medio entre aprobar todo y --yolo</title>
      <dc:creator>Grego</dc:creator>
      <pubDate>Fri, 30 Oct 2026 16:26:39 +0000</pubDate>
      <link>https://dev.to/yodev_grego/permisos-asistidos-en-github-copilot-cli-el-termino-medio-entre-aprobar-todo-y-yolo-3l8d</link>
      <guid>https://dev.to/yodev_grego/permisos-asistidos-en-github-copilot-cli-el-termino-medio-entre-aprobar-todo-y-yolo-3l8d</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fow0jku2rgdvyw0xvc0ps.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fow0jku2rgdvyw0xvc0ps.png" alt=" " width="800" height="624"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Los permisos asistidos (assisted permissions) de GitHub Copilot CLI, la app de Copilot y VS Code hacen que un modelo revise cada solicitud del agente y apruebe solo las que considera seguras; el resto te las sigue preguntando a ti. Están disponibles de forma general desde el 26 de octubre.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.blog/changelog/2026-10-26-github-copilot-assisted-permissions-generally-available/" rel="noopener noreferrer"&gt;https://github.blog/changelog/2026-10-26-github-copilot-assisted-permissions-generally-available/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Si usas el agente de Copilot a diario, conoces las dos opciones que había hasta ahora. La aprobación manual es segura, pero te interrumpe cada pocos segundos. El modo allow-all (&lt;code&gt;--allow-all&lt;/code&gt;, &lt;code&gt;--yolo&lt;/code&gt;) elimina las interrupciones y, con ellas, tu control sobre cada acción. Los permisos asistidos son la propuesta de GitHub para el término medio.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué son los permisos asistidos en GitHub Copilot?
&lt;/h2&gt;

&lt;p&gt;Son un modo de permisos en el que un modelo, y no tú, toma la primera decisión sobre las solicitudes elegibles. Según la documentación de GitHub, hay tres tipos de solicitudes elegibles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ejecutar un comando&lt;/li&gt;
&lt;li&gt;acceder a una ruta del sistema de archivos&lt;/li&gt;
&lt;li&gt;abrir una URL&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para cada una, el modelo comprueba si la acción es segura y si está dentro de la autoridad que le diste a Copilot para la tarea. El resultado es uno de dos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Está seguro de que es segura:&lt;/strong&gt; Copilot la aprueba y continúa sin preguntarte.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No está seguro:&lt;/strong&gt; Copilot te pregunta, exactamente como lo haría con aprobación manual.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Algunas cosas quedan fuera de la revisión. Las solicitudes que ya tenías permitidas se ejecutan sin preguntar y sin pasar por el modelo. Las reglas de denegación y las restricciones de la empresa siguen aplicándose. Las demás llamadas a herramientas que las reglas de la empresa obligan a aprobar, y las solicitudes para saltarse el sandbox local, no las revisa el modelo: siguen el flujo normal de permisos de la sesión. Si la revisión no está disponible o no puede evaluar una solicitud, esa solicitud también vuelve al flujo normal.&lt;/p&gt;

&lt;p&gt;El modelo que hace la revisión no es necesariamente el mismo con el que estás conversando. Copilot elige el modelo revisor; si no está disponible, la revisión puede usar el modelo activo de tu sesión. Si usas tu propio proveedor de modelos, la revisión usa siempre el modelo activo de la sesión.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Permisos asistidos, aprobación manual o --yolo?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Modo&lt;/th&gt;
&lt;th&gt;Revisión por modelo&lt;/th&gt;
&lt;th&gt;Cuándo te pregunta&lt;/th&gt;
&lt;th&gt;Supervisión&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Aprobación manual&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;En cada acción que no esté ya permitida (aprobación única o para toda la sesión)&lt;/td&gt;
&lt;td&gt;Máxima&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Permisos asistidos&lt;/td&gt;
&lt;td&gt;Sí, en solicitudes elegibles&lt;/td&gt;
&lt;td&gt;Solo cuando el modelo no está seguro&lt;/td&gt;
&lt;td&gt;Menos interrupciones, sin permiso global&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Allow-all (&lt;code&gt;--allow-all&lt;/code&gt;, &lt;code&gt;--yolo&lt;/code&gt;, &lt;code&gt;/permissions allow-all&lt;/code&gt;, &lt;code&gt;/yolo&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Nunca&lt;/td&gt;
&lt;td&gt;Ninguna por acción&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;La diferencia práctica: allow-all concede la confianza por adelantado para toda la sesión. Los permisos asistidos la conceden solicitud por solicitud, según un juicio sobre esa acción concreta.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo se activan en Copilot CLI, la app y VS Code?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  En Copilot CLI
&lt;/h3&gt;

&lt;p&gt;Dentro de una sesión interactiva:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/permissions assisted&lt;/code&gt; los activa solo para la sesión actual&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/permissions manual&lt;/code&gt; vuelve a la aprobación manual&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/permissions show&lt;/code&gt; muestra el modo actual&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/permissions&lt;/code&gt; sin argumentos abre una lista para elegir&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para que sea el modo por defecto en todas las sesiones interactivas nuevas, añade esto a &lt;code&gt;~/.copilot/settings.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"defaultPermissionMode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"assisted"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cámbialo a &lt;code&gt;"manual"&lt;/code&gt; para volver atrás.&lt;/p&gt;

&lt;p&gt;En ejecuciones no interactivas (scripts, CI), usa el flag o la variable de entorno:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;copilot -p "Fix the failing tests" --assisted-approval
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;COPILOT_ASSISTED_APPROVAL=true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;--assisted-approval&lt;/code&gt; es solo para ejecuciones no interactivas: si lo usas para iniciar una sesión interactiva, el comando termina con un error.&lt;/p&gt;

&lt;h3&gt;
  
  
  En la app de GitHub Copilot
&lt;/h3&gt;

&lt;p&gt;Abre el menú de modo, elige &lt;strong&gt;Tool permissions&lt;/strong&gt; y luego &lt;strong&gt;Assisted&lt;/strong&gt;. Esto también lo guarda como predeterminado para las nuevas sesiones locales. Para cambiar solo la sesión actual, escribe &lt;code&gt;/permissions assisted&lt;/code&gt; en el cuadro de prompt.&lt;/p&gt;

&lt;h3&gt;
  
  
  En VS Code
&lt;/h3&gt;

&lt;p&gt;Selecciona &lt;strong&gt;Assisted permissions&lt;/strong&gt; en el selector de permisos del chat. Según la documentación de VS Code, hay tres condiciones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;La opción no está disponible en sesiones con el harness &lt;strong&gt;Local&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Tienes que elegir aislamiento &lt;strong&gt;Folder&lt;/strong&gt;: las sesiones en &lt;strong&gt;Worktree&lt;/strong&gt; usan siempre &lt;strong&gt;Allow all&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;La primera vez que eliges este nivel, un diálogo de advertencia te pide confirmación.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;El nivel con el que arrancan las sesiones nuevas se define con la configuración &lt;code&gt;chat.permissions.default&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué pasa en modo autopilot y en CI?
&lt;/h2&gt;

&lt;p&gt;En modo autopilot y en ejecuciones no interactivas no hay nadie a quien preguntar, así que las solicitudes que necesitarían tu aprobación se &lt;strong&gt;deniegan&lt;/strong&gt;. La explicación del modelo vuelve a Copilot, para que el agente pruebe otro camino en lugar de quedarse bloqueado.&lt;/p&gt;

&lt;p&gt;Para la automatización, esto es lo más importante: con permisos asistidos, una ejecución desatendida se cierra en negativo ante cualquier cosa sobre la que el modelo no esté seguro.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo se bloquea --yolo para todo el equipo?
&lt;/h2&gt;

&lt;p&gt;Aquí la función se convierte en una herramienta de gobernanza. Los administradores de una empresa pueden usar la configuración gestionada (enterprise-managed settings) para controlar qué modos pueden usar los desarrolladores:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;permissions.disableBypassPermissionsMode: "disable"&lt;/code&gt; bloquea la aprobación incondicional (allow-all) &lt;strong&gt;sin&lt;/strong&gt; desactivar los permisos asistidos&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;permissions.disableAssistedPermissionsMode: true&lt;/code&gt; desactiva los permisos asistidos&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;permissions.defaultMode&lt;/code&gt; define un modo predeterminado gestionado para las sesiones nuevas, que tiene prioridad sobre el &lt;code&gt;defaultPermissionMode&lt;/code&gt; de cada desarrollador&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Los desarrolladores pueden cambiar a cualquier otro modo que la política permita. Si el modo predeterminado configurado no está disponible o está prohibido, la sesión arranca con aprobación manual.&lt;/p&gt;

&lt;p&gt;La primera opción es la interesante. Hasta ahora, un equipo que quería menos interrupciones tenía que tolerar que sus desarrolladores usaran &lt;code&gt;--yolo&lt;/code&gt;. Ahora un administrador puede sacar &lt;code&gt;--yolo&lt;/code&gt; de la mesa y dejar los permisos asistidos como la opción rápida.&lt;/p&gt;

&lt;p&gt;Referencia: &lt;a href="https://docs.github.com/enterprise-cloud@latest/copilot/reference/enterprise-administrators/enterprise-managed-settings#permissions" rel="noopener noreferrer"&gt;https://docs.github.com/enterprise-cloud@latest/copilot/reference/enterprise-administrators/enterprise-managed-settings#permissions&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Es seguro usarlo sin sandbox?
&lt;/h2&gt;

&lt;p&gt;No por sí solo, y GitHub lo dice sin rodeos. Su documentación advierte que el modelo puede equivocarse y aprobar acciones peligrosas o no deseadas, y que la función no sustituye al sandboxing ni a las restricciones de acceso. Menos interrupciones no te quitan la responsabilidad sobre lo que hace Copilot.&lt;/p&gt;

&lt;p&gt;Antes de meter esto en un pipeline, hay dos detalles de la CLI que conviene revisar:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Los flags no se anulan entre sí.&lt;/strong&gt; &lt;code&gt;--assisted-approval&lt;/code&gt; anula &lt;code&gt;--allow-all-tools&lt;/code&gt;, pero &lt;code&gt;--allow-all-paths&lt;/code&gt; y &lt;code&gt;--allow-all-urls&lt;/code&gt; siguen aplicándose. Si combinas los permisos asistidos con &lt;code&gt;--allow-all&lt;/code&gt; o &lt;code&gt;--yolo&lt;/code&gt;, el acceso a rutas y URLs puede quedar sin restricciones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Puede fallar en silencio.&lt;/strong&gt; Si los permisos asistidos no se pueden activar (por ejemplo, porque la configuración de la empresa los bloquea), la CLI escribe una advertencia en la salida de error estándar y cualquier &lt;code&gt;--allow-all-tools&lt;/code&gt; que hayas pasado sigue aplicándose. En ejecuciones automatizadas, revisa stderr en busca de esa advertencia.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Uno más para entornos empresariales: en la CLI, las reglas &lt;code&gt;ask&lt;/code&gt; de la empresa para comandos de shell, lecturas de archivos, escrituras de archivos y URLs pueden darse por satisfechas con la aprobación del modelo. Una regla &lt;code&gt;ask&lt;/code&gt; ya no garantiza que una persona vea la solicitud.&lt;/p&gt;

&lt;p&gt;La configuración sensata es usar permisos asistidos dentro de un entorno aislado, no en lugar de uno. Explicamos cómo activar el sandbox local de Copilot aquí: &lt;a href="https://www.yodev.dev/t/sandbox-local-de-github-copilot-como-activarlo-en-la-cli-la-app-y-vs-code-y-que-no-bloquea/5600" rel="noopener noreferrer"&gt;Sandbox local de GitHub Copilot: cómo activarlo en la CLI, la app y VS Code y qué no bloquea&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿En qué planes de Copilot está disponible?
&lt;/h2&gt;

&lt;p&gt;Al momento de publicar esta nota, ni el changelog ni la documentación de GitHub indicaban en qué planes de Copilot están incluidos los permisos asistidos.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;¿Y tú?&lt;/strong&gt; ¿Qué acción nunca dejarías que un modelo aprobara sin preguntarte?&lt;/p&gt;

&lt;p&gt;Relacionado: &lt;a href="https://www.yodev.dev/t/github-copilot-apuesta-por-la-autonomia-y-construye-el-guardrail-para-contenerla/2225" rel="noopener noreferrer"&gt;GitHub Copilot Apuesta por la Autonomía — Y Construye el Guardrail para Contenerla&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cli</category>
      <category>github</category>
      <category>security</category>
      <category>ai</category>
    </item>
    <item>
      <title>Claude Code Spends ~16% of Your Tokens on a Status Line: How to Measure agent_summary and Turn It Off ✅ yoDEV Tested</title>
      <dc:creator>Grego</dc:creator>
      <pubDate>Fri, 30 Oct 2026 15:20:35 +0000</pubDate>
      <link>https://dev.to/yodev_grego/claude-code-spends-16-of-your-tokens-on-a-status-line-how-to-measure-agentsummary-and-turn-it-1pon</link>
      <guid>https://dev.to/yodev_grego/claude-code-spends-16-of-your-tokens-on-a-status-line-how-to-measure-agentsummary-and-turn-it-1pon</guid>
      <description>&lt;p&gt;Claude Code envía en segundo plano una petición llamada &lt;code&gt;agent_summary&lt;/code&gt; que, según la telemetría de un desarrollador independiente, se llevó el 16,4 por ciento de todo el gasto en tokens y casi 1 de cada 5 peticiones a la API, solo para actualizar una línea de estado de tres a cinco palabras por cada agente en segundo plano. Cada ~30 segundos, por cada agente activo, Claude Code reenvía la transcripción completa de ese agente a su propio modelo (normalmente Opus) y le pide que describa su última acción. Puedes medirlo en tu propia máquina con OpenTelemetry, y un script de precarga para Bun con licencia MIT, &lt;code&gt;no-agent-summary.js&lt;/code&gt;, lo desactiva.&lt;/p&gt;

&lt;p&gt;Fuente: &lt;a href="https://gist.github.com/flamerix-ai/c3905705cc4205e5de3011fa2e74efce" rel="noopener noreferrer"&gt;README y script de no-agent-summary.js en GitHub Gist&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt; yoDEV Tested&lt;/strong&gt; · 29 de octubre de 2026&lt;br&gt;
Probamos &lt;code&gt;no-agent-summary.js&lt;/code&gt; con Claude Code 2.1.312 en macOS 27.0.1 (Apple Silicon), una plataforma que su autor no ha probado, revisamos los binarios Linux x64 de 2.1.312 y 2.1.308 en un sandbox y reprodujimos dos fallos de instalación en Bun 1.4.4. Los resultados que reportamos como nuestros salen de esa prueba.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fworkplace.yodev.dev%2Fapi%2Fworkspaces%2Fefea03b1-669a-4289-94fa-8bbc61ecd64d%2Fblobs%2F48wvclHEH_H0suB6PM0HTSEogWD72Yk_Dw5Pxi0sY8U%3D%3Ftoken%3Defea03b1-669a-4289-94fa-8bbc61ecd64d%253A48wvclHEH_H0suB6PM0HTSEogWD72Yk_Dw5Pxi0sY8U%253D%253A1793377234888%252CMEUCIHbR5jQ4tm6le0V4dyGYq923UV5KFGCnSfWj4CM3clFZAiEAquQkEJv3QhzDzXaNi0hQgUPxoJIas7T8pX%252BxZtI%252BIC4%253D" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fworkplace.yodev.dev%2Fapi%2Fworkspaces%2Fefea03b1-669a-4289-94fa-8bbc61ecd64d%2Fblobs%2F48wvclHEH_H0suB6PM0HTSEogWD72Yk_Dw5Pxi0sY8U%3D%3Ftoken%3Defea03b1-669a-4289-94fa-8bbc61ecd64d%253A48wvclHEH_H0suB6PM0HTSEogWD72Yk_Dw5Pxi0sY8U%253D%253A1793377234888%252CMEUCIHbR5jQ4tm6le0V4dyGYq923UV5KFGCnSfWj4CM3clFZAiEAquQkEJv3QhzDzXaNi0hQgUPxoJIas7T8pX%252BxZtI%252BIC4%253D" width="72" height="72"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;¿Qué es Claude Code y qué son los agentes en segundo plano?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Claude Code es el agente de programación de Anthropic que trabaja desde la terminal: lee tu repositorio, ejecuta comandos y edita archivos. Puede delegar trabajo en &lt;strong&gt;subagentes&lt;/strong&gt; y dejar algunos corriendo &lt;strong&gt;en segundo plano&lt;/strong&gt; (&lt;code&gt;background agents&lt;/code&gt;) mientras tú sigues con otra cosa. El panel de agentes muestra, junto a cada uno, una línea corta que resume qué está haciendo. Esa línea es la que cuesta.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;¿Qué es agent_summary en Claude Code?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;agent_summary&lt;/code&gt; es el &lt;code&gt;query_source&lt;/code&gt; que Claude Code asigna a la petición que escribe ese texto de estado junto a cada agente en segundo plano. La respuesta nunca llega al modelo ni a tu conversación: solo actualiza esa etiqueta.&lt;/p&gt;

&lt;p&gt;Según el autor del script, Flamerix AI:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Está activado por defecto para los agentes en segundo plano en modo interactivo desde la &lt;strong&gt;2.1.232&lt;/strong&gt; (agosto de 2026).&lt;/li&gt;
&lt;li&gt;El intervalo viene de un flag del servidor, limitado a entre 30 y 240 segundos, y el valor por defecto ya es el mínimo de 30.&lt;/li&gt;
&lt;li&gt;No hay ningún ajuste para apagarlo. La opción del SDK &lt;code&gt;agentProgressSummaries&lt;/code&gt; puede encenderlo pero no apagarlo, y la variable no documentada &lt;code&gt;CLAUDE_CODE_AGENT_PROGRESS_SUMMARIES&lt;/code&gt; también solo sirve para activarlo.&lt;/li&gt;
&lt;li&gt;En la 2.1.310 llegó un modo “short” más barato, unos 2.000 tokens de notas en lugar de la transcripción entera, pero viene apagado y solo los flags del servidor pueden cambiarlo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Todo esto es la lectura que hace el autor del código empaquetado, no documentación de Anthropic.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;¿Cuánto suma agent_summary al precio de Claude Code?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;En una semana de uso del autor, &lt;code&gt;agent_summary&lt;/code&gt; costó más que la conversación principal. Las cifras son &lt;strong&gt;autorreportadas&lt;/strong&gt;, salen de su propia exportación de OpenTelemetry y no publicó los datos en bruto:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;&lt;code&gt;query_source = agent_summary&lt;/code&gt;&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Semana antes del hook&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;2 días después&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Parte del gasto de Claude Code&lt;/td&gt;
&lt;td&gt;16,4% (conversación principal: 15,7%)&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Parte de las peticiones a la API&lt;/td&gt;
&lt;td&gt;19,7%&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;De ese gasto, en Opus&lt;/td&gt;
&lt;td&gt;96%&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tokens de entrada por token de salida&lt;/td&gt;
&lt;td&gt;≈ 9.000 : 1&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;“Gasto” aquí es la estimación que hace el propio Claude Code por petición (&lt;code&gt;cost_usd&lt;/code&gt;), no una factura. Si usas un plan de suscripción, lo que pierdes es margen frente a los límites de uso.&lt;/p&gt;

&lt;p&gt;El autor no es el único. El issue &lt;a href="https://github.com/anthropics/claude-code/issues/86879" rel="noopener noreferrer"&gt;#86879&lt;/a&gt; es una petición abierta para tener una forma oficial de desactivar el temporizador, y reúne mediciones de entre el 18 y el 26 por ciento en sesiones distintas, incluida una donde &lt;code&gt;agent_summary&lt;/code&gt; fue el 22,7 por ciento de las peticiones. El coste crece con cuántos agentes en segundo plano tienes y durante cuánto tiempo, no con el trabajo útil, porque cada ciclo reenvía el contexto actual del agente. Un comentarista en la 2.1.276 calculó que un agente con ~380.000 tokens de contexto paga unos 45 millones de tokens leídos de caché por hora solo por su línea de estado.&lt;/p&gt;

&lt;p&gt;La caché de prompts lo suaviza, pero no lo elimina: según el autor, casi todas estas llamadas aciertan en la caché, y la pequeña fracción que falla carga con más de un tercio del coste.&lt;/p&gt;

&lt;p&gt;Al momento de publicar esta nota, el 29 de octubre de 2026, ninguno de los dos issues tenía respuesta de Anthropic, y Anthropic no había confirmado públicamente este comportamiento.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;¿Por qué Claude Code consume tokens en segundo plano sin que lo veas?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Porque estas peticiones no se escriben en las transcripciones de sesión que se guardan en disco. El issue &lt;a href="https://github.com/anthropics/claude-code/issues/104358" rel="noopener noreferrer"&gt;#104358&lt;/a&gt; documenta que las peticiones de fondo (&lt;code&gt;agent_summary&lt;/code&gt;, &lt;code&gt;compact&lt;/code&gt;, las llamadas del clasificador de &lt;code&gt;auto_mode&lt;/code&gt; y otras) se cobran pero no dejan ninguna fila en esos archivos, así que cualquier herramienta que sume transcripciones se queda corta. Quien lo reportó encontró totales entre 1,35 y 2,13 veces por debajo del estado de costes del propio Claude Code, en 14 sesiones con muchos subagentes.&lt;/p&gt;

&lt;p&gt;La exportación de OpenTelemetry es el único lugar donde aparecen.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;¿Cómo ver el consumo de tokens en Claude Code por tipo de petición?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Activa la exportación de &lt;strong&gt;logs&lt;/strong&gt; de OpenTelemetry de Claude Code y agrupa los eventos &lt;code&gt;claude_code.api_request&lt;/code&gt; por &lt;code&gt;query_source&lt;/code&gt;. Según la documentación oficial de Monitoring, el valor detallado de &lt;code&gt;query_source&lt;/code&gt; (como &lt;code&gt;repl_main_thread&lt;/code&gt;, &lt;code&gt;compact&lt;/code&gt; o el nombre de un subagente) vive en el evento &lt;code&gt;api_request&lt;/code&gt;. Las métricas &lt;code&gt;claude_code.cost.usage&lt;/code&gt; y &lt;code&gt;claude_code.token.usage&lt;/code&gt; solo llevan una categoría gruesa (&lt;code&gt;main&lt;/code&gt;, &lt;code&gt;subagent&lt;/code&gt; o &lt;code&gt;auxiliary&lt;/code&gt;), así que con métricas solas no puedes aislar &lt;code&gt;agent_summary&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;La configuración mínima, según la documentación:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CLAUDE_CODE_ENABLE_TELEMETRY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OTEL_LOGS_EXPORTER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;otlp
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OTEL_EXPORTER_OTLP_PROTOCOL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;grpc
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OTEL_EXPORTER_OTLP_ENDPOINT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost:4317
claude

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apunta el endpoint al colector OTLP que ya uses y suma &lt;code&gt;cost_usd&lt;/code&gt; (o los atributos de tokens) por &lt;code&gt;query_source&lt;/code&gt;. Si no llega nada, la documentación recomienda arrancar Claude Code con &lt;code&gt;claude --debug-file &amp;lt;ruta&amp;gt;&lt;/code&gt; y buscar errores &lt;code&gt;[3P telemetry]&lt;/code&gt; en ese log.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Una comprobación rápida sin colector:&lt;/strong&gt; el método del propio autor cuenta las líneas &lt;code&gt;[AgentSummary] Forking&lt;/code&gt; de un log de &lt;code&gt;--debug-file&lt;/code&gt; mientras corre un subagente en segundo plano. Si esa línea aparece cada ~30 segundos por agente, estás pagando por ella.&lt;/p&gt;

&lt;p&gt;Si también usas Codex, tenemos la guía equivalente: &lt;a href="https://www.yodev.dev/t/como-ver-el-consumo-de-tokens-en-codex-cli-usage-modo-fullscreen-y-voz-por-defecto/5457" rel="noopener noreferrer"&gt;Cómo ver el consumo de tokens en Codex CLI&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;¿Cómo desactivar agent_summary en Claude Code?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Con &lt;code&gt;no-agent-summary.js&lt;/code&gt;, una precarga para Bun de unas 80 líneas. El binario nativo de Claude Code es un programa de Bun compilado, y Bun lee opciones extra de la variable de entorno &lt;code&gt;BUN_OPTIONS&lt;/code&gt;, así que el script se carga antes que Claude Code sin modificar el binario.&lt;/p&gt;

&lt;p&gt;El script envuelve &lt;code&gt;setTimeout&lt;/code&gt; y &lt;code&gt;setInterval&lt;/code&gt;. Cuando el código del callback de un temporizador contiene una de sus dos anclas, la línea de log &lt;code&gt;[AgentSummary] Timer fired&lt;/code&gt; o el id &lt;code&gt;agent_summary&lt;/code&gt;, devuelve un temporizador inerte en lugar de armarlo. Todos los demás temporizadores pasan sin cambios.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Dos reglas que el README no dice.&lt;/strong&gt; Escribe &lt;code&gt;--preload=/ruta&lt;/code&gt;, no &lt;code&gt;--preload /ruta&lt;/code&gt;: con un espacio, poner &lt;code&gt;BUN_OPTIONS&lt;/code&gt; de forma global rompe todos los subcomandos de &lt;code&gt;bun&lt;/code&gt;. Y guarda el hook en una ruta &lt;strong&gt;sin espacios&lt;/strong&gt;, porque &lt;code&gt;BUN_OPTIONS&lt;/code&gt; no puede llevarlos, la entrecomilles como la entrecomilles. Reprodujimos los dos fallos (ver “¿Qué se rompe al instalarlo?”, más abajo). Todos los comandos de aquí usan la forma con &lt;code&gt;=&lt;/code&gt; y la ubicación que propone el README, &lt;code&gt;~/.local/share/&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;



&lt;p&gt;&lt;strong&gt;Para una sola sesión&lt;/strong&gt; (adaptado del resumen del README):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://gist.githubusercontent.com/flamerix-ai/c3905705cc4205e5de3011fa2e74efce/raw/no-agent-summary.js &lt;span class="nt"&gt;-o&lt;/span&gt; ~/.local/share/no-agent-summary.js
claude daemon stop &lt;span class="nt"&gt;--any&lt;/span&gt;
&lt;span class="nv"&gt;BUN_OPTIONS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUN_OPTIONS&lt;/span&gt;:+&lt;span class="nv"&gt;$BUN_OPTIONS&lt;/span&gt;&lt;span class="p"&gt; &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;--preload=&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.local/share/no-agent-summary.js"&lt;/span&gt; claude

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;De forma permanente&lt;/strong&gt;, añade esto a &lt;code&gt;~/.profile&lt;/code&gt;, &lt;code&gt;~/.bashrc&lt;/code&gt; o &lt;code&gt;~/.zshrc&lt;/code&gt;, con la ruta absoluta:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;BUN_OPTIONS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BUN_OPTIONS&lt;/span&gt;:+&lt;span class="nv"&gt;$BUN_OPTIONS&lt;/span&gt;&lt;span class="p"&gt; &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;--preload=/ruta/absoluta/no-agent-summary.js"&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Después reinicia el daemon para que los procesos en segundo plano lo tomen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude daemon stop &lt;span class="nt"&gt;--any&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ese reinicio importa. El daemon, el pty host y las sesiones &lt;code&gt;bg-spare&lt;/code&gt; precalentadas heredan el entorno de lo que arrancó el daemon, así que un daemon iniciado antes de definir &lt;code&gt;BUN_OPTIONS&lt;/code&gt; sigue creando sesiones sin el hook. Las ejecuciones sin interfaz (&lt;code&gt;claude -p&lt;/code&gt;, cron, CI, integraciones con editores) también necesitan la variable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Qué cambia:&lt;/strong&gt; la línea de estado de cada agente en el panel deja de actualizarse. Los subagentes, los agentes en segundo plano, los skills bifurcados y las sesiones en segundo plano siguen funcionando con normalidad.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;¿Se puede sin parche?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;En parte. El README indica que &lt;code&gt;CLAUDE_CODE_FORK_SUBAGENT=0&lt;/code&gt; y &lt;code&gt;CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1&lt;/code&gt; también detienen los resúmenes, pero solo porque apagan por completo los subagentes bifurcados o los agentes en segundo plano. La variable que se suele sugerir, &lt;code&gt;DISABLE_NON_ESSENTIAL_MODEL_CALLS&lt;/code&gt;, ni siquiera existe en el binario: la buscamos en las dos versiones que probamos y no aparece ni una vez.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;¿Qué se rompe al instalarlo?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Hay tres maneras distintas de que salga mal. Las dos primeras las reprodujimos nosotros.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Un BUN_OPTIONS global con espacio rompe Bun&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Un comentario en el gist reportó que &lt;code&gt;BUN_OPTIONS="--preload /ruta"&lt;/code&gt; hace fallar &lt;code&gt;bun install&lt;/code&gt;, &lt;code&gt;add&lt;/code&gt;, &lt;code&gt;test&lt;/code&gt;, &lt;code&gt;build&lt;/code&gt; y &lt;code&gt;x&lt;/code&gt; con &lt;code&gt;Script not found "install"&lt;/code&gt; (y similares) en Bun 1.4.3. La causa es el analizador de argumentos de Bun: cualquier flag con valor colocado antes del subcomando lo provoca; &lt;code&gt;bun --define x:1 install&lt;/code&gt; falla igual.&lt;/p&gt;

&lt;p&gt;Lo reprodujimos en Bun 1.4.4:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;&lt;code&gt;BUN_OPTIONS&lt;/code&gt;&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;&lt;code&gt;bun install&lt;/code&gt;&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;&lt;code&gt;bun test&lt;/code&gt;&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;&lt;code&gt;bun build&lt;/code&gt;&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;&lt;code&gt;bun x&lt;/code&gt;&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--preload /ruta&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Script not found "install"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--preload=/ruta&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;sin definir&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Con &lt;code&gt;--preload=/ruta&lt;/code&gt;, el hook sigue cargando en Claude Code 2.1.312 y 2.1.308. El arreglo no cuesta nada del lado de Claude Code. En macOS vimos lo mismo con el Bun independiente 1.3.13.&lt;/p&gt;

&lt;p&gt;El mismo comentarista también restringió la comprobación de instalación del script para que solo actúe dentro del binario de Claude Code, y así otros binarios de Bun compilados en la máquina no vean sus temporizadores envueltos. Tal como está publicado, el script solo verifica que corre dentro de algún binario de Bun compilado. Esa modificación no la probamos.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Un espacio en la ruta del hook impide que Claude Code arranque&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Bun separa &lt;code&gt;BUN_OPTIONS&lt;/code&gt; por espacios, así que una ruta como &lt;code&gt;~/mis pruebas/no-agent-summary.js&lt;/code&gt; se parte en dos. Nos pasó en nuestra primera prueba en macOS, desde una carpeta cuyo nombre tenía un espacio. Bun leyó la segunda mitad como un flag suelto (&lt;code&gt;error: Invalid Argument '-s'&lt;/code&gt;), y todos los comandos que definían &lt;code&gt;BUN_OPTIONS&lt;/code&gt;, &lt;code&gt;claude&lt;/code&gt; incluido, imprimieron la ayuda de Bun y terminaron.&lt;/p&gt;

&lt;p&gt;Entrecomillar no sirve. En el sandbox probamos la ruta tal cual, entre comillas dobles, entre comillas simples y con los espacios escapados con barra invertida. Las cuatro fallaron con &lt;code&gt;preload not found&lt;/code&gt;, con la ruta cortada en el primer espacio. El archivo del hook tiene que estar en una ruta sin espacios.&lt;/p&gt;

&lt;p&gt;Al menos este fallo es visible: Claude Code se niega a arrancar, en lugar de correr sin el hook.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. Cualquier actualización de Claude Code puede deshacerlo en silencio&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;El hook reconoce el temporizador del resumen por texto dentro de su callback. Si una actualización renombra la línea de log o el id, saca esos textos fuera del callback, pasa el callback por &lt;code&gt;.bind()&lt;/code&gt; o mueve el temporizador a una API que el script no envuelve, el hook no detecta nada y los resúmenes vuelven sin avisar. El autor lo llama “fail-open”.&lt;/p&gt;

&lt;p&gt;Por eso conviene volver a verificarlo después de cada actualización:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;BUN_OPTIONS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"--preload=&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.local/share/no-agent-summary.js"&lt;/span&gt; &lt;span class="nv"&gt;CC_AGENT_SUMMARY_LOG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/tmp/nas.log claude &lt;span class="nt"&gt;--version&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cat&lt;/span&gt; /tmp/nas.log

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deberías ver &lt;code&gt;preload active mode=off …&lt;/code&gt;. Después, con las mismas variables, deja correr un subagente en segundo plano un minuto o dos: el log debería mostrar &lt;code&gt;summary timer #1 suppressed&lt;/code&gt;. Si exportas OpenTelemetry, que &lt;code&gt;query_source = agent_summary&lt;/code&gt; se mantenga en cero es la única comprobación que detecta todos los modos de fallo.&lt;/p&gt;

&lt;p&gt;Para una prueba A/B, &lt;code&gt;CC_AGENT_SUMMARY_MODE=pass&lt;/code&gt; carga el hook pero deja armados todos los temporizadores. Los resúmenes vuelven, lo que demuestra que es el modo &lt;code&gt;off&lt;/code&gt; el que los elimina.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ten en cuenta también:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Plataforma:&lt;/strong&gt; el autor solo lo probó en Linux. Nuestra prueba, más abajo, muestra que funciona en macOS (Apple Silicon) con la 2.1.312. En Windows, según el autor, lo más probable es que el hook nunca se instale.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Términos de servicio:&lt;/strong&gt; el README advierte que cambiar el comportamiento de un cliente en ejecución puede entrar en conflicto con los términos del servicio con el que lo usas, y deja esa comprobación en tus manos.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;¿Qué probamos en yoDEV?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Hicimos dos pruebas el 29 de octubre de 2026.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;En macOS: ¿el hook realmente detiene agent_summary?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Entorno:&lt;/strong&gt; Claude Code 2.1.312, el binario nativo &lt;code&gt;arm64&lt;/code&gt; con Bun 1.4.4 integrado, en macOS 27.0.1 sobre Apple Silicon. El hook se descargó desde la URL del propio README; su sha256 es &lt;code&gt;dc6699da…59f7&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Seguimos el método del autor: tres sesiones sin interfaz (&lt;code&gt;claude -p --model haiku&lt;/code&gt;, con los resúmenes forzados mediante &lt;code&gt;CLAUDE_CODE_AGENT_PROGRESS_SUMMARIES=1&lt;/code&gt;). En cada una, un subagente ejecutó ocho pasos de 20 segundos, y contamos las líneas &lt;code&gt;[AgentSummary] Forking&lt;/code&gt; en el log de &lt;code&gt;--debug-file&lt;/code&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Ejecución&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Disparos del temporizador&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Bifurcaciones de resumen&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Duración&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Tarea completada&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sin hook&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;181 s&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hook en modo &lt;code&gt;pass&lt;/code&gt; (control)&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;220 s&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hook en modo &lt;code&gt;off&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;212 s&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;El resultado coincide con el del autor en Linux para la 2.1.312: la bifurcación ocurre, cargar el hook por sí solo no cambia nada, y el modo &lt;code&gt;off&lt;/code&gt; la elimina. El subagente completó los ocho pasos en todas las ejecuciones.&lt;/p&gt;

&lt;p&gt;El log del hook en modo &lt;code&gt;off&lt;/code&gt; muestra el mecanismo: un temporizador suprimido, unos 26 segundos después de empezar. Un temporizador suprimido nunca se dispara, así que nunca se vuelve a armar, y el log de depuración no muestra ninguna línea &lt;code&gt;Timer fired&lt;/code&gt; ni &lt;code&gt;Forking&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;El log sin hook también muestra qué se paga en cada una de esas llamadas. Cada bifurcación reenvió el contexto completo del subagente (23 mensajes en el primer ciclo) para producir un resumen como &lt;em&gt;“Running sleep 20, call 1 of 8”&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;En un sandbox Linux x64: ¿encaja con las versiones actuales?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Con el paquete de npm &lt;code&gt;@anthropic-ai/claude-code-linux-x64&lt;/code&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Comprobación&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;2.1.312 (latest)&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;2.1.308 (stable)&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;El prefijo sha256 coincide con la tabla del README&lt;/td&gt;
&lt;td&gt;&lt;code&gt;4f4178ce41d8&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;356733f185fa&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anclas del hook presentes en el binario&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;La precarga carga y envuelve los temporizadores&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Existe &lt;code&gt;claude daemon stop --any&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;DISABLE_NON_ESSENTIAL_MODEL_CALLS&lt;/code&gt; en el binario&lt;/td&gt;
&lt;td&gt;0 apariciones&lt;/td&gt;
&lt;td&gt;0 apariciones&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Lo que no medimos:&lt;/strong&gt; la parte del gasto. Nuestras ejecuciones demuestran que la llamada desaparece, pero no verifican la cifra del 16,4 por ciento del autor, que depende de cuántos agentes en segundo plano uses y durante cuánto tiempo. Por eso la sección de medición va primero.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;¿Vale la pena instalarlo?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Si dejas agentes en segundo plano corriendo durante mucho tiempo, sobre todo sin supervisión o en CI, donde nadie mira la línea de estado, mide primero. Si &lt;code&gt;agent_summary&lt;/code&gt; aparece como una parte grande de tus eventos &lt;code&gt;api_request&lt;/code&gt;, el hook es un script pequeño y legible, con un interruptor de control (modo &lt;code&gt;pass&lt;/code&gt;) y una forma clara de verificarlo. Instálalo con &lt;code&gt;--preload=&lt;/code&gt; en una ruta sin espacios, reinicia el daemon y vuelve a comprobarlo después de cada actualización de Claude Code.&lt;/p&gt;

&lt;p&gt;Si trabajas sobre todo en una sola sesión en primer plano, sin agentes en segundo plano, puede que no estés pagando nada de esto, y eso es justo lo que la medición te va a decir.&lt;/p&gt;

&lt;p&gt;Si quieres entender mejor qué estás pagando en cada petición, empieza por &lt;a href="https://www.yodev.dev/t/que-son-los-tokens-en-la-ia-y-por-que-te-cobran-por-ellos/5141" rel="noopener noreferrer"&gt;qué son los tokens en la IA y por qué te cobran por ellos&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;¿Y tú?&lt;/strong&gt; ¿Qué parte de tu consumo de tokens en Claude Code te sorprendió más cuando lo mediste?&lt;/p&gt;

</description>
      <category>agents</category>
      <category>llm</category>
      <category>claude</category>
      <category>ai</category>
    </item>
    <item>
      <title>Tsrs, Probado: el Port de TypeScript 7 a Rust Fue Hasta 6,5x Más Rápido que tsc (y te Pasa a 7.1) ✅ yoDEV Tested</title>
      <dc:creator>Grego</dc:creator>
      <pubDate>Sun, 25 Oct 2026 15:48:19 +0000</pubDate>
      <link>https://dev.to/yodev_grego/tsrs-probado-el-port-de-typescript-7-a-rust-fue-hasta-65x-mas-rapido-que-tsc-y-te-pasa-a-71-187</link>
      <guid>https://dev.to/yodev_grego/tsrs-probado-el-port-de-typescript-7-a-rust-fue-hasta-65x-mas-rapido-que-tsc-y-te-pasa-a-71-187</guid>
      <description>&lt;p&gt;tsrs es un port a Rust del compilador de TypeScript 7 que ya puedes instalar desde npm, y en nuestra prueba fue entre 2,9x y 6,5x más rápido que &lt;code&gt;tsc&lt;/code&gt; 7.0.2, con entre 2x y 4,2x menos memoria. Cloudflare, VoidZero y Max Schwenk, de Owner.com, lo anunciaron el 20 de octubre de 2026. El proyecto se incuba dentro del toolchain Oxc y se desarrolla en colaboración con el equipo de TypeScript.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.cloudflare.com/typescript-rust-port/" rel="noopener noreferrer"&gt;https://blog.cloudflare.com/typescript-rust-port/&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;✅ yoDEV Tested&lt;/strong&gt; · 20 de octubre de 2026 Ejecutamos tsrs 0.18.0 frente a tsc 7.0.2, tsc-rs 0.7.0 y bun check 1.4.3 sobre zod, playwright y hono, en una máquina Linux de 2 vCPU. Los resultados que reportamos como nuestros salen de esa prueba.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  ¿Qué es tsrs, el compilador de TypeScript en Rust?
&lt;/h2&gt;

&lt;p&gt;tsrs es un reemplazo directo (&lt;em&gt;drop-in replacement&lt;/em&gt;) del compilador de TypeScript 7 (&lt;code&gt;tsc&lt;/code&gt;) y de su servidor de lenguaje, escrito en Rust. Lee tu &lt;code&gt;tsconfig.json&lt;/code&gt; actual, emite JavaScript y declaraciones igual que &lt;code&gt;tsc&lt;/code&gt;, y admite &lt;code&gt;--watch&lt;/code&gt;, &lt;code&gt;-b&lt;/code&gt; y un modo LSP para editores. Su objetivo declarado es 100 por ciento de conformidad con TypeScript, con menos memoria y un &lt;em&gt;type checking&lt;/em&gt; más rápido.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No es un fork.&lt;/strong&gt; El anuncio de Cloudflare lo deja claro: el equipo de TypeScript sigue controlando el diseño del lenguaje, y tsrs debe seguir las decisiones de upstream, no tomar las suyas. Hoy sigue la rama principal de microsoft/TypeScript, y cada versión del paquete indica el commit que porta: &lt;code&gt;0.18.0-ts7.1.0-dev.20260929&lt;/code&gt; es tsrs 0.18.0 siguiendo TypeScript &lt;code&gt;7.1.0-dev.20260929&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Dos datos que conviene saber desde el principio:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lo escribieron agentes de IA.&lt;/strong&gt; Max Schwenk, Head of AI Developer Experience en Owner.com, lo empezó el 30 de septiembre preguntándose si Claude Opus 5.5 podía portar el compilador a partir del código en Go de TypeScript. Según su propio relato, no escribió código él mismo: los agentes trabajaron con la suite de conformidad de TypeScript como especificación. El 19 de octubre el proyecto pasó a &lt;code&gt;oxc-project/tsrs&lt;/code&gt;, bajo Cloudflare y VoidZero.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Por qué lo construyó Owner.com.&lt;/strong&gt; Su código principal tiene unos 37.000 archivos TypeScript. Con TypeScript 7.0, un chequeo con un solo hilo tardaba 80 segundos y usaba 19 GiB de memoria. Con tsrs, Owner reporta unos 7 segundos en CI.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Licencia: Apache-2.0, como derivado de TypeScript. El README aclara que no está afiliado ni respaldado por Microsoft.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo instalar tsrs?
&lt;/h2&gt;

&lt;p&gt;Agrégalo como dependencia de desarrollo y ejecútalo donde ejecutarías &lt;code&gt;tsc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm add &lt;span class="nt"&gt;-D&lt;/span&gt; tsrs
pnpm &lt;span class="nb"&gt;exec &lt;/span&gt;tsrs &lt;span class="nt"&gt;--noEmit&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Con npm, el anuncio de Cloudflare usa:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;tsrs
npx tsrs

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para probarlo sin agregarlo al proyecto: &lt;code&gt;pnpm dlx tsrs -p .&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Comandos útiles de la documentación de uso:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm &lt;span class="nb"&gt;exec &lt;/span&gt;tsrs &lt;span class="nt"&gt;-p&lt;/span&gt; path/to/project           &lt;span class="c"&gt;# compilar&lt;/span&gt;
pnpm &lt;span class="nb"&gt;exec &lt;/span&gt;tsrs &lt;span class="nt"&gt;-p&lt;/span&gt; path/to/project &lt;span class="nt"&gt;--noEmit&lt;/span&gt;  &lt;span class="c"&gt;# solo type check&lt;/span&gt;
pnpm &lt;span class="nb"&gt;exec &lt;/span&gt;tsrs &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--extendedDiagnostics&lt;/span&gt;   &lt;span class="c"&gt;# contadores y tiempos&lt;/span&gt;
pnpm &lt;span class="nb"&gt;exec &lt;/span&gt;tsrs &lt;span class="nt"&gt;--version&lt;/span&gt;
tsrs &lt;span class="nt"&gt;--watch&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;                           &lt;span class="c"&gt;# recompila al guardar&lt;/span&gt;
tsrs &lt;span class="nt"&gt;--lsp&lt;/span&gt; &lt;span class="nt"&gt;-stdio&lt;/span&gt;                           &lt;span class="c"&gt;# servidor de lenguaje para el editor&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El launcher de npm instala un binario nativo para tu plataforma como dependencia opcional &lt;code&gt;@tsrs/&amp;lt;os&amp;gt;-&amp;lt;arch&amp;gt;&lt;/code&gt;. También hay un playground en el navegador (tsrs-playground.void.app) y una build en WebAssembly, &lt;code&gt;@tsrs/wasm&lt;/code&gt;, para Node y navegadores.&lt;/p&gt;

&lt;p&gt;Lo que todavía no hace: &lt;code&gt;--init&lt;/code&gt; y &lt;code&gt;--showConfig&lt;/code&gt; no están soportados, así que mantén &lt;code&gt;tsc&lt;/code&gt; a mano para generar la configuración.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿tsrs es más rápido que tsc? Nuestro benchmark
&lt;/h2&gt;

&lt;p&gt;Sí: en nuestra prueba fue entre 2,9x y 6,5x más rápido que &lt;code&gt;tsc&lt;/code&gt; 7.0.2 (el compilador en Go, también conocido como &lt;code&gt;tsgo&lt;/code&gt;). La cifra de "hasta 8x más rápido" con alrededor de 70 por ciento menos memoria es el benchmark propio de Cloudflare: tsrs contra TypeScript 7.0 con el mismo número de &lt;em&gt;workers&lt;/em&gt; de chequeo. El benchmark publicado por el proyecto usó 17 proyectos en una máquina de CI de 16 vCPU y 63 GB, y el código está en el repo, en &lt;code&gt;bench/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Queríamos números en una máquina más chica, así que repetimos el montaje de nuestra prueba de bun check: los mismos tres repos, 2 vCPU, 7 GB de RAM, una ejecución de calentamiento más cinco medidas (diez en hono), mediana del tiempo total y pico de memoria.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Proyecto&lt;/th&gt;
&lt;th&gt;tsc 7.0.2&lt;/th&gt;
&lt;th&gt;tsrs 0.18.0&lt;/th&gt;
&lt;th&gt;tsc-rs 0.7.0&lt;/th&gt;
&lt;th&gt;bun check 1.4.3&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;zod (593 errores)&lt;/td&gt;
&lt;td&gt;5,82 s · 1.118 MB&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0,90 s · 266 MB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1,46 s · 632 MB&lt;/td&gt;
&lt;td&gt;1,42 s · 192 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;playwright (5.664 errores)&lt;/td&gt;
&lt;td&gt;3,12 s · 581 MB&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0,73 s · 195 MB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1,19 s · 417 MB&lt;/td&gt;
&lt;td&gt;1,05 s · 189 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;hono, config de build (limpio, 364 archivos)&lt;/td&gt;
&lt;td&gt;0,32 s · 98 MB&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0,11 s · 49 MB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0,10 s · 103 MB&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Frente a &lt;code&gt;tsc&lt;/code&gt; 7.0.2, tsrs fue:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;zod:&lt;/strong&gt; 6,5x más rápido, 4,2x menos memoria&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;playwright:&lt;/strong&gt; 4,3x más rápido, 3,0x menos memoria&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;hono:&lt;/strong&gt; 2,9x más rápido, 2,0x menos memoria&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dos cosas nos llamaron la atención. Primero, la ganancia no es solo paralelismo: con un único hilo de chequeo en ambos (&lt;code&gt;--checkers 1&lt;/code&gt;), tsrs siguió siendo 4,8x más rápido en zod y 3,3x en playwright. Segundo, se sostiene en proyectos chicos. En nuestra prueba anterior, &lt;code&gt;bun check&lt;/code&gt; fue &lt;em&gt;más lento&lt;/em&gt; que &lt;code&gt;tsc&lt;/code&gt; en el build limpio de hono; tsrs fue casi tres veces más rápido con la misma configuración.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿tsrs o bun check?
&lt;/h3&gt;

&lt;p&gt;tsrs fue más rápido que &lt;code&gt;bun check&lt;/code&gt; en los dos repos grandes. En memoria quedaron parejos en playwright, pero en zod tsrs usó más (266 MB frente a 192 MB). Si la memoria te importa más que la velocidad, &lt;code&gt;--checkers 1&lt;/code&gt; bajó tsrs a 195 MB en zod y se mantuvo por debajo de 1,2 segundos.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué flags controlan la velocidad y la memoria?
&lt;/h3&gt;

&lt;p&gt;tsrs agrega algunas opciones de rendimiento a los flags estándar de &lt;code&gt;tsc&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--checkers N&lt;/code&gt; define cuántos hilos de chequeo usar. Por defecto, uno por núcleo hasta 16.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--singleThreaded&lt;/code&gt; usa un solo hilo, para el menor consumo de memoria.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--maxMemory &amp;lt;size&amp;gt;&lt;/code&gt; (por ejemplo &lt;code&gt;12G&lt;/code&gt;, solo con &lt;code&gt;--noEmit&lt;/code&gt;) mantiene el proceso cerca de ese límite, cambiando CPU por memoria.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--checkerCostCache &amp;lt;file&amp;gt;&lt;/code&gt; recuerda cuánto tardó cada archivo para repartir mejor los hilos en la siguiente ejecución.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ¿tsrs da los mismos errores que tsc? El cambio a TypeScript 7.1
&lt;/h2&gt;

&lt;p&gt;Sí, siempre que lo compares con la versión de TypeScript que realmente porta, y ahí está el detalle: tsrs sigue &lt;strong&gt;TypeScript 7.1-dev&lt;/strong&gt;, no 7.0.&lt;/p&gt;

&lt;p&gt;En zod, tsrs y &lt;code&gt;tsc&lt;/code&gt; 7.0.2 reportaron los mismos 593 errores, línea por línea. En playwright, ambos reportaron 5.664 errores, pero 20 aparecieron en otra línea y columna. En la configuración de build de hono, &lt;code&gt;tsc&lt;/code&gt; 7.0.2 terminó limpio y tsrs reportó dos errores nuevos &lt;code&gt;TS7031&lt;/code&gt; (&lt;em&gt;any&lt;/em&gt; implícito).&lt;/p&gt;

&lt;p&gt;Después ejecutamos &lt;code&gt;typescript@7.1.0-dev.20260930.4&lt;/code&gt;, la build del commit que porta tsrs. Su salida coincidió exactamente con tsrs en ambos repos. Las diferencias son comportamiento de TypeScript 7.1, no bugs de tsrs.&lt;/p&gt;

&lt;p&gt;En la práctica: &lt;strong&gt;cambiar &lt;/strong&gt;&lt;strong&gt;&lt;code&gt;tsc&lt;/code&gt;&lt;/strong&gt;&lt;strong&gt; 7.0 por tsrs en tu CI significa pasar tu type check a la semántica de 7.1-dev.&lt;/strong&gt; Un repo que hoy está limpio puede empezar a fallar. Pruébalo primero en local y trátalo como una actualización, no como un cambio transparente.&lt;/p&gt;

&lt;p&gt;Un detalle más para CI: con errores, &lt;code&gt;tsc&lt;/code&gt; 7.0.2 salió con código 1 y tsrs con código 2. TypeScript 7.1-dev también devuelve 2. Los dos son distintos de cero, así que el paso de CI falla igual, pero un script que compare exactamente con &lt;code&gt;1&lt;/code&gt; no.&lt;/p&gt;

&lt;p&gt;El propio proyecto dice que quiere reducir las diferencias que quedan, como el orden en que se imprimen los diagnósticos, antes de una versión estable. Para la comparación más cercana con el compilador en Go, el README sugiere &lt;code&gt;--checkerAssignment go --noLazyMembers&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  tsrs vs tsc-rs: ¿qué port de TypeScript a Rust usar?
&lt;/h2&gt;

&lt;p&gt;Son dos paquetes de npm distintos con nombres casi idénticos, y es fácil confundirlos.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;tsrs&lt;/th&gt;
&lt;th&gt;tsc-rs&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Paquete npm&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tsrs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tsc-rs&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repo&lt;/td&gt;
&lt;td&gt;&lt;code&gt;oxc-project/tsrs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pingdotgg/ts-rust&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Detrás&lt;/td&gt;
&lt;td&gt;Oxc, Cloudflare, VoidZero; nació en Owner.com&lt;/td&gt;
&lt;td&gt;pingdotgg (Theo Browne)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Licencia&lt;/td&gt;
&lt;td&gt;Apache-2.0&lt;/td&gt;
&lt;td&gt;MIT AND Apache-2.0 (npm)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Porta&lt;/td&gt;
&lt;td&gt;TypeScript 7.1-dev&lt;/td&gt;
&lt;td&gt;TypeScript 7.1-dev&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cómo se escribió&lt;/td&gt;
&lt;td&gt;Agentes de IA (Claude Opus 5.5)&lt;/td&gt;
&lt;td&gt;Agentes de IA: primero modelos de OpenAI, luego Claude Opus 5.5&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Los dos son ports escritos por LLM a partir del mismo compilador en Go. El README de tsc-rs cuenta que el primer intento con modelos de OpenAI costó más de 400.000 dólares en tokens a precio de API y se estancó cerca del 84 por ciento de compatibilidad, y que el reinicio con Claude Opus 5.5 tomó unas dos semanas y unos 24.000 dólares.&lt;/p&gt;

&lt;p&gt;En nuestra prueba, los dos dieron &lt;strong&gt;diagnósticos idénticos&lt;/strong&gt; en los tres repos. tsrs fue alrededor de 1,6x más rápido en los repos grandes y usó cerca de la mitad de memoria; en hono empataron en tiempo y tsrs usó la mitad de memoria.&lt;/p&gt;

&lt;p&gt;La elección puede no durar. El anuncio de Cloudflare dice que están trabajando con Theo Browne para fusionar tsc-rs y tsrs en un solo paquete. Al 20 de octubre de 2026, esa fusión está anunciada pero no publicada, y el README de ts-rust todavía no la menciona.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿tsrs está listo para producción?
&lt;/h2&gt;

&lt;p&gt;Es una versión experimental con un camino claro hacia una estable. Cloudflare la llama experimental; el README, en cambio, nombra limitaciones concretas en vez de una advertencia general, y dice que en sus pruebas sobre proyectos existentes no han encontrado un bug de corrección. El objetivo declarado es una versión estable sobre TypeScript 7.1 con 100 por ciento de conformidad.&lt;/p&gt;

&lt;p&gt;Antes de adoptarlo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Issues abiertos, PRs cerrados.&lt;/strong&gt; El tracker acepta reportes de bugs con una reproducción mínima; los mantenedores dicen que no tienen capacidad para revisar pull requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fija la versión.&lt;/strong&gt; Cada versión del paquete indica el commit de TypeScript que sigue, así que actualizar puede cambiar los diagnósticos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Buen primer uso:&lt;/strong&gt; un chequeo local o en pre-commit, o un job de CI que corra junto a &lt;code&gt;tsc&lt;/code&gt; hasta que confíes en la salida.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hacia dónde va:&lt;/strong&gt; Cloudflare menciona reglas de lint con información de tipos en Oxlint, y la compilación de Rust a WebAssembly es una de las razones declaradas para elegir Rust en vez de Go: correr un toolchain de TypeScript completo en el navegador o en un Worker aislado.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;¿Y tú?&lt;/strong&gt; ¿Qué usas hoy para el type check en tu CI, y cuánto tarda?&lt;/p&gt;

&lt;p&gt;Comenta abajo o, si este artículo te llegó por correo, responde directamente al email: tu respuesta se publica aquí.&lt;/p&gt;

&lt;p&gt;Relacionado: &lt;a href="https://www.yodev.dev/t/bun-check-vs-tsc-probamos-el-nuevo-type-checker-de-bun-en-zod-playwright-y-hono/5672" rel="noopener noreferrer"&gt;bun check vs tsc: probamos el nuevo type checker de Bun en zod, playwright y hono&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>PHP2Shell: cómo comprobar si tu PHP es vulnerable con la skill oficial de Codex ✅ yoDEV Tested</title>
      <dc:creator>Grego</dc:creator>
      <pubDate>Sun, 25 Oct 2026 15:43:50 +0000</pubDate>
      <link>https://dev.to/yodev_grego/php2shell-como-comprobar-si-tu-php-es-vulnerable-con-la-skill-oficial-de-codex-yodev-tested-1bd1</link>
      <guid>https://dev.to/yodev_grego/php2shell-como-comprobar-si-tu-php-es-vulnerable-con-la-skill-oficial-de-codex-yodev-tested-1bd1</guid>
      <description>&lt;p&gt;OpenAI publicó php2shell-checker, una skill oficial de Codex que te dice si un sitio o un servidor usa una versión de PHP expuesta a PHP2Shell (CVE-2026-109618 y CVE-2026-109619) sin enviar ni una sola petición de exploit. Se instala en Codex con una instrucción, y el mismo script también funciona por su cuenta solo con Node.js.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/openai/php2shell-checker" rel="noopener noreferrer"&gt;https://github.com/openai/php2shell-checker&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;✅ yoDEV Tested&lt;/strong&gt; · 21 de octubre de 2026 Ejecutamos php2shell-checker (commit 40a4746, Node.js 22.22 y PHP 8.3.6 de distribución) contra una instalación local de PHP, un servidor PHP local, un servidor parcheado simulado y un sitio público sin PHP. Los resultados que reportamos como nuestros salen de esa prueba.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  ¿Qué es la skill php2shell-checker de Codex?
&lt;/h2&gt;

&lt;p&gt;Es un pequeño script de Node.js más dos skills de Codex, que OpenAI publicó el 21 de octubre de 2026 junto con su anuncio de Patch the Planet sobre las vulnerabilidades de PHP. OpenAI lo presenta como un PHP version checker distribuido como Codex skill, pensado para que los operadores identifiquen versiones de PHP potencialmente vulnerables.&lt;/p&gt;

&lt;p&gt;El repositorio tiene licencia Apache-2.0 y no tiene dependencias: no hace falta &lt;code&gt;npm install&lt;/code&gt;. Contiene tres piezas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;skills/phpcheck-url&lt;/code&gt;: comprueba la versión de PHP que anuncia una URL. Incluye el script real.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;skills/phpcheck-server&lt;/code&gt;: solo instrucciones, sin script. Le indica a Codex cómo comprobar el PHP que realmente sirve un sitio cuando tienes acceso al servidor.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;phpcheck.js&lt;/code&gt; en la raíz: un envoltorio de una línea sobre el script de la skill de URL, para que puedas ejecutarlo sin Codex.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lo más importante es lo que &lt;strong&gt;no&lt;/strong&gt; hace: nunca prueba la vulnerabilidad. Lee cadenas de versión y las compara con una tabla de versiones límite.&lt;/p&gt;

&lt;p&gt;Al momento de publicar esta nota, el repositorio tenía 7 commits y ninguna release etiquetada (el script se identifica como &lt;code&gt;1.0.0&lt;/code&gt;), y OpenAI indica que no acepta contribuciones de código externas. Cambió dos veces el mismo día de su publicación, así que revisa el README antes de depender de cualquiera de los comandos de abajo.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué versión de PHP corrige PHP2Shell?
&lt;/h2&gt;

&lt;p&gt;PHP 8.5.12, 8.4.27, 8.3.36 y 8.2.35, publicadas el 21 de octubre de 2026. Son exactamente un parche por encima de los límites que trae el checker (8.5.11, 8.4.26, 8.3.35 y 8.2.34), así que un servidor con cualquiera de ellas devuelve &lt;code&gt;OK&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;PHP 8.1 y anteriores no reciben una versión oficial. El equipo de seguridad de PHP publicó backports mínimos en código fuente para 7.4, 8.0 y 8.1, y las distribuciones Linux y los proveedores LTS recibieron los parches por adelantado. Explicamos las vulnerabilidades, las mitigaciones y las ramas sin soporte en &lt;a href="https://www.yodev.dev/t/cve-2026-109618-y-cve-2026-109619-que-version-de-php-necesitas-y-cuando-sale-el-parche/5732" rel="noopener noreferrer"&gt;nuestro artículo sobre PHP2Shell&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo instalar la skill en Codex CLI?
&lt;/h2&gt;

&lt;p&gt;Pídeselo a Codex dentro de una sesión:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$skill&lt;/span&gt;&lt;span class="nt"&gt;-installer&lt;/span&gt; &lt;span class="nb"&gt;install &lt;/span&gt;both skills from https://github.com/openai/php2shell-checker

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;$skill-installer&lt;/code&gt; es la skill integrada de Codex para añadir skills. La documentación de Codex indica que también puede descargar skills de otros repositorios, no solo del catálogo oficial. Codex detecta automáticamente las skills recién instaladas; si alguna no aparece, reinicia Codex.&lt;/p&gt;

&lt;p&gt;Después, invoca la que corresponda a tu caso:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$phpcheck&lt;/span&gt;&lt;span class="nt"&gt;-server&lt;/span&gt; check the PHP version serving my site
&lt;span class="nv"&gt;$phpcheck&lt;/span&gt;&lt;span class="nt"&gt;-url&lt;/span&gt; check example.com

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usa &lt;code&gt;phpcheck-server&lt;/code&gt; cuando tienes acceso a la máquina, y &lt;code&gt;phpcheck-url&lt;/code&gt; cuando solo tienes una dirección.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo comprobar la versión de PHP de una web sin Codex?
&lt;/h2&gt;

&lt;p&gt;Clona el repositorio y ejecuta el script directamente. Node.js es el único requisito.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/openai/php2shell-checker
&lt;span class="nb"&gt;cd &lt;/span&gt;php2shell-checker
node phpcheck.js &lt;span class="s2"&gt;"https://example.com"&lt;/span&gt;
node phpcheck.js &lt;span class="nt"&gt;--local&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Flags útiles: &lt;code&gt;--json&lt;/code&gt; para obtener una salida legible por máquina, &lt;code&gt;--php PATH&lt;/code&gt; para apuntar &lt;code&gt;--local&lt;/code&gt; a un binario concreto y &lt;code&gt;--timeout SECONDS&lt;/code&gt; para hosts lentos.&lt;/p&gt;

&lt;p&gt;Un detalle con el que nos topamos: la CLI necesita una URL completa. Al pasarle un &lt;code&gt;host:puerto&lt;/code&gt; sin esquema devolvió &lt;code&gt;UNKNOWN: Invalid URL&lt;/code&gt;. La skill de URL lo resuelve por ti, porque sus instrucciones le piden a Codex que añada &lt;code&gt;https://&lt;/code&gt; a los nombres de host sin esquema.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué resultados obtuvimos al probarlo?
&lt;/h2&gt;

&lt;p&gt;La batería de tests (&lt;code&gt;node --test phpcheck.test.js&lt;/code&gt;) pasó 39 de 39. Después lo ejecutamos contra cuatro objetivos:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Objetivo&lt;/th&gt;
&lt;th&gt;Salida&lt;/th&gt;
&lt;th&gt;Código de salida&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;--local&lt;/code&gt;, PHP 8.3.6 de distribución&lt;/td&gt;
&lt;td&gt;&lt;code&gt;VULNERABLE: PHP 8.3.6&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Servidor local &lt;code&gt;php -S&lt;/code&gt; con PHP 8.3.6&lt;/td&gt;
&lt;td&gt;&lt;code&gt;VULNERABLE: PHP 8.3.6&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Servidor local que envía &lt;code&gt;X-Powered-By: PHP/8.3.36&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;OK: PHP 8.3.36&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;github.com (sin cabecera de PHP)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;UNKNOWN&lt;/code&gt; — "PHP version not found"&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Con &lt;code&gt;--json&lt;/code&gt;, la comprobación local devolvió:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"patch_status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"vulnerable"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"php_version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"8.3.6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"reason"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"PHP 8.3.6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"exit_code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La primera fila es la más instructiva. Ese PHP 8.3.6 viene de los paquetes de la distribución, y las distribuciones suelen aplicar backports de seguridad sin cambiar el número de versión upstream. El checker no puede verlo. En nuestro caso tenía razón al alertar, porque la compilación es anterior a la corrección, pero con un paquete de distribución ya parcheado diría exactamente lo mismo.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué significan OK, VULNERABLE y UNKNOWN?
&lt;/h2&gt;

&lt;p&gt;Significan menos de lo que parece, y el README lo deja claro.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;OK&lt;/code&gt;&lt;/strong&gt;&lt;strong&gt; (código 0):&lt;/strong&gt; la versión está por encima del límite de su rama. Es una comparación de versiones, no una verificación de la corrección. Las cabeceras se pueden reescribir, y un &lt;code&gt;OK&lt;/code&gt; obtenido de una cabecera puesta a mano no vale nada: así es exactamente como conseguimos nuestra fila &lt;code&gt;OK&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;VULNERABLE&lt;/code&gt;&lt;/strong&gt;&lt;strong&gt; (código 1):&lt;/strong&gt; la versión es igual o inferior al límite. Si usas paquetes de distribución, confírmalo con el aviso de seguridad de tu proveedor antes de alarmarte. En 8.1 y anteriores seguirá diciendo &lt;code&gt;VULNERABLE&lt;/code&gt; aunque apliques un backport en código fuente, porque la cadena de versión no cambia.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;UNKNOWN&lt;/code&gt;&lt;/strong&gt;&lt;strong&gt; (código 3):&lt;/strong&gt; no encontró versión, la rama no está en la tabla o es una compilación previa a una versión estable. &lt;strong&gt;No&lt;/strong&gt; significa que esté parcheado. Cualquier sitio que oculte &lt;code&gt;X-Powered-By&lt;/code&gt;, una medida de hardening habitual, cae aquí. También las release candidates de PHP 8.6, porque la rama 8.6 no está en la tabla, aunque 8.6.0 RC4 ya incluye la corrección.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Los argumentos inválidos devuelven el código 2. Los códigos 1 y 3 son resultados, no fallos de ejecución: útil si lo integras en CI o en un script de monitoreo.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Por qué no basta con revisar la URL?
&lt;/h2&gt;

&lt;p&gt;Porque solo ve lo que el servidor decide anunciar. El modo URL lee las cabeceras &lt;code&gt;X-Powered-By&lt;/code&gt; y &lt;code&gt;Server&lt;/code&gt;, envía una petición &lt;code&gt;HEAD&lt;/code&gt; (y recurre a &lt;code&gt;GET&lt;/code&gt; solo si recibe un 405 o un 501), no sigue redirecciones y no lee el cuerpo de la página.&lt;/p&gt;

&lt;p&gt;Eso lo convierte en una herramienta rápida de triaje para una lista de sitios, no en una prueba. La skill &lt;code&gt;phpcheck-server&lt;/code&gt; existe para la comprobación más sólida: le indica a Codex que empiece con &lt;code&gt;php -v&lt;/code&gt;, pero que confirme que la CLI coincide con la compilación de PHP-FPM o Apache que realmente sirve el sitio, y que compare la revisión completa del paquete con los avisos de PHP o del proveedor. Si no puede verificar la versión que sirve el sitio, la instrucción es reportar desconocido.&lt;/p&gt;

&lt;p&gt;Ambas skills incluyen la misma regla: no ejecutar pruebas de exploit.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Por qué importa que sea una skill de Codex?
&lt;/h2&gt;

&lt;p&gt;Es la primera vez que vemos a OpenAI publicar una skill oficial de Codex como repositorio independiente ligado a una respuesta de seguridad, en lugar de incluirla en su catálogo de skills o en su documentación. La skill es el mecanismo de distribución: una sola instrucción pone un checker revisado dentro del agente de cada usuario de Codex, con las salvaguardas ("no ejecutar pruebas de exploit") escritas en la propia skill.&lt;/p&gt;

&lt;p&gt;Para quien busque en inglés: son Codex skills que funcionan en Codex CLI, y el patrón de instalación con &lt;code&gt;$skill-installer&lt;/code&gt; sirve igual para cualquier otro repositorio de skills.&lt;/p&gt;

&lt;p&gt;El mismo anuncio compromete suscripciones para mantenedores de código abierto a través de Codex for OSS. No pudimos confirmar cuándo se abrió ese programa, así que la noticia de hoy es la skill, no la suscripción.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;¿Y tú?&lt;/strong&gt; ¿Cuántos servidores PHP tienes que revisar esta semana?&lt;/p&gt;

&lt;p&gt;Comenta abajo o, si este artículo te llegó por correo, responde directamente al email: tu respuesta se publica aquí.&lt;/p&gt;

&lt;p&gt;Relacionado: &lt;a href="https://www.yodev.dev/t/cve-2026-109618-y-cve-2026-109619-que-version-de-php-necesitas-y-cuando-sale-el-parche/5732" rel="noopener noreferrer"&gt;CVE-2026-109618 y CVE-2026-109619: qué versión de PHP necesitas y cuándo sale el parche&lt;/a&gt;&lt;/p&gt;

</description>
      <category>openai</category>
      <category>php</category>
      <category>security</category>
      <category>tools</category>
    </item>
    <item>
      <title>TokenEconomizer: el Plugin de Microsoft para Claude Code, Codex y Copilot CLI que Recortó un 31 por ciento del Contexto ✅ yoDEV Tested</title>
      <dc:creator>Grego</dc:creator>
      <pubDate>Sun, 25 Oct 2026 15:38:52 +0000</pubDate>
      <link>https://dev.to/yodev_grego/tokeneconomizer-el-plugin-de-microsoft-para-claude-code-codex-y-copilot-cli-que-recorto-un-31-por-163p</link>
      <guid>https://dev.to/yodev_grego/tokeneconomizer-el-plugin-de-microsoft-para-claude-code-codex-y-copilot-cli-que-recorto-un-31-por-163p</guid>
      <description>&lt;p&gt;TokenEconomizer, el plugin de Microsoft Research y UC Berkeley para Claude Code, Codex, GitHub Copilot CLI y Pi, recortó un 31 por ciento del contexto de cada petición de Claude Code en nuestra prueba, sin perder ninguna tarea. No actúa desde la primera sesión: necesita varias sesiones en el mismo repositorio antes de empezar a ahorrar.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/microsoft/TokenEconomizer" rel="noopener noreferrer"&gt;https://github.com/microsoft/TokenEconomizer&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;✅ yoDEV Tested&lt;/strong&gt; · 23 de octubre de 2026&lt;/p&gt;

&lt;p&gt;Ejecutamos 32 sesiones de Claude Code 2.1.305 con Sonnet, con y sin TokenEconomizer (commit &lt;code&gt;0ce0e06&lt;/code&gt;), sobre 8 tareas seguidas en un mismo repositorio de Python, repetidas dos veces. Los resultados que reportamos como nuestros salen de esa prueba.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  ¿Qué es TokenEconomizer y cómo ahorra tokens?
&lt;/h2&gt;

&lt;p&gt;Es un plugin que no toca tu agente y abarata las sesiones siguientes en el mismo repositorio. En cada turno, un agente de programación vuelve a cobrar sus instrucciones, todas las herramientas cargadas y la conversación hasta ese punto. El plugin lee cada sesión terminada y cambia lo que pagan las siguientes con tres mecanismos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Micro-skills.&lt;/strong&gt; Los datos del entorno que tus sesiones redescubren fallando una y otra vez (por ejemplo, que &lt;code&gt;pytest&lt;/code&gt; no está instalado pero &lt;code&gt;python -m pytest&lt;/code&gt; sí funciona) se aprenden y se indican al inicio de la sesión siguiente. Aprenderlos no consume ninguna llamada al modelo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Poda de herramientas (&lt;/strong&gt;&lt;strong&gt;&lt;code&gt;tool pruning&lt;/code&gt;&lt;/strong&gt;&lt;strong&gt;).&lt;/strong&gt; Las herramientas que siguen cargadas pero nadie usa, por defecto durante cinco sesiones seguidas, se dejan fuera de las sesiones siguientes a través de la propia configuración del agente.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Guardián de bucles (&lt;/strong&gt;&lt;strong&gt;&lt;code&gt;loop guard&lt;/code&gt;&lt;/strong&gt;&lt;strong&gt;).&lt;/strong&gt; Un turno que repite el mismo ciclo fallido de editar y probar recibe una redirección. Si sigue atascado, el plugin te dice cómo detenerlo. Nunca detiene un turno por su cuenta.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Usa solo la biblioteca estándar de Python, no necesita una API key propia y funciona con el plan o el inicio de sesión que ya use tu agente. Lo que aprende se guarda en &lt;code&gt;~/.tokeneconomizer&lt;/code&gt;. Licencia Apache 2.0.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cuánto ahorra según el paper de Microsoft?
&lt;/h2&gt;

&lt;p&gt;El paper (arXiv 2610.22732, publicado el 15 de octubre de 2026) reporta un &lt;strong&gt;costo medio entre un 18,4 y un 30,9 por ciento más bajo&lt;/strong&gt; en SWE-Bench, con cinco combinaciones de agente y modelo. Los autores miden teniendo en cuenta la caché de prompts e incluyen las llamadas del propio plugin:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Agente y modelo&lt;/th&gt;
&lt;th&gt;Costo medio más bajo&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Claude Code + Opus 4.8&lt;/td&gt;
&lt;td&gt;30,9%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codex + GPT-5.6 Sol&lt;/td&gt;
&lt;td&gt;26,1%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codex + GPT-5.6 Terra&lt;/td&gt;
&lt;td&gt;24,7%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Code + Sonnet 5&lt;/td&gt;
&lt;td&gt;23,6%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Copilot CLI + Sonnet 5&lt;/td&gt;
&lt;td&gt;18,4%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Según el paper, el Pass@1 subió en 4 de las 5 combinaciones. Son cifras de los propios autores, medidas sobre 277 tareas en seis repositorios, con las tareas de cada repositorio en secuencia: una racha mucho más larga que una semana normal de trabajo.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cuánto ahorró en nuestra prueba con Claude Code?
&lt;/h2&gt;

&lt;p&gt;Armamos un pequeño repositorio de Python con dos trampas que cada sesión tiene que redescubrir: los imports solo funcionan con &lt;code&gt;PYTHONPATH=src&lt;/code&gt;, y el paquete se niega a cargar si no está definida &lt;code&gt;TIENDA_ENV&lt;/code&gt;. No documentamos ninguna de las dos, a propósito. Después le dimos a Claude Code 8 reportes de bugs seguidos, con y sin el plugin, dos veces.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Sin plugin&lt;/th&gt;
&lt;th&gt;Con plugin&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Tareas resueltas&lt;/td&gt;
&lt;td&gt;16/16&lt;/td&gt;
&lt;td&gt;16/16&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Contexto por petición, antes de que el plugin actuara&lt;/td&gt;
&lt;td&gt;24.779 tokens&lt;/td&gt;
&lt;td&gt;24.809 tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Contexto por petición, con la poda activa&lt;/td&gt;
&lt;td&gt;25.966 tokens&lt;/td&gt;
&lt;td&gt;17.795 tokens (−31%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Costo de las sesiones con la poda activa&lt;/td&gt;
&lt;td&gt;0,72 USD&lt;/td&gt;
&lt;td&gt;0,61 USD (−15%)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Qué hizo cada mecanismo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;La poda de herramientas actuó, y su efecto fue claro.&lt;/strong&gt; Se activó en la sesión 8 de la primera tanda y en la sesión 6 de la segunda. Dejó fuera 284 herramientas: la mayoría eran de conectores que se cargan en cada sesión de nuestra configuración (Docs, Discourse, Drive), más 16 herramientas propias de Claude Code que nunca usamos, como las tareas programadas y los worktrees. Desde ese momento, cada petición llevaba unos 8.000 tokens menos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Las micro-skills no llegaron a activarse.&lt;/strong&gt; El plugin sí detectó que nuestras sesiones fallaban con &lt;code&gt;python -m pytest&lt;/code&gt;. Pero un dato solo se forma tras tres sesiones que lo confirman entre al menos cuatro donde aplica, y Claude no falló de la misma forma con suficiente constancia. Tras 8 sesiones, el mejor candidato iba en 2 de 7.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;El guardián de bucles no intervino.&lt;/strong&gt; Ningún turno se atascó: las tareas eran cortas.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;El costo propio del plugin fue cero. En las 32 sesiones, el lado con plugin costó un 8,5 por ciento menos, pero la mayor parte vino de sesiones en las que todavía no había cambiado nada. Esa parte es variación normal entre ejecuciones, así que no la contamos como efecto del plugin. Las 4 sesiones con poda activa son una muestra pequeña; el dato sólido es la caída del contexto.&lt;/p&gt;

&lt;p&gt;Cambiamos un ajuste respecto de los valores por defecto. Normalmente, la poda espera a que tus sesiones lleven una hora inactivas antes de escribir la lista de herramientas excluidas, para no romper una caché de prompts que sigue caliente. Nuestras sesiones iban una detrás de otra, así que usamos &lt;code&gt;toolprune_quiet_minutes=0&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Te conviene si usas muchos servidores MCP en Claude Code?
&lt;/h2&gt;

&lt;p&gt;Sí: es el caso en que más ahorra. El ahorro depende de dos cosas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cuántas herramientas se cargan en cada sesión.&lt;/strong&gt; Si tienes muchos servidores MCP o conectores, la poda tiene mucho que quitar. Con una configuración mínima, hay poco que recortar.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cuántas sesiones haces en el mismo repositorio.&lt;/strong&gt; Los datos se forman a partir de evidencia repetida, así que el plugin rinde en un código que trabajas a diario, no en repos de una sola vez. Si tu repositorio ya documenta sus particularidades en un &lt;code&gt;CLAUDE.md&lt;/code&gt;, las micro-skills tienen menos que aprender.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Si quieres recortar tokens por otras vías, aquí probamos &lt;a href="https://www.yodev.dev/t/como-reducir-tokens-en-claude-code-con-hooks-y-portal-de-spotify/5139" rel="noopener noreferrer"&gt;cómo hacerlo con hooks&lt;/a&gt;, y aquí &lt;a href="https://www.yodev.dev/t/como-ver-el-consumo-de-tokens-en-codex-cli-usage-modo-fullscreen-y-voz-por-defecto/5457" rel="noopener noreferrer"&gt;cómo ver el consumo de tokens en Codex CLI&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Es gratis y cuánto baja el precio de Claude Code?
&lt;/h2&gt;

&lt;p&gt;El plugin es gratis y open source, y no hace llamadas al modelo por su cuenta: sus ayudantes de pago (un generador de datos con LLM y un juez para el guardián de bucles) vienen apagados salvo que actives &lt;code&gt;paid=true&lt;/code&gt;. Lo que baja es lo que pagas por cada sesión de tu agente: en nuestra prueba, un 15 por ciento en las sesiones con la poda activa, a precios de lista de la API. Con un plan de suscripción, el efecto es que la misma cuota te alcanza para más trabajo.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo instalar el plugin en Claude Code, Codex y Copilot CLI?
&lt;/h2&gt;

&lt;p&gt;Necesitas Python 3.10 o superior en el &lt;code&gt;PATH&lt;/code&gt;. Clona el repositorio en una carpeta donde vaya a quedarse, porque los agentes ejecutan el plugin desde ahí:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Claude Code&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/microsoft/TokenEconomizer.git
claude plugin marketplace add "$PWD/TokenEconomizer"
claude plugin install tokeneconomizer@tokeneconomizer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inicia &lt;code&gt;claude&lt;/code&gt; en un repositorio y ejecuta &lt;code&gt;/tokeneconomizer:status&lt;/code&gt;. Una vez por máquina, y de nuevo cada vez que Claude Code se actualice, ejecuta &lt;code&gt;/tokeneconomizer:toolprune refresh-catalog&lt;/code&gt;: registra qué herramientas carga una sesión, y sin ese paso la poda solo ve unas pocas.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Codex&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;codex plugin marketplace add "$PWD/TokenEconomizer"
codex plugin add tokeneconomizer@tokeneconomizer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cuando Codex muestre &lt;strong&gt;Hooks need review&lt;/strong&gt;, elige &lt;strong&gt;Trust all and continue&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Copilot CLI&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;copilot plugin marketplace add "$PWD/TokenEconomizer"
copilot plugin install tokeneconomizer@tokeneconomizer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La ruta del marketplace tiene que ser absoluta. Versiones soportadas según el README: Claude Code de la 2.1.300 a la 2.1.307, Codex de la 0.153.1 a la 0.163.0 y Copilot CLI de la 1.0.83 a la 1.0.102. Al momento de publicar esta nota, los autores no habían comprobado versiones posteriores.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo ver lo que hizo o deshacer los cambios?
&lt;/h2&gt;

&lt;p&gt;Desde una terminal, dentro del repositorio y sin gastar tokens:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/.tokeneconomizer/bin/te status              # qué aprendió y cuánto costaron tus sesiones
~/.tokeneconomizer/bin/te toolprune           # qué herramientas dejó fuera y por qué
~/.tokeneconomizer/bin/te toolprune restore   # devolverlas
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Por defecto, la poda se aplica sin preguntarte, y en Claude Code el aviso solo aparece en la transcripción detallada (Ctrl+O). Si prefieres aprobar cada lista tú mismo, ejecuta &lt;code&gt;te config set toolprune=propose&lt;/code&gt;. Para una sola sesión sin el plugin, inicia el agente con &lt;code&gt;TE_DISABLE=1 claude&lt;/code&gt;.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;¿Y tú?&lt;/strong&gt; ¿Cuántos servidores MCP tienes conectados hoy en tu agente de programación?&lt;/p&gt;

&lt;p&gt;Comenta abajo o, si este artículo te llegó por correo, responde directamente al email: tu respuesta se publica aquí.&lt;/p&gt;

&lt;p&gt;Relacionado: &lt;a href="https://www.yodev.dev/t/como-reducir-el-consumo-de-tokens-de-tu-agente-de-ia-probamos-pensieve-en-un-repo-real/5650" rel="noopener noreferrer"&gt;Cómo reducir el consumo de tokens de tu agente de IA: probamos Pensieve en un repo real&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>cli</category>
      <category>github</category>
      <category>productivity</category>
    </item>
    <item>
      <title>¿Cómo hacer migraciones de esquema en ClickHouse? Probamos chkit, el Drizzle que le faltaba ✅ yoDEV Tested</title>
      <dc:creator>Grego</dc:creator>
      <pubDate>Sun, 25 Oct 2026 15:32:37 +0000</pubDate>
      <link>https://dev.to/yodev_grego/como-hacer-migraciones-de-esquema-en-clickhouse-probamos-chkit-el-drizzle-que-le-faltaba-yodev-1j1k</link>
      <guid>https://dev.to/yodev_grego/como-hacer-migraciones-de-esquema-en-clickhouse-probamos-chkit-el-drizzle-que-le-faltaba-yodev-1j1k</guid>
      <description>&lt;p&gt;Para hacer migraciones de esquema en ClickHouse con chkit, declaras tus tablas en TypeScript o Python, chkit genera el SQL de la migración a partir del diff, lo aplica y hace fallar tu CI si la base en vivo se desvía de lo declarado. Probamos la versión 0.2.0-beta.11 de punta a punta, incluidas las partes que deben fallar.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/obsessiondb/chkit" rel="noopener noreferrer"&gt;https://github.com/obsessiondb/chkit&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;✅ yoDEV Tested&lt;/strong&gt; · 22 de octubre de 2026 Probamos chkit 0.2.0-beta.11 (TypeScript con Bun) y chkit-py 0.2.0 contra clickhouse-server 26.9.25.15 en Linux. Los resultados que reportamos como nuestros salen de esa prueba.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  ¿Qué es chkit?
&lt;/h2&gt;

&lt;p&gt;chkit es &lt;em&gt;schema as code&lt;/em&gt; para ClickHouse, con licencia MIT: describes tablas, vistas, vistas materializadas y diccionarios en código, y la CLI calcula los &lt;code&gt;CREATE&lt;/code&gt; y &lt;code&gt;ALTER&lt;/code&gt; necesarios. En su Show HN se presenta como "like Drizzle", y el flujo tiene esa forma: un archivo de esquema, un paso &lt;code&gt;generate&lt;/code&gt; que escribe SQL que puedes leer, un paso &lt;code&gt;migrate&lt;/code&gt; que lo aplica y una tabla de registro que guarda qué se ejecutó.&lt;/p&gt;

&lt;p&gt;Se distribuye en varios paquetes de npm: &lt;code&gt;chkit&lt;/code&gt; (la CLI), &lt;code&gt;@chkit/core&lt;/code&gt; (el DSL de esquema, la configuración y el motor de diff) y plugins para importar un esquema existente, generar tipos y hacer &lt;em&gt;backfills&lt;/em&gt;. También hay una versión para Python, &lt;code&gt;chkit-py&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Dos cosas que debes saber antes de adoptarlo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Está en beta.&lt;/strong&gt; El README afirma que la CLI y el DSL de esquema son estables y que chkit ya corre cargas de producción, pero el equipo se reserva pequeños cambios incompatibles en la experiencia de uso y en las APIs internas antes de la 1.0. Todo lo que ves en este artículo está fijado a &lt;code&gt;0.2.0-beta.11&lt;/code&gt;, publicada en npm el 12 de octubre de 2026.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lo construye un proveedor.&lt;/strong&gt; chkit viene del equipo de ObsessionDB, un servicio de ClickHouse administrado, y el README recomienda ObsessionDB para producción. La herramienta en sí es MIT y funciona con cualquier ClickHouse. La relación se nota en &lt;code&gt;chkit init&lt;/code&gt;, que te ofrece registrarte en ObsessionDB antes de explicarte cómo conectar tu propio servidor.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo se instala chkit?
&lt;/h2&gt;

&lt;p&gt;Con Bun, fijando la versión que probamos (el comando del README es el mismo sin las versiones &lt;code&gt;@&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bun add &lt;span class="nt"&gt;-d&lt;/span&gt; chkit@0.2.0-beta.11 @chkit/core@0.2.0-beta.11
bunx chkit init

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;init&lt;/code&gt; crea &lt;code&gt;clickhouse.config.ts&lt;/code&gt; y un esquema de ejemplo en &lt;code&gt;src/db/schema/example.ts&lt;/code&gt;. La configuración generada lee la conexión de cuatro variables de entorno y solo define el bloque &lt;code&gt;clickhouse&lt;/code&gt; cuando &lt;code&gt;CLICKHOUSE_URL&lt;/code&gt; está definida:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CLICKHOUSE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost:8123
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CLICKHOUSE_USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;default
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CLICKHOUSE_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CLICKHOUSE_DB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;default

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Las cuatro tienen que estar definidas; una contraseña vacía está permitida, una sin definir no. El esquema de ejemplo además se niega a cargar sin &lt;code&gt;CLICKHOUSE_DB&lt;/code&gt;, así que una terminal mal configurada falla de forma visible en lugar de generar migraciones para la base equivocada.&lt;/p&gt;

&lt;p&gt;Para Python es &lt;code&gt;pip install chkit-py&lt;/code&gt;, y el comando sigue siendo &lt;code&gt;chkit&lt;/code&gt;. Más abajo verás en qué se diferencia.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo se define el esquema de base de datos de ClickHouse en TypeScript?
&lt;/h2&gt;

&lt;p&gt;Se define con la función &lt;code&gt;table()&lt;/code&gt; de &lt;code&gt;@chkit/core&lt;/code&gt;. Esta es la tabla que genera &lt;code&gt;init&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;table&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@chkit/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CLICKHOUSE_DB&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Set CLICKHOUSE_DB to the intended database before generating migrations.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;events&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;table&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;events&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MergeTree&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UInt64&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;source&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;String&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ingested_at&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DateTime64(3)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;expression&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;now64(3)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;primaryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;orderBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;partitionBy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;toYYYYMM(ingested_at)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Los tipos de columna son los propios de ClickHouse escritos como texto, así que no hay una capa de traducción de tipos que aprender. Un detalle que nos sorprendió: un &lt;code&gt;default&lt;/code&gt; escrito como texto plano es un valor literal. En nuestra primera prueba escribimos &lt;code&gt;default: "''"&lt;/code&gt; para un valor vacío y obtuvimos &lt;code&gt;DEFAULT ''''''&lt;/code&gt;, es decir, el texto de dos caracteres &lt;code&gt;''&lt;/code&gt;. Las expresiones van en &lt;code&gt;{ expression: '...' }&lt;/code&gt; (la forma antigua del README, &lt;code&gt;'fn:now64(3)'&lt;/code&gt;, sigue funcionando y es equivalente). La referencia del DSL lo documenta, y &lt;code&gt;generate&lt;/code&gt; rechaza el error más común: una llamada a función escrita como texto, como &lt;code&gt;'now64(3)'&lt;/code&gt;, en una columna que no puede guardar texto.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo hacer migraciones de esquema en ClickHouse?
&lt;/h2&gt;

&lt;p&gt;Ejecuta &lt;code&gt;generate&lt;/code&gt; con un nombre y luego &lt;code&gt;migrate&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bunx chkit generate &lt;span class="nt"&gt;--name&lt;/span&gt; init
bunx chkit migrate &lt;span class="nt"&gt;--apply&lt;/span&gt;
bunx chkit status

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;generate&lt;/code&gt; escribe un archivo SQL con marca de tiempo en &lt;code&gt;chkit/migrations/&lt;/code&gt; y actualiza &lt;code&gt;chkit/meta/snapshot.json&lt;/code&gt;. Este es el archivo que obtuvimos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- chkit-migration-format: v1&lt;/span&gt;
&lt;span class="c1"&gt;-- generated-at: 2026-10-23T00:17:16.148Z&lt;/span&gt;
&lt;span class="c1"&gt;-- cli-version: 0.2.0-beta.11&lt;/span&gt;
&lt;span class="c1"&gt;-- definition-count: 1&lt;/span&gt;
&lt;span class="c1"&gt;-- operation-count: 2&lt;/span&gt;
&lt;span class="c1"&gt;-- rename-suggestion-count: 0&lt;/span&gt;
&lt;span class="c1"&gt;-- risk-summary: safe=2, caution=0, danger=0&lt;/span&gt;

&lt;span class="c1"&gt;-- operation: create_database key=database:default risk=safe&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;DATABASE&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- operation: create_table key=table:default.events risk=safe&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nv"&gt;`id`&lt;/span&gt; &lt;span class="n"&gt;UInt64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nv"&gt;`source`&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nv"&gt;`ingested_at`&lt;/span&gt; &lt;span class="n"&gt;DateTime64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="n"&gt;now64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;ENGINE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MergeTree&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;PARTITION&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;toYYYYMM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ingested_at&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;`id`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;`id`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cada sentencia lleva una etiqueta de riesgo, y el SQL es DDL normal de ClickHouse que puedes revisar en un pull request. &lt;code&gt;migrate --apply&lt;/code&gt; lo ejecutó y lo registró en la tabla &lt;code&gt;_chkit_migrations&lt;/code&gt;, con el nombre del archivo, un checksum SHA-256 del archivo y la versión de chkit que lo aplicó.&lt;/p&gt;

&lt;p&gt;Agregar una columna al esquema y ejecutar &lt;code&gt;generate --name add-country&lt;/code&gt; produjo una sola sentencia:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- operation: alter_table_add_column key=table:default.events:column:country risk=safe&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="k"&gt;ADD&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="nv"&gt;`country`&lt;/span&gt; &lt;span class="n"&gt;LowCardinality&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ¿Cómo detectar schema drift en ClickHouse?
&lt;/h2&gt;

&lt;p&gt;Con &lt;code&gt;chkit drift&lt;/code&gt;, que inspecciona la base en vivo y la compara con el snapshot. Para probarlo hicimos lo que alguien siempre termina haciendo: agregar una columna a mano, por fuera de chkit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="k"&gt;ADD&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="n"&gt;debug_flag&lt;/span&gt; &lt;span class="n"&gt;UInt8&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;chkit drift&lt;/code&gt; la detectó:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Expected objects: 1
Actual objects:   1
Drifted:          yes

Table shape drift:
- default.events
  extraColumns=debug_flag
  reasonCodes=extra_column

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Con &lt;code&gt;--json&lt;/code&gt; devuelve lo mismo de forma estructurada, con una entrada &lt;code&gt;tableDrift&lt;/code&gt; por tabla y un código de motivo para cada tipo de diferencia: columnas que faltan o sobran, tipos o valores por defecto cambiados, &lt;em&gt;settings&lt;/em&gt;, índices, TTL, motor, clave primaria, &lt;code&gt;ORDER BY&lt;/code&gt;, &lt;code&gt;PARTITION BY&lt;/code&gt; y proyecciones.&lt;/p&gt;

&lt;p&gt;Ojo: &lt;code&gt;drift&lt;/code&gt; siempre termina con código &lt;code&gt;0&lt;/code&gt;. Informa, no bloquea. El comando que hace fallar un build es &lt;code&gt;chkit check&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Las tablas que chkit no administra se tratan distinto. Creamos a mano una tabla &lt;code&gt;scratch&lt;/code&gt;, y &lt;code&gt;drift&lt;/code&gt; la listó como objeto inesperado pero igual indicó &lt;code&gt;Drifted: no&lt;/code&gt;, y &lt;code&gt;check&lt;/code&gt; pasó. Es a propósito: chkit puede compartir una base con tablas que no le pertenecen. Si chkit es dueño de toda la base, la política &lt;code&gt;check.failOnExtraObjects&lt;/code&gt; hace que los objetos sobrantes también fallen.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo usar chkit check en CI con GitHub Actions?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;chkit check&lt;/code&gt; termina con código &lt;code&gt;1&lt;/code&gt; si hay migraciones pendientes, si alguien editó un archivo de migración ya aplicado o si el esquema en vivo se desvió. Provocamos los tres casos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tras agregar la columna &lt;code&gt;country&lt;/code&gt; pero antes de migrar: &lt;code&gt;Failed checks: pending_migrations, schema_drift&lt;/code&gt;, código 1.&lt;/li&gt;
&lt;li&gt;Después de migrar: &lt;code&gt;Check status: ok&lt;/code&gt;, código 0.&lt;/li&gt;
&lt;li&gt;Tras la columna &lt;code&gt;debug_flag&lt;/code&gt; agregada a mano: &lt;code&gt;Failed checks: schema_drift&lt;/code&gt;, código 1.&lt;/li&gt;
&lt;li&gt;Tras agregar una línea a un archivo de migración ya aplicado: &lt;code&gt;Failed checks: checksum_mismatch&lt;/code&gt;, código 1. &lt;code&gt;chkit status&lt;/code&gt; nombró el archivo; revertir el cambio lo resolvió.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;El workflow de GitHub Actions para pull requests que trae la documentación es:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Schema Validation&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pull_request&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;validate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;oven-sh/setup-bun@v2&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;bun-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;1.3.5'&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bun install --frozen-lockfile&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Check schema consistency&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bunx chkit check --strict --json&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Verify generated types&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bunx chkit codegen --check --json&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;--strict&lt;/code&gt; activa todas las políticas sin importar el archivo de configuración, que es lo que quieres en CI. Un requisito que el ejemplo no muestra: &lt;code&gt;check&lt;/code&gt; necesita llegar a un servidor ClickHouse, porque el registro de migraciones vive ahí. Sin conexión se detiene con "clickhouse config is required for check". El ejemplo de despliegue de la misma guía pasa &lt;code&gt;CLICKHOUSE_URL&lt;/code&gt;, &lt;code&gt;CLICKHOUSE_USER&lt;/code&gt;, &lt;code&gt;CLICKHOUSE_PASSWORD&lt;/code&gt; y &lt;code&gt;CLICKHOUSE_DB&lt;/code&gt; desde los &lt;em&gt;secrets&lt;/em&gt;; el job de validación también los necesita.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué hace chkit con las migraciones destructivas?
&lt;/h2&gt;

&lt;p&gt;Las bloquea, salvo que digas lo contrario. Quitamos la columna &lt;code&gt;source&lt;/code&gt; del esquema y &lt;code&gt;generate&lt;/code&gt; escribió:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- operation: alter_table_drop_column key=table:default.events:column:source risk=danger&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="k"&gt;DROP&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="nv"&gt;`source`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Al ejecutar &lt;code&gt;migrate --apply&lt;/code&gt; sin terminal, como en CI, se negó con un código de advertencia (&lt;code&gt;drop_column_irreversible&lt;/code&gt;), el motivo, el impacto y una recomendación, y nos pidió repetir con &lt;code&gt;--allow-destructive&lt;/code&gt;. Con esa opción, se aplicó.&lt;/p&gt;

&lt;p&gt;Una diferencia con la documentación: dice que una migración destructiva bloqueada termina con código &lt;code&gt;3&lt;/code&gt; en ejecuciones no interactivas. En nuestras pruebas terminó con &lt;code&gt;3&lt;/code&gt; solo con &lt;code&gt;--json&lt;/code&gt;; en modo texto, con la entrada cerrada y también con &lt;code&gt;CI=true&lt;/code&gt;, terminó con &lt;code&gt;1&lt;/code&gt;. Ambos hacen fallar el job, así que nada se cuela, pero si tu pipeline separa el código 3 para mandar los cambios destructivos a un job con aprobación manual, como sugiere la documentación, usa &lt;code&gt;--json&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿chkit genera tipos de TypeScript desde las tablas de ClickHouse?
&lt;/h2&gt;

&lt;p&gt;Sí, con &lt;code&gt;@chkit/plugin-codegen&lt;/code&gt;. Con el plugin registrado en &lt;code&gt;clickhouse.config.ts&lt;/code&gt; (&lt;code&gt;codegen({ outFile: './src/generated/chkit-types.ts' })&lt;/code&gt;), &lt;code&gt;chkit codegen&lt;/code&gt; escribió:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;DefaultEventsRow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="na"&gt;country&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="na"&gt;ingested_at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;UInt64&lt;/code&gt; y &lt;code&gt;DateTime64&lt;/code&gt; salen como &lt;code&gt;string&lt;/code&gt;, que coincide con cómo ClickHouse los devuelve en JSON. El plugin también puede generar esquemas de Zod, y &lt;code&gt;chkit codegen --check&lt;/code&gt; hace fallar el CI cuando el archivo generado quedó desactualizado.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Funciona chkit con Python?
&lt;/h2&gt;

&lt;p&gt;Sí, con una diferencia que conviene conocer. &lt;code&gt;pip install chkit-py&lt;/code&gt; instala la versión 0.2.0, que la documentación marca como alfa. &lt;code&gt;init&lt;/code&gt;, &lt;code&gt;generate&lt;/code&gt;, &lt;code&gt;migrate --apply&lt;/code&gt; y &lt;code&gt;check&lt;/code&gt; funcionaron en nuestra prueba.&lt;/p&gt;

&lt;p&gt;La diferencia está en el drift. Por defecto, &lt;code&gt;chkit drift&lt;/code&gt; en Python compara el snapshot con tus archivos de esquema locales, no con la base en vivo. Tras agregar la misma columna a mano, &lt;code&gt;drift&lt;/code&gt; en Python indicó &lt;code&gt;Drifted: no&lt;/code&gt;, y &lt;code&gt;chkit check --strict&lt;/code&gt; terminó con código &lt;code&gt;0&lt;/code&gt;. Al agregar &lt;code&gt;--live&lt;/code&gt;, ambos la detectaron: &lt;code&gt;drift --live&lt;/code&gt; reportó &lt;code&gt;extra_column&lt;/code&gt; y &lt;code&gt;check --live&lt;/code&gt; falló con &lt;code&gt;schema_drift&lt;/code&gt;, código 1.&lt;/p&gt;

&lt;p&gt;Al 22 de octubre de 2026, &lt;code&gt;--live&lt;/code&gt; solo aparece en la página de Kafka de la documentación, y el workflow de Python de la guía de CI ejecuta &lt;code&gt;chkit check --strict --json&lt;/code&gt; sin esa opción, mientras afirma que las opciones son las mismas que en TypeScript. Si usas la versión de Python en CI, agrega &lt;code&gt;--live&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Es chkit como Drizzle ORM?
&lt;/h2&gt;

&lt;p&gt;En el flujo de trabajo, sí; en el alcance, no. Drizzle ORM es el ORM de TypeScript con el que muchos equipos definen su esquema y generan migraciones para bases relacionales. chkit copia ese ciclo (esquema en código, &lt;code&gt;generate&lt;/code&gt;, &lt;code&gt;migrate&lt;/code&gt;) y lo lleva a ClickHouse, pero no es un ORM: no construye consultas desde tu código. Si tu equipo ya escribe el esquema de Postgres en Drizzle y el DDL de ClickHouse es lo único que sigue a mano, ese es el hueco que llena.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué otras herramientas de migración de base de datos hay para ClickHouse?
&lt;/h2&gt;

&lt;p&gt;La propia base de conocimiento de ClickHouse lista una docena. La mayoría son ejecutores imperativos que aplican archivos SQL versionados en orden: golang-migrate, Goose, Flyway, Liquibase y ejecutores específicos de ClickHouse para Node.js y Python. Atlas y Ptah son declarativos como chkit y también detectan drift.&lt;/p&gt;

&lt;p&gt;Lo que aporta chkit es el enfoque centrado en TypeScript: el esquema vive en el mismo lenguaje que tu aplicación, los tipos se generan a partir de él y una sola CLI cubre generate, migrate, drift y la validación en CI. Y si lo que buscas es explorar esa base desde el navegador, ya vimos &lt;a href="https://www.yodev.dev/t/alternativa-a-dbeaver-en-el-navegador-como-desplegar-libredb-studio-con-docker-o-helm/5472" rel="noopener noreferrer"&gt;cómo desplegar LibreDB Studio con Docker o Helm&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Vale la pena usar chkit?
&lt;/h2&gt;

&lt;p&gt;Si usas ClickHouse junto a un código en TypeScript y tus cambios de esquema hoy viven en archivos SQL sueltos o en la memoria de alguien, chkit merece una tarde. El SQL generado se lee bien, la protección contra cambios destructivos funciona y la detección de drift encontró una columna agregada a mano que de otra forma habría pasado desapercibida.&lt;/p&gt;

&lt;p&gt;Fija la versión, porque la 1.0 todavía puede traer pequeños cambios incompatibles. Y si trabajas en Python, trata esa versión como la alfa que dice ser y usa &lt;code&gt;--live&lt;/code&gt;.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;¿Y tú?&lt;/strong&gt; ¿Qué cambio de esquema hecho a mano en producción te costó más descubrir?&lt;/p&gt;

&lt;p&gt;Comenta abajo o, si este artículo te llegó por correo, responde directamente al email: tu respuesta se publica aquí.&lt;/p&gt;

&lt;p&gt;Relacionado: &lt;a href="https://www.yodev.dev/t/alternativa-a-dbeaver-en-el-navegador-como-desplegar-libredb-studio-con-docker-o-helm/5472" rel="noopener noreferrer"&gt;Alternativa a DBeaver en el navegador: cómo desplegar LibreDB Studio con Docker o Helm&lt;/a&gt;&lt;/p&gt;

</description>
      <category>database</category>
      <category>opensource</category>
      <category>typescript</category>
    </item>
    <item>
      <title>earstrip vs earcut: probamos la triangulación de 3,7 millones de polígonos de OpenStreetMap ✅ yoDEV Tested</title>
      <dc:creator>Grego</dc:creator>
      <pubDate>Sun, 25 Oct 2026 15:25:56 +0000</pubDate>
      <link>https://dev.to/yodev_grego/earstrip-vs-earcut-probamos-la-triangulacion-de-37-millones-de-poligonos-de-openstreetmap-yodev-1c81</link>
      <guid>https://dev.to/yodev_grego/earstrip-vs-earcut-probamos-la-triangulacion-de-37-millones-de-poligonos-de-openstreetmap-yodev-1c81</guid>
      <description>&lt;p&gt;earstrip es un reemplazo directo de earcut para la triangulación de polígonos en WebGL. En nuestra prueba fue unas 6 veces más rápido con polígonos con miles de huecos, y dibujó mucho mejor los polígonos rotos. Con polígonos de mapa comunes, en x86, la ventaja fue de apenas 1,1–1,2 veces, lejos de las cifras que el autor midió en Apple silicon.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/GLMap/earstrip" rel="noopener noreferrer"&gt;https://github.com/GLMap/earstrip&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;✅ yoDEV Tested&lt;/strong&gt; · 23 de octubre de 2026 Corrimos earstrip 0.2.0 contra earcut 3.2.4 (npm) y earcut.hpp 3.2.4 (C++) sobre los 5,7 millones de polígonos de OpenStreetMap que publica el autor, en una VM x86 con Intel Xeon, Node 22, 24 y 26, GCC 13 y Clang 18. Los resultados que reportamos como nuestros salen de esa prueba.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  ¿Qué es la triangulación de polígonos y para qué sirven earcut y earstrip?
&lt;/h2&gt;

&lt;p&gt;La triangulación de polígonos convierte cualquier contorno en un conjunto de triángulos, que es lo único que una GPU sabe rellenar. Cada edificio, parque o lago que dibuja un mapa web o una escena en WebGL pasa primero por ese paso. earcut, de Mapbox, es la librería que usa la mayoría de los stacks de mapas web para hacerlo: le pasas las coordenadas planas y los índices donde empieza cada hueco, y te devuelve tres índices de vértice por triángulo.&lt;/p&gt;

&lt;p&gt;earstrip es el triangulador del motor de mapas móviles GLMap. Globus Software lo publicó como librería independiente el 16 de octubre de 2026 y viene en dos formatos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;un único archivo de cabecera C++17 (&lt;em&gt;header-only&lt;/em&gt;);&lt;/li&gt;
&lt;li&gt;un build de WebAssembly en npm cuya llamada principal recibe exactamente los mismos argumentos que earcut.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Se diferencia de earcut en dos puntos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Triangle strips.&lt;/strong&gt; Recorta las "orejas" del polígono (&lt;em&gt;ear clipping&lt;/em&gt;) siguiendo tiras en zigzag, así que su salida nativa necesita unos 1,7 índices por triángulo en lugar de 3.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Anillos rotos.&lt;/strong&gt; Cuando los anillos de un polígono se cruzan o se tocan, recurre a una triangulación de Delaunay restringida (&lt;em&gt;constrained Delaunay&lt;/em&gt;) en lugar de devolver los triángulos que hayan quedado.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;La licencia es ISC, la misma que la de earcut.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo reemplazar earcut por earstrip?
&lt;/h2&gt;

&lt;p&gt;Instalas el paquete y cambias el import; ese es todo el diff:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;earstrip

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;- import earcut from 'earcut';
&lt;/span&gt;&lt;span class="gi"&gt;+ import earstrip from 'earstrip';
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gd"&gt;- const triangles = earcut(vertices, holes, dimensions);
&lt;/span&gt;&lt;span class="gi"&gt;+ const triangles = earstrip(vertices, holes, dimensions);
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si tus datos vienen en GeoJSON, earstrip trae su propio &lt;code&gt;flatten()&lt;/code&gt;. En nuestra prueba su salida fue idéntica a la del &lt;code&gt;flatten()&lt;/code&gt; de earcut:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;earstrip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;flatten&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;earstrip&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;vertices&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;holes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dimensions&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;flatten&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;geojsonPolygon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;coordinates&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;triangles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;earstrip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;vertices&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;holes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dimensions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tres notas prácticas de la prueba:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Formato del módulo.&lt;/strong&gt; El paquete es solo ESM. En Node 22, &lt;code&gt;require('earstrip')&lt;/code&gt; igual nos funcionó gracias al soporte &lt;code&gt;require(esm)&lt;/code&gt; de Node.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Carga.&lt;/strong&gt; El módulo WebAssembly viene incrustado y compila de forma síncrona donde la plataforma lo permite. Donde no, el README indica hacer &lt;code&gt;await ready&lt;/code&gt; antes de la primera llamada (&lt;code&gt;import { ready } from 'earstrip'&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;C++.&lt;/strong&gt; Copia &lt;code&gt;include/earstrip.hpp&lt;/code&gt; a tu proyecto. Necesita C++17 y nada más que la biblioteca estándar. La suite de tests en C++ del repositorio pasó completa en nuestra máquina.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ¿earstrip es más rápido que earcut?
&lt;/h2&gt;

&lt;p&gt;Depende de tus polígonos y de la máquina. Usamos los datos de benchmark del propio autor, con los checksums verificados: extractos de OpenStreetMap del voivodato de Mazovia (Polonia) y las teselas del mapa mundial de GLMap. El harness fue nuestro, contra los paquetes de npm, con un hilo y el mejor de 5 corridas.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Prueba&lt;/th&gt;
&lt;th&gt;Autor (Apple M4 Pro)&lt;/th&gt;
&lt;th&gt;yoDEV (x86 Xeon)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;3,74 M polígonos de mapa, llamada drop-in, V8&lt;/td&gt;
&lt;td&gt;1,44× más rápido&lt;/td&gt;
&lt;td&gt;1,08–1,19× más rápido&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Igual, la API más rápida (&lt;code&gt;direct.batch&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;1,74× más rápido&lt;/td&gt;
&lt;td&gt;1,21–1,38× más rápido&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;56 mil polígonos del mapa mundial, hasta 11.674 huecos en uno&lt;/td&gt;
&lt;td&gt;7,4× más rápido&lt;/td&gt;
&lt;td&gt;5,6–6,0× más rápido&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C++ nativo vs earcut.hpp, 3,74 M polígonos&lt;/td&gt;
&lt;td&gt;13% más rápido&lt;/td&gt;
&lt;td&gt;GCC 13: empate · Clang 18: 12% más rápido&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C++ nativo, mapa mundial&lt;/td&gt;
&lt;td&gt;6,3× más rápido&lt;/td&gt;
&lt;td&gt;4,0× más rápido (GCC 13)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Con polígonos con muchos huecos, la promesa se cumple.&lt;/strong&gt; En el set mundial, earcut necesitó unos 10,2 segundos en Node y earstrip entre 1,7 y 1,9. Es justo el caso donde earcut paga caro por unir cada hueco al contorno, y earstrip manda directo a su ruta de Delaunay los polígonos con más de 128 anillos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Con polígonos de mapa comunes, la ganancia es mucho menor.&lt;/strong&gt; En nuestra máquina x86 la llamada drop-in fue entre 8 y 19 por ciento más rápida en Node 22, 24 y 26. El README reporta 44 por ciento para V8 en un M4 Pro.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;En C++ nativo, depende del compilador.&lt;/strong&gt; Hubo empate con GCC y una ventaja de 12 por ciento con Clang, así que la ventaja con datos cotidianos parece sensible al compilador y a la CPU. No investigamos por qué; reportamos lo que medimos.&lt;/p&gt;

&lt;p&gt;Si tus datos se parecen a los nuestros y la velocidad es tu motivo para cambiar, haz un benchmark primero en el hardware donde realmente corre tu código.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué pasa con los polígonos que se cruzan a sí mismos?
&lt;/h2&gt;

&lt;p&gt;earstrip los dibuja bien, y esta parte de lo que promete el autor se reprodujo con exactitud. Los datos de mapa redondeados a una grilla de teselas suelen terminar con anillos que se cruzan o se tocan, y el &lt;em&gt;ear clipping&lt;/em&gt; asume que eso no pasa. El set principal tiene 82 polígonos que las orejas no pueden cortar de forma exacta. En ellos, los triángulos de earstrip se alejaron del relleno correcto (&lt;em&gt;even-odd&lt;/em&gt;) en un 0,15 por ciento de los píxeles en promedio, y los de earcut.hpp en un 30,7 por ciento. El autor reporta 0,15 y 31.&lt;/p&gt;

&lt;p&gt;Un ejemplo mínimo muestra la diferencia. Toma un polígono en forma de corbatín que se cruza a sí mismo (&lt;code&gt;[0,0, 10,10, 10,0, 0,10]&lt;/code&gt;):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;earcut devolvió un solo triángulo y rellenó solo uno de los dos lóbulos.&lt;/li&gt;
&lt;li&gt;earstrip devolvió dos triángulos que cubren ambos, y &lt;code&gt;lastStatus()&lt;/code&gt; informó &lt;code&gt;approximate&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ese estado le permite a tu código saber cómo se resolvió cada polígono. Los valores posibles son &lt;code&gt;exact&lt;/code&gt;, &lt;code&gt;constrained&lt;/code&gt;, &lt;code&gt;holes-left-out&lt;/code&gt;, &lt;code&gt;approximate&lt;/code&gt; y &lt;code&gt;refused&lt;/code&gt;. En el set de 3,74 millones de polígonos, todos salvo 82 volvieron como &lt;code&gt;exact&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué son los triangle strips y los necesitas en WebGL?
&lt;/h2&gt;

&lt;p&gt;Un &lt;em&gt;triangle strip&lt;/em&gt; es una lista de índices donde cada índice nuevo forma un triángulo con los dos anteriores. La GPU dibuja n triángulos con unos n + 2 índices en lugar de 3n. earstrip escribe tiras de forma nativa:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1,66 índices por triángulo tanto en el set principal como en el mundial, contra 3 de una lista de triángulos normal;&lt;/li&gt;
&lt;li&gt;1,95 en un set de polígonos casi todos pequeños y simples, donde la ganancia es menor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;La llamada drop-in &lt;code&gt;earstrip()&lt;/code&gt; vuelve a convertir las tiras en una lista de triángulos al estilo earcut, así que ese ahorro solo lo obtienes con las otras APIs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;strips()&lt;/code&gt; devuelve las tiras tal cual.&lt;/li&gt;
&lt;li&gt;Las llamadas &lt;code&gt;direct&lt;/code&gt; escriben el polígono directamente en la memoria de WebAssembly y devuelven un solo index buffer listo para &lt;code&gt;TRIANGLE_STRIP&lt;/code&gt; en WebGL 2 o WebGPU. Esa ruta fue además la más rápida en nuestro benchmark.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;strips&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;earstrip&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;indices&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ends&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;clockwise&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;strips&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;vertices&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;holes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ¿Conviene cambiar de earcut a earstrip?
&lt;/h2&gt;

&lt;p&gt;Cámbiate si:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tus datos tienen polígonos con muchos huecos (costas, bosques con claros, teselas mundiales). La aceleración de 5 a 6 veces se reprodujo.&lt;/li&gt;
&lt;li&gt;Renderizas datos de mapa reales que pueden traer anillos que se cruzan o se tocan, y ya has visto errores de relleno.&lt;/li&gt;
&lt;li&gt;Controlas el index buffer y puedes usar tiras en WebGL 2 o WebGPU.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Piénsalo dos veces si:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tus polígonos son pequeños y simples y la velocidad es tu único motivo.&lt;/strong&gt; En x86 la ganancia que medimos fue modesta.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;El tamaño del bundle importa.&lt;/strong&gt; Tal como se publica, el JavaScript de earstrip más su WebAssembly incrustado sumó unos 41 KB con gzip, frente a unos 13 KB del código fuente de earcut sin minificar. La cifra de 27 KB del README corresponde solo al binario WebAssembly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Necesitas una API estable.&lt;/strong&gt; Al momento de publicar esta nota (23 de octubre de 2026), earstrip está en la versión 0.2.0, publicada tres días antes. Considera estable la llamada compatible con earcut; el resto puede cambiar antes de la 1.0.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;¿Y tú?&lt;/strong&gt; ¿Qué librería usas hoy para triangular polígonos en tu stack de mapas o WebGL?&lt;/p&gt;

&lt;p&gt;Comenta abajo o, si este artículo te llegó por correo, responde directamente al email: tu respuesta se publica aquí.&lt;/p&gt;

&lt;p&gt;Relacionado: &lt;a href="https://www.yodev.dev/t/node-ffi-en-node-js-26-9-como-llamar-a-una-libreria-de-c-sin-compilar-un-addon-nativo/5481" rel="noopener noreferrer"&gt;Node:ffi en Node.js 26.9: cómo llamar a una librería de C sin compilar un addon nativo&lt;/a&gt;&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>javascript</category>
      <category>performance</category>
      <category>programming</category>
    </item>
    <item>
      <title>RAG-Anything: Cómo Hacer RAG con PDFs que Tienen Imágenes, Tablas y Ecuaciones</title>
      <dc:creator>Grego</dc:creator>
      <pubDate>Sun, 25 Oct 2026 15:20:53 +0000</pubDate>
      <link>https://dev.to/yodev_grego/rag-anything-como-hacer-rag-con-pdfs-que-tienen-imagenes-tablas-y-ecuaciones-2f8</link>
      <guid>https://dev.to/yodev_grego/rag-anything-como-hacer-rag-con-pdfs-que-tienen-imagenes-tablas-y-ecuaciones-2f8</guid>
      <description>&lt;p&gt;RAG-Anything es un framework open source en Python para chatear con tus PDFs y documentos de Office sin perder sus imágenes, tablas ni ecuaciones. En lugar de aplanar el archivo a texto plano, separa cada elemento, lo describe con un modelo de lenguaje o de visión y lo conecta todo en un grafo de conocimiento que puedes consultar en lenguaje natural. Lo desarrolla HKUDS, el laboratorio de la Universidad de Hong Kong detrás de LightRAG, tiene licencia MIT y supera las 24.100 estrellas en GitHub.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fworkplace.yodev.dev%2Fapi%2Fworkspaces%2Fefea03b1-669a-4289-94fa-8bbc61ecd64d%2Fblobs%2F7uvw2pYLPqrkLsyB9i-g74Urcl0L7PwdK9YolRrXEQI%3D%3Ftoken%3Defea03b1-669a-4289-94fa-8bbc61ecd64d%253A7uvw2pYLPqrkLsyB9i-g74Urcl0L7PwdK9YolRrXEQI%253D%253A1792945253297%252CMEYCIQDth9t9iXvU0qRCxpW7M6XybjUn5hPy9R7VlbNNTmLm6gIhAO3DYwprMRm5ov3ys4jbp%252FFPZuHHO7Axbmy%252FgSJ%252FDoIx" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fworkplace.yodev.dev%2Fapi%2Fworkspaces%2Fefea03b1-669a-4289-94fa-8bbc61ecd64d%2Fblobs%2F7uvw2pYLPqrkLsyB9i-g74Urcl0L7PwdK9YolRrXEQI%3D%3Ftoken%3Defea03b1-669a-4289-94fa-8bbc61ecd64d%253A7uvw2pYLPqrkLsyB9i-g74Urcl0L7PwdK9YolRrXEQI%253D%253A1792945253297%252CMEYCIQDth9t9iXvU0qRCxpW7M6XybjUn5hPy9R7VlbNNTmLm6gIhAO3DYwprMRm5ov3ys4jbp%252FFPZuHHO7Axbmy%252FgSJ%252FDoIx" width="708" height="330"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/HKUDS/RAG-Anything" rel="noopener noreferrer"&gt;https://github.com/HKUDS/RAG-Anything&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué es RAG-Anything?
&lt;/h2&gt;

&lt;p&gt;RAG-Anything es un pipeline de RAG multimodal (&lt;code&gt;multimodal RAG&lt;/code&gt;) construido sobre LightRAG. Cubre todo el recorrido, desde la ingesta del documento hasta la respuesta, en cuatro etapas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Parsing.&lt;/strong&gt; Un parser divide el archivo en bloques de texto, imágenes, tablas y ecuaciones, y registra la página de la que viene cada uno.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Análisis por tipo.&lt;/strong&gt; Cada elemento pasa por su propio procesador. Un modelo de visión escribe descripciones de las imágenes teniendo en cuenta el contexto, las tablas se interpretan como datos estructurados y las ecuaciones se procesan en LaTeX.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Grafo de conocimiento.&lt;/strong&gt; Los elementos se convierten en entidades relacionadas con el texto que los rodea. Una cadena de relaciones &lt;code&gt;belongs_to&lt;/code&gt; conserva la jerarquía de secciones del documento.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recuperación híbrida.&lt;/strong&gt; Las consultas combinan búsqueda vectorial con recorrido del grafo, así que una respuesta puede traer un párrafo junto con el gráfico que lo explica. Es la idea detrás del &lt;code&gt;knowledge graph RAG&lt;/code&gt; o &lt;code&gt;graph RAG&lt;/code&gt;, extendida a contenido que no es texto.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Acepta PDFs, documentos de Office (DOC, DOCX, PPT, PPTX, XLS, XLSX), imágenes (JPG, PNG, BMP, TIFF, GIF, WebP) y archivos de texto (TXT, MD). Las versiones recientes también aceptan audio y video, que vemos más abajo.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Por qué el RAG tradicional falla con PDFs que tienen tablas y gráficos?
&lt;/h2&gt;

&lt;p&gt;Porque un pipeline de RAG típico extrae la capa de texto del PDF, la corta en fragmentos y genera embeddings de esos fragmentos. Todo lo que no es texto corrido se pierde por el camino:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Un gráfico de barras desaparece.&lt;/li&gt;
&lt;li&gt;Una tabla se convierte en una lista de números sin los encabezados de sus columnas.&lt;/li&gt;
&lt;li&gt;Una fórmula queda como caracteres rotos.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;En documentación técnica, reportes financieros y papers de investigación, la respuesta suele estar justo ahí.&lt;/p&gt;

&lt;p&gt;RAG-Anything trata esos elementos como contenido de primera clase. Un gráfico lo describe un modelo de visión y se guarda como una entidad vinculada al párrafo que lo menciona. Una tabla conserva su estructura y su leyenda.&lt;/p&gt;

&lt;p&gt;El enfoque está descrito en el reporte técnico de los autores en arXiv (2510.12323, octubre de 2025). Según los propios autores, supera a los métodos existentes en benchmarks multimodales, con las mayores ventajas en documentos largos. Son resultados reportados por el equipo que creó la herramienta, y el reporte es un preprint.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué diferencia hay entre LightRAG y RAG-Anything?
&lt;/h2&gt;

&lt;p&gt;LightRAG es el motor y RAG-Anything es la capa multimodal que va encima. LightRAG aporta la indexación basada en grafos, el almacenamiento y los modos de consulta. RAG-Anything suma los parsers, los procesadores por tipo de contenido y las relaciones entre texto, imágenes, tablas y ecuaciones dentro del grafo.&lt;/p&gt;

&lt;p&gt;Los dos proyectos están muy conectados:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Si ya tienes una base de conocimiento en LightRAG, puedes pasar esa instancia a RAG-Anything. Hereda el directorio de trabajo, la función del LLM y la de embeddings, y puedes agregar documentos multimodales al mismo almacenamiento.&lt;/li&gt;
&lt;li&gt;Desde junio de 2026, el propio LightRAG habilita RAG multimodal mediante una integración nativa de RAG-Anything.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Regla práctica: si tus documentos son casi todo prosa, con LightRAG te alcanza. Si las respuestas están en figuras, tablas o fórmulas, necesitas la capa de RAG-Anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿RAG-Anything o MarkItDown?
&lt;/h2&gt;

&lt;p&gt;Depende de si necesitas un sistema de RAG completo o solo convertir documentos para dárselos a un modelo. &lt;a href="https://www.yodev.dev/t/markitdown-la-herramienta-de-microsoft-que-convierte-cualquier-documento-en-contexto-para-tu-ia/2232" rel="noopener noreferrer"&gt;MarkItDown&lt;/a&gt; es una utilidad ligera de Microsoft que convierte PDFs, Office, imágenes, audio, HTML y EPUB a Markdown, conservando títulos, listas, tablas y enlaces. Está pensada para alimentar LLMs, pero solo convierte: no indexa ni recupera nada.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;MarkItDown&lt;/th&gt;
&lt;th&gt;RAG-Anything&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Qué produce&lt;/td&gt;
&lt;td&gt;Un archivo Markdown&lt;/td&gt;
&lt;td&gt;Un grafo de conocimiento consultable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Imágenes&lt;/td&gt;
&lt;td&gt;EXIF y OCR; descripciones con LLM opcionales para PPTX e imágenes&lt;/td&gt;
&lt;td&gt;Descripción con modelo de visión de cada imagen, vinculada al texto&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Búsqueda y respuestas&lt;/td&gt;
&lt;td&gt;No incluye&lt;/td&gt;
&lt;td&gt;Recuperación híbrida vectorial y de grafo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Modelos necesarios&lt;/td&gt;
&lt;td&gt;Ninguno para la conversión básica&lt;/td&gt;
&lt;td&gt;LLM, modelo de visión y embeddings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Instalación&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pip install 'markitdown[all]'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pip install raganything&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Si vas a pegar un documento en el contexto de Claude Code o de tu agente, MarkItDown es la herramienta más directa. Si tienes una carpeta con cientos de documentos y quieres hacerles preguntas cuyas respuestas están en gráficos y tablas, RAG-Anything es la opción.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo se instala RAG-Anything?
&lt;/h2&gt;

&lt;p&gt;Se instala desde PyPI y requiere Python 3.9 o superior:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install raganything

# Extras opcionales para más formatos
pip install 'raganything[all]'
pip install 'raganything[image]'   # BMP, TIFF, GIF, WebP
pip install 'raganything[text]'    # TXT, MD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si prefieres trabajar desde el código fuente, el proyecto usa &lt;code&gt;uv&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/HKUDS/RAG-Anything.git
cd RAG-Anything
uv sync
uv sync --all-extras   # todas las funciones opcionales
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hay dos cosas que &lt;code&gt;pip&lt;/code&gt; no instala por ti:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;LibreOffice&lt;/strong&gt; es obligatorio para procesar documentos de Office. En macOS es &lt;code&gt;brew install --cask libreoffice&lt;/code&gt;, en Ubuntu/Debian &lt;code&gt;sudo apt-get install libreoffice&lt;/code&gt;, y en Windows, el instalador del sitio oficial.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Los modelos de MinerU&lt;/strong&gt; se descargan automáticamente la primera vez que procesas un documento.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para comprobar que el parser está listo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mineru --version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ¿MinerU, Docling o PaddleOCR: qué parser conviene usar?
&lt;/h2&gt;

&lt;p&gt;Empieza con MinerU, que es el parser por defecto, salvo que tu corpus sea casi todo Office: en ese caso prueba Docling. RAG-Anything soporta tres parsers y eliges uno con el argumento &lt;code&gt;parser&lt;/code&gt; o la variable de entorno &lt;code&gt;PARSER&lt;/code&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parser&lt;/th&gt;
&lt;th&gt;Ideal para&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;MinerU&lt;/strong&gt; (por defecto)&lt;/td&gt;
&lt;td&gt;PDFs, imágenes y Office; OCR y extracción de tablas sólidos; aceleración por GPU&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Docling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Documentos de Office y HTML; conserva mejor la estructura del documento&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PaddleOCR&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Trabajo intensivo de OCR sobre PDFs escaneados e imágenes; convierte Office/TXT/MD a PDF primero&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;PaddleOCR necesita su propio extra (&lt;code&gt;pip install 'raganything[paddleocr]'&lt;/code&gt;) y además una versión de &lt;code&gt;paddlepaddle&lt;/code&gt; para tu plataforma, que se instala siguiendo su guía oficial.&lt;/p&gt;

&lt;p&gt;El método de parsing puede ser &lt;code&gt;auto&lt;/code&gt;, &lt;code&gt;ocr&lt;/code&gt; o &lt;code&gt;txt&lt;/code&gt;. MinerU también acepta opciones como &lt;code&gt;device&lt;/code&gt; (&lt;code&gt;cpu&lt;/code&gt;, &lt;code&gt;cuda&lt;/code&gt;, &lt;code&gt;mps&lt;/code&gt;), un rango de páginas y &lt;code&gt;lang&lt;/code&gt; para el OCR.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo chatear con tus PDFs usando RAG-Anything?
&lt;/h2&gt;

&lt;p&gt;Configuras tres funciones de modelo (un LLM, un modelo de visión y una función de embeddings), procesas el archivo y lo consultas. Las llamadas principales son estas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RAGAnythingConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;working_dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;./rag_storage&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mineru&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;parse_method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;auto&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;enable_image_processing&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;enable_table_processing&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;enable_equation_processing&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;rag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RAGAnything&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;llm_model_func&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;llm_model_func&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;vision_model_func&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;vision_model_func&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;embedding_func&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;embedding_func&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;rag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;process_document_complete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;file_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;path/to/your/document.pdf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;output_dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;./output&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;parse_method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;auto&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;rag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;aquery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;What are the main findings shown in the figures and tables?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hybrid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Las definiciones completas de las tres funciones de modelo están en el README. El ejemplo oficial las conecta a la API de OpenAI, y el parámetro &lt;code&gt;base_url&lt;/code&gt; te permite apuntarlas a cualquier endpoint compatible.&lt;/p&gt;

&lt;p&gt;Hay tres formas de consultar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Consultas de texto&lt;/strong&gt;, con los modos de LightRAG: &lt;code&gt;hybrid&lt;/code&gt;, &lt;code&gt;local&lt;/code&gt;, &lt;code&gt;global&lt;/code&gt; y &lt;code&gt;naive&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consultas mejoradas con VLM&lt;/strong&gt;, que se activan solas cuando hay un modelo de visión configurado. Si el contexto recuperado incluye imágenes, se envían las imágenes mismas al modelo de visión, no solo sus descripciones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consultas multimodales&lt;/strong&gt; (&lt;code&gt;aquery_with_multimodal&lt;/code&gt;), que te permiten incluir una tabla o una ecuación en LaTeX dentro de la propia pregunta.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para procesar una carpeta completa, &lt;code&gt;process_folder_complete&lt;/code&gt; recibe una lista de extensiones, un flag &lt;code&gt;recursive&lt;/code&gt; y &lt;code&gt;max_workers&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Si ya procesaste tus documentos con otra herramienta, &lt;code&gt;insert_content_list&lt;/code&gt; acepta contenido ya parseado y se salta el parsing por completo.&lt;/p&gt;

&lt;p&gt;El repositorio incluye un script de punta a punta listo para usar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python examples/raganything_example.py path/to/document.pdf --api-key YOUR_API_KEY --parser mineru
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ¿RAG-Anything puede procesar audio y video?
&lt;/h2&gt;

&lt;p&gt;Sí, desde las versiones 1.4.x (septiembre de 2026). Las dos funciones son opcionales.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Audio&lt;/strong&gt; (.mp3, .wav, .flac, .m4a, .ogg)

&lt;ul&gt;
&lt;li&gt;Instala con &lt;code&gt;pip install 'raganything[audio]'&lt;/code&gt; y activa &lt;code&gt;enable_audio_processing=True&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;La transcripción se hace en local con faster-whisper, usando el modelo que indiques en &lt;code&gt;WHISPER_MODEL&lt;/code&gt; (por defecto, &lt;code&gt;base&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Video&lt;/strong&gt; (.mp4, .mov, .webm, .avi, .mkv)

&lt;ul&gt;
&lt;li&gt;Instala con &lt;code&gt;pip install 'raganything[video]'&lt;/code&gt;, que además necesita &lt;code&gt;ffmpeg&lt;/code&gt; en tu PATH, y activa &lt;code&gt;enable_video_processing=True&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;El pipeline detecta escenas con SceneDetect, describe los fotogramas clave con el modelo de visión, transcribe la pista de audio y lo une todo por marca de tiempo.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Los archivos multimedia entran en la misma base de conocimiento que tus documentos. Así, una sola pregunta puede apoyarse a la vez en la especificación en PDF y en la grabación de una revisión de diseño.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿RAG-Anything es gratis?
&lt;/h2&gt;

&lt;p&gt;El framework es gratuito y tiene licencia MIT, pero ejecutarlo no necesariamente lo es, porque llama a tres modelos: un LLM, un modelo de visión para las imágenes y un modelo de embeddings. Si usas APIs alojadas, pagas por tokens al indexar, ya que cada imagen y cada tabla pasa por un modelo, y otra vez al consultar.&lt;/p&gt;

&lt;p&gt;Algunas partes corren en local sin costo de API:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Los modelos de los parsers (MinerU, Docling, PaddleOCR).&lt;/li&gt;
&lt;li&gt;La transcripción de audio con faster-whisper.&lt;/li&gt;
&lt;li&gt;Los scripts de prueba de parsing incluidos (&lt;code&gt;office_document_test.py&lt;/code&gt;, &lt;code&gt;image_format_test.py&lt;/code&gt;, &lt;code&gt;text_format_test.py&lt;/code&gt;), que ejercitan el parser sin API key.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Por eso son una buena forma de comprobar qué tan bien se parsean tus documentos antes de gastar en la indexación.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;¿Y tú?&lt;/strong&gt; ¿Qué documentos te gustaría poder consultar con un RAG multimodal en tu trabajo?&lt;/p&gt;

&lt;p&gt;Comenta abajo o, si este artículo te llegó por correo, responde directamente al email: tu respuesta se publica aquí.&lt;/p&gt;

&lt;p&gt;Relacionado: &lt;a href="https://www.yodev.dev/t/building-the-entire-rag-ecosystem-and-optimizing-every-component/976" rel="noopener noreferrer"&gt;Building the Entire RAG Ecosystem and Optimizing Every Component&lt;/a&gt;&lt;/p&gt;

</description>
      <category>llm</category>
      <category>opensource</category>
      <category>python</category>
      <category>rag</category>
    </item>
    <item>
      <title>¿Cómo Reducir los Tokens de Razonamiento de Gemma 4? ThinkingCap Explicado</title>
      <dc:creator>Grego</dc:creator>
      <pubDate>Sat, 24 Oct 2026 18:43:53 +0000</pubDate>
      <link>https://dev.to/yodev_grego/como-reducir-los-tokens-de-razonamiento-de-gemma-4-thinkingcap-explicado-28ae</link>
      <guid>https://dev.to/yodev_grego/como-reducir-los-tokens-de-razonamiento-de-gemma-4-thinkingcap-explicado-28ae</guid>
      <description>&lt;p&gt;ThinkingCap es una versión reentrenada de Gemma 4 26B-A4B de Google que usa, en promedio, un 38.9 por ciento menos de tokens de razonamiento con casi la misma precisión: 75.0 frente a 75.2 del modelo base en doce benchmarks. BottleCap AI lo publicó el 23 de octubre de 2026 bajo licencia Apache 2.0, con los pesos completos y versiones GGUF en Hugging Face.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://huggingface.co/bottlecapai/ThinkingCap-gemma-4-26B-A4B-it" rel="noopener noreferrer"&gt;https://huggingface.co/bottlecapai/ThinkingCap-gemma-4-26B-A4B-it&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Es un reemplazo directo (drop-in replacement): solo cambian los pesos. La plantilla de chat, el tokenizador y la configuración de muestreo recomendada son los del modelo base. Todas las cifras son mediciones de la propia BottleCap: están bien hechas, pero nadie las ha reproducido de forma independiente todavía. Y, como muestra la ficha GGUF del mismo equipo, el ahorro no llega intacto a los archivos que la mayoría ejecuta en local.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué son los tokens de razonamiento y por qué conviene reducirlos?
&lt;/h2&gt;

&lt;p&gt;Los tokens de razonamiento (reasoning tokens o thinking tokens, en inglés) son el texto que un modelo se escribe a sí mismo antes de responder: el borrador donde resuelve el problema paso a paso. Casi nunca lo lees, pero lo pagas entero en tiempo, en energía y en ventana de contexto.&lt;/p&gt;

&lt;p&gt;En problemas de matemáticas difíciles, Gemma 4 26B escribe entre 15,000 y 22,000 tokens de razonamiento por pregunta. Recortar un tercio de eso cambia cuánto esperas cada respuesta y cuántas peticiones puede atender una sola máquina. La propuesta de BottleCap es exactamente esa: las mismas respuestas, con menos pensamiento por el camino.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué es Gemma 4 26B-A4B?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;gemma-4-26B-A4B-it&lt;/code&gt; es el modelo intermedio de la familia Gemma 4 de Google DeepMind, con arquitectura de mezcla de expertos (mixture of experts, MoE). Almacena unos 26,000 millones de parámetros, pero activa solo alrededor de 4,000 millones por token: en cada paso se ejecutan 8 de sus 128 expertos. Eso le da el conocimiento de un modelo grande con un costo de cómputo cercano al de uno pequeño. También acepta imágenes como entrada.&lt;/p&gt;

&lt;p&gt;Su modo de razonamiento está &lt;strong&gt;apagado por defecto&lt;/strong&gt;: cada petición tiene que activarlo con &lt;code&gt;enable_thinking&lt;/code&gt;. Todas las cifras de ThinkingCap se midieron con el razonamiento activado, así que si ejecutas el modelo sin él, no hay nada que ahorrar.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cuántos tokens de razonamiento ahorra ThinkingCap?
&lt;/h2&gt;

&lt;p&gt;En promedio, un 38.9 por ciento en doce benchmarks. Pero el ahorro varía mucho según la tarea:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Benchmark&lt;/th&gt;
&lt;th&gt;Precisión base&lt;/th&gt;
&lt;th&gt;Precisión ThinkingCap&lt;/th&gt;
&lt;th&gt;Tokens base&lt;/th&gt;
&lt;th&gt;Tokens ThinkingCap&lt;/th&gt;
&lt;th&gt;Reducción&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;LongBench v2&lt;/td&gt;
&lt;td&gt;59.43&lt;/td&gt;
&lt;td&gt;60.88&lt;/td&gt;
&lt;td&gt;9,486&lt;/td&gt;
&lt;td&gt;2,934&lt;/td&gt;
&lt;td&gt;69.1%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AA-LCR&lt;/td&gt;
&lt;td&gt;64.62&lt;/td&gt;
&lt;td&gt;60.62&lt;/td&gt;
&lt;td&gt;6,519&lt;/td&gt;
&lt;td&gt;2,655&lt;/td&gt;
&lt;td&gt;59.3%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MMLU-Pro&lt;/td&gt;
&lt;td&gt;84.55&lt;/td&gt;
&lt;td&gt;84.64&lt;/td&gt;
&lt;td&gt;3,907&lt;/td&gt;
&lt;td&gt;1,989&lt;/td&gt;
&lt;td&gt;49.1%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPQA-Diamond&lt;/td&gt;
&lt;td&gt;79.92&lt;/td&gt;
&lt;td&gt;78.96&lt;/td&gt;
&lt;td&gt;7,699&lt;/td&gt;
&lt;td&gt;4,284&lt;/td&gt;
&lt;td&gt;44.4%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AIME 2026&lt;/td&gt;
&lt;td&gt;86.20&lt;/td&gt;
&lt;td&gt;86.72&lt;/td&gt;
&lt;td&gt;14,766&lt;/td&gt;
&lt;td&gt;8,963&lt;/td&gt;
&lt;td&gt;39.3%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HMMT (feb. 2026)&lt;/td&gt;
&lt;td&gt;72.92&lt;/td&gt;
&lt;td&gt;74.20&lt;/td&gt;
&lt;td&gt;22,005&lt;/td&gt;
&lt;td&gt;14,717&lt;/td&gt;
&lt;td&gt;33.1%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LiveCodeBench v6&lt;/td&gt;
&lt;td&gt;76.98&lt;/td&gt;
&lt;td&gt;76.96&lt;/td&gt;
&lt;td&gt;11,560&lt;/td&gt;
&lt;td&gt;8,375&lt;/td&gt;
&lt;td&gt;27.6%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;τ²-bench&lt;/td&gt;
&lt;td&gt;64.25&lt;/td&gt;
&lt;td&gt;63.73&lt;/td&gt;
&lt;td&gt;4,374&lt;/td&gt;
&lt;td&gt;3,466&lt;/td&gt;
&lt;td&gt;20.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IFBench&lt;/td&gt;
&lt;td&gt;76.83&lt;/td&gt;
&lt;td&gt;78.67&lt;/td&gt;
&lt;td&gt;6,470&lt;/td&gt;
&lt;td&gt;5,585&lt;/td&gt;
&lt;td&gt;13.7%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Promedio (12 benchmarks)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;75.2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;75.0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;8,773&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5,398&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;38.9%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Selección de filas; la tabla completa de doce benchmarks está en la ficha del modelo.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Las tareas de contexto largo y de conocimiento son las que más recortan; el código recorta menos. El seguimiento de instrucciones y el uso de herramientas en modo agente apenas cambian. La explicación de BottleCap es que esas tareas no consisten en pensar mucho, sino en cumplir una lista de restricciones o una política fija.&lt;/p&gt;

&lt;p&gt;La segunda mejora es menos evidente y quizá más útil en la práctica: &lt;strong&gt;menos bucles&lt;/strong&gt;. El modelo base se queda repitiendo el mismo razonamiento en el 3.64 por ciento de sus respuestas; ThinkingCap, en el 0.76 por ciento. En el conjunto de matemáticas más difícil (HMMT de febrero de 2026), los bucles bajan del 17.0 al 4.5 por ciento. Una respuesta en bucle es una respuesta perdida: corre hasta el límite de tokens y no devuelve nada.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿ThinkingCap pierde precisión frente a Gemma 4?
&lt;/h2&gt;

&lt;p&gt;En promedio, casi nada: 0.15 puntos. Cinco de los doce benchmarks incluso salen ligeramente por delante. Pero "sin pérdida de calidad" es un promedio, no una garantía. Cuatro benchmarks se mueven más de lo que explica el ruido entre ejecuciones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AA-LCR (razonamiento sobre contexto largo): −4.00 puntos.&lt;/strong&gt; BottleCap lo reconoce como el único costo real del conjunto. Si tu trabajo consiste en razonar sobre documentos muy largos, pruébalo antes de cambiar.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GPQA-Diamond: −0.96 puntos&lt;/strong&gt;, y &lt;strong&gt;MMMLU (multilingüe): −0.66 puntos.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IFBench (seguimiento de instrucciones): +1.83 puntos&lt;/strong&gt;, esta vez a favor de ThinkingCap.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;En cuanto al método, la evaluación es más sólida que la mayoría de las cifras autodeclaradas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ambos modelos medidos por ellos mismos.&lt;/strong&gt; BottleCap ejecutó el modelo base en lugar de citar las cifras de Google, con el mismo arnés de evaluación, el mismo hardware y la misma configuración de muestreo para los dos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Muchas semillas por benchmark.&lt;/strong&gt; Cada uno se ejecutó entre 4 y 64 veces, con intervalos de confianza del 95 por ciento.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;El entorno de servicio:&lt;/strong&gt; vLLM 0.26.0 sobre una NVIDIA GB300 por servidor, con los pesos completos en bf16.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ese último detalle importa si piensas ejecutarlo en tu propia máquina.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Se mantiene el ahorro con la cuantización GGUF en llama.cpp?
&lt;/h2&gt;

&lt;p&gt;Solo en parte, según los propios números de BottleCap. El equipo probó su archivo GGUF recomendado (&lt;code&gt;MXFP4_MOE&lt;/code&gt;, 16.6 GB) en llama.cpp frente al ThinkingCap en bf16, en nueve de los doce benchmarks. Con la cuantización, la longitud del razonamiento se desplaza en ambas direcciones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AIME 2026:&lt;/strong&gt; 15.5 por ciento &lt;em&gt;más&lt;/em&gt; tokens de razonamiento que la versión bf16&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IFBench:&lt;/strong&gt; 6.9 por ciento más&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GPQA-Diamond:&lt;/strong&gt; prácticamente igual&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MMLU-Pro:&lt;/strong&gt; 8.0 por ciento menos&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HMMT (feb. 2026):&lt;/strong&gt; 25.0 por ciento menos&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;La ficha añade que incluso el GGUF &lt;em&gt;sin cuantizar&lt;/em&gt; (BF16) en llama.cpp piensa más que el checkpoint original servido con vLLM: un 6.1 por ciento más en AIME y un 14.7 por ciento más en GPQA. Es decir, el propio runtime cambia la longitud del razonamiento, al margen de la cuantización.&lt;/p&gt;

&lt;p&gt;Lo que no se ha publicado es la comparación que de verdad le importa a quien trabaja en local: Gemma 4 base en GGUF frente a ThinkingCap en GGUF, en la misma máquina. Al momento de publicar esta nota (24 de octubre de 2026), ni BottleCap ni nadie más había publicado esa medición. &lt;strong&gt;Espera un ahorro real en local, pero no cuentes con el 38.9 por ciento completo.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo usar ThinkingCap con llama.cpp u Ollama?
&lt;/h2&gt;

&lt;p&gt;BottleCap documenta llama.cpp. Estos comandos vienen de su ficha GGUF:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# serve an OpenAI-compatible endpoint, thinking on, with the base model's recommended sampling
llama-server -hf bottlecapai/ThinkingCap-gemma-4-26B-A4B-it-GGUF:MXFP4_MOE \
  --jinja --chat-template-kwargs '{"enable_thinking":true}' --reasoning-format deepseek \
  --temp 1.0 --top-p 0.95 --top-k 64 -ub 2048 -b 2048
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Con &lt;code&gt;--reasoning-format deepseek&lt;/code&gt;, el servidor devuelve el razonamiento en &lt;code&gt;reasoning_content&lt;/code&gt; y la respuesta en &lt;code&gt;content&lt;/code&gt;, así que puedes contar los tokens de razonamiento tú mismo. BottleCap hace dos advertencias:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mantén la temperatura en 1.0.&lt;/strong&gt; La decodificación greedy puede hacer que el modelo entre en bucle.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mantén &lt;/strong&gt;&lt;strong&gt;&lt;code&gt;-ub 2048 -b 2048&lt;/code&gt;&lt;/strong&gt;&lt;strong&gt; si envías imágenes.&lt;/strong&gt; Con el tamaño de lote por defecto de llama.cpp, una imagen grande puede tumbar el servidor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ollama, LM Studio y Jan cargan los mismos archivos GGUF. La página de Hugging Face genera este comando para Ollama:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ollama run hf.co/bottlecapai/ThinkingCap-gemma-4-26B-A4B-it-GGUF:Q4_K_M
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ten en cuenta dos cosas. Ese comando descarga &lt;code&gt;Q4_K_M&lt;/code&gt;, que según BottleCap rindió peor en matemáticas que &lt;code&gt;MXFP4_MOE&lt;/code&gt;. Y la ficha de BottleCap no explica cómo activar el razonamiento en Ollama, LM Studio o Jan; sin razonamiento activado, ThinkingCap no tiene nada que ahorrar. Si quieres medir la diferencia, usa llama.cpp.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué archivo GGUF descargar?
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Archivo&lt;/th&gt;
&lt;th&gt;Tamaño&lt;/th&gt;
&lt;th&gt;Notas&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MXFP4_MOE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;16.6 GB&lt;/td&gt;
&lt;td&gt;Recomendado por BottleCap; es el que evaluaron&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Q4_K_M&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;17.0 GB&lt;/td&gt;
&lt;td&gt;Rindió peor en sus benchmarks de matemáticas que MXFP4_MOE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;IQ4_XS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;13.6 GB&lt;/td&gt;
&lt;td&gt;El más pequeño; sin evaluar por BottleCap&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;Q6_K&lt;/code&gt; / &lt;code&gt;Q8_0&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;23.3 / 26.9 GB&lt;/td&gt;
&lt;td&gt;Más precisión, más memoria&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mmproj-…-f16&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1.19 GB&lt;/td&gt;
&lt;td&gt;Proyector de visión, necesario para enviar imágenes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;En equipos con poca memoria, IQ4_XS es el que cabe, pero también es el único sin cifras publicadas. Si ya ejecutas Gemma 4 en local, nuestra guía sobre &lt;a href="https://www.yodev.dev/t/gemma-4-en-tu-mac-con-ollama-que-variante-elegir-segun-tu-ram/2175" rel="noopener noreferrer"&gt;qué variante de Gemma 4 elegir según la RAM de tu Mac&lt;/a&gt; cubre la parte de memoria.&lt;/p&gt;

&lt;p&gt;Para servidores con GPU, la ficha principal documenta vLLM, con parsers de razonamiento y de llamadas a herramientas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vllm serve bottlecapai/ThinkingCap-gemma-4-26B-A4B-it --max-model-len 262144 \
  --reasoning-parser gemma4 --enable-auto-tool-choice --tool-call-parser gemma4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Los pesos completos en bf16 ocupan unos 52 GB.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Quién está detrás de ThinkingCap?
&lt;/h2&gt;

&lt;p&gt;BottleCap AI. Es el quinto modelo de su serie ThinkingCap, después de dos variantes de Qwen3 27B, Nemotron 3.5 Lightning de NVIDIA y Qwen3.8-Flash-Next, y el primero construido sobre un modelo de Google. Entre los autores que figuran en la cita del modelo está Tomas Mikolov, conocido por word2vec.&lt;/p&gt;

&lt;p&gt;BottleCap también vende una versión comercial "PRO" que, según la empresa, recorta el razonamiento un 62 por ciento en promedio. No hay nada público sobre ella, así que tómalo como un argumento de venta. Al momento de publicar esta nota, la página del modelo gratuito en Hugging Face todavía no mostraba cifras de descargas: es muy reciente.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cuándo conviene usar ThinkingCap?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Conviene:&lt;/strong&gt; trabajo con contexto largo, matemáticas y preguntas de conocimiento donde Gemma 4 piensa mucho, y cualquier entorno donde los bucles te hacen perder tiempo o GPU.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Da igual:&lt;/strong&gt; seguimiento de instrucciones y uso de herramientas en modo agente, donde el ahorro es pequeño (entre 14 y 21 por ciento).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pruébalo antes:&lt;/strong&gt; razonamiento sobre documentos largos (la caída en AA-LCR) y cualquier configuración GGUF en local, donde la cifra principal no se ha medido.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Como es un reemplazo directo con la misma licencia, la forma más barata de salir de dudas es pasar tus propios prompts por los dos modelos con el razonamiento activado y comparar la longitud de &lt;code&gt;reasoning_content&lt;/code&gt;.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;¿Y tú?&lt;/strong&gt; ¿Activas el modo de razonamiento cuando ejecutas modelos en local, o lo dejas apagado para ganar velocidad?&lt;/p&gt;

&lt;p&gt;Comenta abajo o, si este artículo te llegó por correo, responde directamente al email: tu respuesta se publica aquí.&lt;/p&gt;

&lt;p&gt;Relacionado: &lt;a href="https://www.yodev.dev/t/lm-studio-ollama-o-llama-cpp-que-corre-de-verdad-en-tu-maquina/5264" rel="noopener noreferrer"&gt;LM Studio, Ollama o llama.cpp: qué corre de verdad en tu máquina&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>gemma</category>
      <category>llm</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>agent-usage-guard: cómo evitar que Claude Code agote tu límite de uso con subagentes</title>
      <dc:creator>Grego</dc:creator>
      <pubDate>Sat, 24 Oct 2026 18:40:12 +0000</pubDate>
      <link>https://dev.to/yodev_grego/agent-usage-guard-como-evitar-que-claude-code-agote-tu-limite-de-uso-con-subagentes-3ahf</link>
      <guid>https://dev.to/yodev_grego/agent-usage-guard-como-evitar-que-claude-code-agote-tu-limite-de-uso-con-subagentes-3ahf</guid>
      <description>&lt;p&gt;agent-usage-guard es un mod de Claude Code, con licencia MIT, que frena el fan-out de subagentes, los prompts con contexto pesado y los reintentos en bucle antes de que agoten tu límite de uso. Lee los porcentajes de la ventana de 5 horas y de la semanal que reporta Claude Code, y cuenta los agentes de todas las sesiones abiertas en tu máquina. Cuando se cruza un umbral, primero te pregunta; si nadie puede responder, se niega. La versión 1.1.0, publicada el 23 de octubre de 2026, agrega un modo de cierre: cuando una ventana del plan llega al 95 por ciento, cada sesión recibe la instrucción de terminar el paso en curso e informar qué queda pendiente.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/rbartoli/agent-usage-guard" rel="noopener noreferrer"&gt;https://github.com/rbartoli/agent-usage-guard&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Actualización, 24 de octubre de 2026:&lt;/strong&gt; al momento de publicar esta nota, el CHANGELOG del repositorio lista dos correcciones de seguridad todavía sin publicar (&lt;em&gt;Unreleased&lt;/em&gt;). Las explicamos en la sección de seguridad.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  ¿Por qué Claude Code agota el límite de uso tan rápido?
&lt;/h2&gt;

&lt;p&gt;Porque los costos se multiplican, no se suman. El autor identifica cuatro factores que se potencian entre sí: un contexto grande, bucles rápidos de herramientas, agentes en paralelo y reintentos a ciegas.&lt;/p&gt;

&lt;p&gt;En el README cuenta la tarde que lo llevó a construir el guard. Le dio a Claude Code un prompt de investigación con esfuerzo máximo, y Claude Code lanzó 394 llamadas a subagentes, 341 de ellas al mismo tiempo. En diez minutos pasó 84 millones de tokens de contexto por la API y la sesión terminó con el mensaje &lt;code&gt;Claude usage limit reached&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Son cifras del propio autor, tomadas de sus registros y no verificadas de forma independiente. Según el mismo relato, en sesenta días de registros tuvo 12 bloqueos. También enlaza reportes públicos parecidos: 339 subagentes a partir de un solo prompt, y la mitad de un plan Max semanal consumida por subagentes que lanzaban otros subagentes.&lt;/p&gt;

&lt;p&gt;Cada regla del guard elimina uno de esos cuatro factores.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué es un mod de Claude Code?
&lt;/h2&gt;

&lt;p&gt;Un mod es un tipo de plugin de Claude Code formado por manejadores de eventos en JavaScript o TypeScript que se ejecutan &lt;em&gt;dentro&lt;/em&gt; de Claude Code. Esa es la diferencia con los hooks clásicos que se configuran en &lt;code&gt;settings.json&lt;/code&gt;, que ejecutan un script externo. Como un mod vive en el mismo proceso, puede intervenir en un evento antes de que ocurra: retener una llamada a una herramienta mientras te hace una pregunta, reescribir un prompt o rechazar una acción.&lt;/p&gt;

&lt;p&gt;Eso es justo lo que agent-usage-guard necesita. Su CHANGELOG explica que la versión anterior (0.2.5) estaba construida sobre hooks de configuración y solo podía aproximar lo que los mods exponen directamente: el contexto en vivo, los porcentajes de la ventana del plan y un evento que se puede rechazar antes de que arranque cada agente.&lt;/p&gt;

&lt;p&gt;Los mods están activos por defecto desde Claude Code v2.1.287 en la terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo limita los subagentes de Claude Code y el contexto?
&lt;/h2&gt;

&lt;p&gt;El guard actúa en tres momentos: antes de que arranque un agente, antes de que se envíe un prompt y antes de que se ejecute una llamada a una herramienta. Estos son sus valores por defecto según el README:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Área&lt;/th&gt;
&lt;th&gt;Regla&lt;/th&gt;
&lt;th&gt;Por defecto&lt;/th&gt;
&lt;th&gt;Qué hace&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ventana del plan&lt;/td&gt;
&lt;td&gt;Ventana así de llena&lt;/td&gt;
&lt;td&gt;80%&lt;/td&gt;
&lt;td&gt;pregunta antes de nuevos agentes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ventana del plan&lt;/td&gt;
&lt;td&gt;Ventana así de llena&lt;/td&gt;
&lt;td&gt;95%&lt;/td&gt;
&lt;td&gt;rechaza nuevos agentes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ventana del plan&lt;/td&gt;
&lt;td&gt;La ventana de 5 horas sube así de rápido&lt;/td&gt;
&lt;td&gt;20 puntos / 10 min&lt;/td&gt;
&lt;td&gt;pregunta&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agentes&lt;/td&gt;
&lt;td&gt;Agentes corriendo a la vez, en todas las sesiones de la máquina&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;pregunta&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agentes&lt;/td&gt;
&lt;td&gt;Agentes iniciados o reanudados cada 10 minutos&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;pregunta&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agentes&lt;/td&gt;
&lt;td&gt;Tokens procesados por subagentes cada 10 minutos&lt;/td&gt;
&lt;td&gt;10M&lt;/td&gt;
&lt;td&gt;pregunta&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agentes&lt;/td&gt;
&lt;td&gt;Subagentes que lanzan sus propios agentes&lt;/td&gt;
&lt;td&gt;profundidad 1&lt;/td&gt;
&lt;td&gt;rechaza&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Contexto&lt;/td&gt;
&lt;td&gt;Aviso único para que Claude acote el turno&lt;/td&gt;
&lt;td&gt;300k tokens&lt;/td&gt;
&lt;td&gt;agrega una nota&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Contexto&lt;/td&gt;
&lt;td&gt;Prompt que volvería a leer este contexto&lt;/td&gt;
&lt;td&gt;500k tokens&lt;/td&gt;
&lt;td&gt;pregunta: compactar y enviar, enviar igual o cancelar&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Contexto&lt;/td&gt;
&lt;td&gt;Llamadas a herramientas cada 10 min con este contexto&lt;/td&gt;
&lt;td&gt;20 llamadas a 400k&lt;/td&gt;
&lt;td&gt;pregunta&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Contexto&lt;/td&gt;
&lt;td&gt;Sesión pesada inactiva el tiempo suficiente para que expire su caché&lt;/td&gt;
&lt;td&gt;150k tokens, 1 h inactiva&lt;/td&gt;
&lt;td&gt;pregunta antes de reescribir la caché&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bucles&lt;/td&gt;
&lt;td&gt;La misma llamada falla una y otra vez&lt;/td&gt;
&lt;td&gt;3 fallos idénticos&lt;/td&gt;
&lt;td&gt;rechaza el reintento idéntico&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bucles&lt;/td&gt;
&lt;td&gt;Agentes rechazados en 10 minutos&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;pausa los lanzamientos 10 min&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;La regla de la sesión inactiva tiene que ver con la caché de prompts, que explicamos en detalle en &lt;a href="https://www.yodev.dev/t/tu-cache-de-5-minutos-no-dura-5-minutos-que-arregla-realmente-promptcachettl/4873" rel="noopener noreferrer"&gt;Tu caché de 5 minutos no dura 5 minutos&lt;/a&gt;. Si todavía no usas subagentes, empieza por &lt;a href="https://www.yodev.dev/t/sub-agents-en-claude-code-la-funcionalidad-que-cambia-tu-flujo-de-desarrollo/899" rel="noopener noreferrer"&gt;Sub-agents en Claude Code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Dos decisiones de diseño importan en el uso diario:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Una respuesta vale por un rato.&lt;/strong&gt; Si permites algo, el guard no vuelve a preguntar hasta que la condición desaparece. Una ventana del plan queda permitida hasta que se reinicia, y los conteos de agentes quedan permitidos durante 10 minutos. El autor lo incorporó porque su versión anterior preguntó 136 veces en sesiones de contexto alto y la respuesta fue "sí" en 132.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sin una persona, rechaza.&lt;/strong&gt; En &lt;code&gt;claude -p&lt;/code&gt;, el Agent SDK o el modo &lt;code&gt;dontAsk&lt;/code&gt;, rechaza y explica el motivo. Claude lee el rechazo como el resultado de la herramienta, así que puede esperar, agrupar el trabajo o detenerse. Los rechazos repetidos suben de tono, y el tercero le pide a Claude que termine el turno.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ¿Qué hace el nuevo modo de cierre al 95 por ciento?
&lt;/h2&gt;

&lt;p&gt;Según el CHANGELOG de la 1.1.0, cuando cualquier ventana del plan en la máquina llega al 95 por ciento, el siguiente prompt de &lt;em&gt;cada&lt;/em&gt; sesión lleva una nota para Claude: termina el paso en curso, no empieces nada grande y cierra el turno con lo hecho y lo pendiente.&lt;/p&gt;

&lt;p&gt;El autor explica por qué lo agregó. Los bloqueos que seguía viendo después de la 1.0 venían de muchas sesiones principales corriendo en paralelo, y eso no lo frenaba ninguna regla. Ahora, cuando llega el bloqueo, las encuentra en un punto limpio y no a mitad de un cambio. Una sesión inactiva también se entera de que otra sesión llenó la ventana. Cada sesión recibe el aviso una sola vez, y solo vuelve a recibirlo cuando la ventana baja del umbral, por ejemplo después de su reinicio.&lt;/p&gt;

&lt;p&gt;La versión 1.1.1, publicada el mismo día, corrige un doble conteo: desde Claude Code 2.1.299, reanudar un subagente con &lt;code&gt;SendMessage&lt;/code&gt; contaba como dos inicios. También hace que &lt;code&gt;/agent-guard status&lt;/code&gt; muestre qué versión está corriendo.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo se instala agent-usage-guard en Claude Code?
&lt;/h2&gt;

&lt;p&gt;Dentro de Claude Code v2.1.287 o posterior, ejecuta:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/plugin marketplace add rbartoli/agent-usage-guard
/plugin install agent-usage-guard@agent-usage-guard
/reload-plugins
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Después ejecuta &lt;code&gt;/agent-guard&lt;/code&gt; para ver lo que ve el guard.&lt;/p&gt;

&lt;p&gt;Estos son los comandos que vas a usar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/agent-guard [status]                          what the guard sees right now
/agent-guard allow [agents|context] [minutes]  lift its limits for this session (default: all, 10 min)
/agent-guard pause [minutes]                   the same as allow, for every limit
/agent-guard resume                            end an allow early
/agent-guard report [days]                     what it did on this machine (default: 7 days)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;/agent-guard&lt;/code&gt; se ejecuta sin iniciar un turno del modelo, así que Claude nunca ve una anulación y no puede tomarla como permiso.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo se ajustan los umbrales?
&lt;/h2&gt;

&lt;p&gt;Con variables de entorno, o dentro de &lt;code&gt;env&lt;/code&gt; en &lt;code&gt;~/.claude/settings.json&lt;/code&gt;. Algunas de las más útiles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;AGENT_GUARD_AGENT_MAX&lt;/code&gt;: agentes corriendo a la vez en la máquina (por defecto &lt;code&gt;4&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AGENT_GUARD_LIMIT_ASK_PERCENT&lt;/code&gt; y &lt;code&gt;AGENT_GUARD_LIMIT_DENY_PERCENT&lt;/code&gt;: umbrales para preguntar y para rechazar (&lt;code&gt;80&lt;/code&gt; y &lt;code&gt;95&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AGENT_GUARD_CONTEXT_HARD&lt;/code&gt;: contexto a partir del cual un prompt pregunta antes de enviarse (&lt;code&gt;500000&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AGENT_GUARD=0&lt;/code&gt;: apaga el guard sin desinstalarlo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;El README documenta 22 variables en total.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Funciona con una API key?
&lt;/h2&gt;

&lt;p&gt;Sí, con dos diferencias. Las sesiones con API key no reportan los porcentajes de la ventana del plan, así que solo se aplican los presupuestos de tokens y de conteo de agentes. Además, la caché de prompts dura cinco minutos en lugar de una hora, por lo que el README recomienda &lt;code&gt;AGENT_GUARD_DORMANT_SECONDS=300&lt;/code&gt;. Lo mismo vale si usas uso adicional (&lt;em&gt;extra usage&lt;/em&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué no puede ver?
&lt;/h2&gt;

&lt;p&gt;El README es explícito sobre sus puntos ciegos, verificados contra Claude Code v2.1.295:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No cuenta sesiones en otras máquinas, porque los registros compartidos viven en el almacén de mods de cada equipo.&lt;/li&gt;
&lt;li&gt;No ve a los compañeros de equipo (&lt;em&gt;teammates&lt;/em&gt;) que corren en su propio panel de terminal, porque corren en otros procesos.&lt;/li&gt;
&lt;li&gt;Los forks de &lt;code&gt;/subtask&lt;/code&gt;, y todo lo que arranca sin el evento &lt;code&gt;agent.spawn&lt;/code&gt;, se cuentan pero nunca se retienen.&lt;/li&gt;
&lt;li&gt;No corre en una sesión WSL de la app de escritorio.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Los límites nativos de Claude Code siguen vigentes: una sesión admite hasta 20 subagentes concurrentes y tres niveles de anidamiento, pero no hay límite al total de agentes que una sesión lanza. Los valores por defecto del guard son más estrictos y abarcan todas las sesiones.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Es seguro instalar un mod de Claude Code?
&lt;/h2&gt;

&lt;p&gt;Un mod corre con tus permisos y no está aislado en un sandbox. La documentación de Anthropic lo dice sin rodeos: un mod puede leer tus archivos, tus variables de entorno y tu sesión. Según las notas de privacidad del autor, el guard son unas 2.400 líneas de TypeScript sin dependencias, no hace peticiones de red ni inicia procesos, y guarda conteos y rangos aproximados, nunca el texto de los prompts ni las entradas de las herramientas. Puedes revisar qué APIs usa con &lt;code&gt;claude plugin validate .&lt;/code&gt; antes de instalarlo.&lt;/p&gt;

&lt;p&gt;Al momento de publicar esta nota, el CHANGELOG lista dos correcciones de una revisión de seguridad del 24 de octubre de 2026 que todavía no forman parte de una versión publicada:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hasta que salga esa corrección, cualquier otro plugin instalado podía ejecutar &lt;code&gt;/agent-guard allow&lt;/code&gt; y levantar todos los límites hasta por ocho horas.&lt;/li&gt;
&lt;li&gt;Una pregunta que terminaba sin respuesta podía dejar arrancar un agente; con la corrección cuenta como "no".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Antes de confiar en el guard en sesiones con otros mods instalados, comprueba que tu versión incluya ambas correcciones. Para revisar si cualquier mod es seguro, mira &lt;a href="https://www.yodev.dev/t/como-saber-si-un-plugin-de-claude-code-es-seguro-probamos-modvet-el-escaner-que-lo-revisa-antes-de-instalarlo/5728" rel="noopener noreferrer"&gt;cómo probamos ModVet, el escáner que revisa un plugin antes de instalarlo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿agent-usage-guard o Claude HUD?
&lt;/h2&gt;

&lt;p&gt;Resuelven problemas distintos y funcionan bien juntos. &lt;a href="https://www.yodev.dev/t/claude-hud-el-plugin-que-te-dice-exactamente-que-esta-haciendo-claude-code-y-cuanto-te-esta-costando/2344" rel="noopener noreferrer"&gt;Claude HUD&lt;/a&gt; te muestra qué está haciendo Claude Code y cuánto te cuesta. agent-usage-guard le pone un techo a ese costo y lo aplica antes de que se gaste.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;¿Y tú?&lt;/strong&gt; ¿Cuántos subagentes dejas correr en paralelo en Claude Code antes de empezar a preocuparte por el límite?&lt;/p&gt;

&lt;p&gt;Comenta abajo o, si este artículo te llegó por correo, responde directamente al email: tu respuesta se publica aquí.&lt;/p&gt;

&lt;p&gt;Relacionado: &lt;a href="https://www.yodev.dev/t/claude-hud-el-plugin-que-te-dice-exactamente-que-esta-haciendo-claude-code-y-cuanto-te-esta-costando/2344" rel="noopener noreferrer"&gt;Claude HUD: El Plugin que te Dice Exactamente Qué Está Haciendo Claude Code (y Cuánto te Está Costando)&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claude</category>
      <category>opensource</category>
      <category>tools</category>
    </item>
    <item>
      <title>SvelteKit 3: cómo migrar con sv migrate y el cambio de $lib que el comando no hace por ti</title>
      <dc:creator>Grego</dc:creator>
      <pubDate>Fri, 02 Oct 2026 16:10:23 +0000</pubDate>
      <link>https://dev.to/yodev_grego/sveltekit-3-como-migrar-con-sv-migrate-y-el-cambio-de-lib-que-el-comando-no-hace-por-ti-153h</link>
      <guid>https://dev.to/yodev_grego/sveltekit-3-como-migrar-con-sv-migrate-y-el-cambio-de-lib-que-el-comando-no-hace-por-ti-153h</guid>
      <description>&lt;p&gt;SvelteKit 3.0 salió el 1 de octubre de 2026 y casi toda la migración se automatiza con un comando, &lt;code&gt;npx sv migrate sveltekit-3&lt;/code&gt;. Lo que ese comando no hace es cambiar &lt;code&gt;$lib&lt;/code&gt; por &lt;code&gt;#lib&lt;/code&gt;: ese paso es manual. En esta guía verás qué cambia, qué resuelve la herramienta de migración y qué te toca hacer a ti.&lt;/p&gt;

&lt;p&gt;El equipo de Svelte lo presenta como el mismo framework con más pulido y más seguridad de tipos. Para la API del día a día es cierto, pero la estructura del proyecto cambia: la configuración se muda de archivo, el alias de importación más usado se reemplaza, los módulos de variables de entorno quedan obsoletos y los service workers se configuran de otra manera.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué es SvelteKit y en qué se diferencia de Svelte?
&lt;/h2&gt;

&lt;p&gt;SvelteKit es el framework oficial de aplicaciones para Svelte: se encarga del enrutamiento, la carga de datos, el renderizado en servidor y el despliegue mediante adapters. Es a Svelte lo que Next.js es a React. Svelte compila los componentes y SvelteKit los convierte en una aplicación desplegable, ya sea con renderizado en servidor, prerenderizada como sitio estático o como single-page app. Tiene licencia MIT y se desarrolla en &lt;a href="https://github.com/sveltejs/kit" rel="noopener noreferrer"&gt;github.com/sveltejs/kit&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué cambia en SvelteKit 3?
&lt;/h2&gt;

&lt;p&gt;El anuncio oficial destaca cinco cambios, y cuatro de ellos afectan a archivos que ya tienes en tu proyecto.&lt;/p&gt;

&lt;h3&gt;
  
  
  La configuración pasa de &lt;code&gt;svelte.config.js&lt;/code&gt; a &lt;code&gt;vite.config&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;svelte.config.js&lt;/code&gt; ya no está soportado. La configuración ahora se pasa directamente al plugin &lt;code&gt;sveltekit&lt;/code&gt; de Vite, y las opciones que antes vivían en &lt;code&gt;config.kit.*&lt;/code&gt; pasan a ser opciones de primer nivel del plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;adapter&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@sveltejs/adapter-auto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;sveltekit&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@sveltejs/kit/vite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nf"&gt;sveltekit&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Las opciones que no son de SvelteKit se reenvían a &lt;code&gt;vite-plugin-svelte&lt;/code&gt;. Con la mudanza desaparecen varias opciones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;files.lib&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vitePlugin&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;preloadStrategy&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;prerender.origin&lt;/code&gt;, reemplazada por la nueva &lt;code&gt;paths.origin&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;csrf.checkOrigin&lt;/code&gt;, reemplazada por &lt;code&gt;csrf.trustedOrigins&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;$lib&lt;/code&gt; pasa a ser &lt;code&gt;#lib&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;SvelteKit ya no genera el alias &lt;code&gt;$lib&lt;/code&gt;. En su lugar declaras tú mismo &lt;code&gt;#lib&lt;/code&gt; usando los &lt;strong&gt;subpath imports&lt;/strong&gt; de Node.js, que Vite y TypeScript resuelven de forma nativa. Es el cambio que &lt;code&gt;sv migrate&lt;/code&gt; no hace por ti; los pasos están más abajo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Las variables de entorno pasan a &lt;code&gt;$app/env&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Los módulos &lt;code&gt;$env/...&lt;/code&gt; quedan obsoletos en favor de &lt;code&gt;$app/env/private&lt;/code&gt; y &lt;code&gt;$app/env/public&lt;/code&gt;. &lt;code&gt;$app/environment&lt;/code&gt; se renombra a &lt;code&gt;$app/env&lt;/code&gt;, y ahora también puedes importarlo dentro de un service worker.&lt;/p&gt;

&lt;h3&gt;
  
  
  Los service workers necesitan menos código repetitivo
&lt;/h3&gt;

&lt;p&gt;El módulo &lt;code&gt;$service-worker&lt;/code&gt; se eliminó y sus exportaciones se reparten entre módulos estándar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;version&lt;/code&gt; viene de &lt;code&gt;$app/env&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;assets&lt;/code&gt;, &lt;code&gt;immutable&lt;/code&gt; y &lt;code&gt;prerendered&lt;/code&gt; vienen del nuevo &lt;code&gt;$app/manifest&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Las utilidades de rutas vienen de &lt;code&gt;$app/paths&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Un nuevo módulo, &lt;code&gt;$app/service-worker&lt;/code&gt;, te da un contexto de service worker con tipos. Además, SvelteKit ahora registra el service worker como módulo ES y no como script clásico.&lt;/p&gt;

&lt;p&gt;El quinto cambio destacado es el manejo de errores. En SvelteKit 3, &lt;code&gt;handleError&lt;/code&gt; recibe &lt;em&gt;todos&lt;/em&gt; los errores, incluidos los esperados que creas con &lt;code&gt;error(...)&lt;/code&gt;, y los errores de renderizado se envían al &lt;code&gt;+error.svelte&lt;/code&gt; más cercano.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué necesitas antes de migrar a SvelteKit 3?
&lt;/h2&gt;

&lt;p&gt;Según la guía oficial de migración, SvelteKit 3 exige estas versiones mínimas:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dependencia&lt;/th&gt;
&lt;th&gt;Mínimo&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Node&lt;/td&gt;
&lt;td&gt;22.17&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TypeScript&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Svelte&lt;/td&gt;
&lt;td&gt;5.57.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vite&lt;/td&gt;
&lt;td&gt;8.0.12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@sveltejs/vite-plugin-svelte&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;El equipo de Svelte recomienda actualizar primero a la última versión 2.x, porque esa versión muestra avisos de obsolescencia dirigidos exactamente al código que tendrás que cambiar. Haz commit de tu proyecto antes de empezar: si el árbol de trabajo tiene cambios sin confirmar, &lt;code&gt;sv migrate&lt;/code&gt; te lo avisará.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo migrar a SvelteKit 3 con &lt;code&gt;sv migrate&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;El anuncio de lanzamiento propone un comando que lo hace todo de una vez:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx sv migrate sveltekit-3 --tasks all --confirm

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La documentación del CLI recomienda un enfoque más prudente: ejecuta una tarea por vez y haz commit después de cada una, para que cada diff sea fácil de revisar. Para ver las tareas disponibles sin ejecutar nada, usa:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx sv migrate sveltekit-3 --tasks

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La migración &lt;code&gt;sveltekit-3&lt;/code&gt; se compone de nueve tareas. Las dos primeras son requisitos previos y se ejecutan siempre:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tarea&lt;/th&gt;
&lt;th&gt;Qué hace&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;package-json&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Actualiza las versiones de los paquetes para SvelteKit 3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tsconfig&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Hace que tu &lt;code&gt;tsconfig.json&lt;/code&gt; extienda &lt;code&gt;$app/tsconfig&lt;/code&gt; en lugar de &lt;code&gt;.svelte-kit/tsconfig.json&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;svelte-config&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mueve las opciones soportadas de &lt;code&gt;svelte.config.*&lt;/code&gt; a &lt;code&gt;vite.config.*&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;environment&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reemplaza los módulos de entorno antiguos por &lt;code&gt;$app/env&lt;/code&gt; y crea las declaraciones &lt;code&gt;src/env.js&lt;/code&gt; o &lt;code&gt;src/env.ts&lt;/code&gt; cuando hacen falta&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;paths&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Migra las APIs obsoletas de &lt;code&gt;$app/paths&lt;/code&gt; (&lt;code&gt;base&lt;/code&gt;, &lt;code&gt;assets&lt;/code&gt; y &lt;code&gt;resolveRoute&lt;/code&gt; se reemplazan por &lt;code&gt;asset()&lt;/code&gt; y &lt;code&gt;resolve()&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;external-redirects&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Adapta las redirecciones externas al nuevo comportamiento&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;shallow-routing&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reemplaza &lt;code&gt;pushState&lt;/code&gt; y &lt;code&gt;replaceState&lt;/code&gt; por &lt;code&gt;goto(..., { shallow: true })&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;params&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reúne los param matchers en un único &lt;code&gt;src/params.js&lt;/code&gt; o &lt;code&gt;src/params.ts&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;app-state&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Migra &lt;code&gt;$app/stores&lt;/code&gt; a &lt;code&gt;$app/state&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Para ejecutar una sola tarea:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx sv migrate sveltekit-3 --tasks svelte-config

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La documentación advierte que el proyecto no tiene por qué funcionar si solo se ejecutaron algunas tareas: la mayoría de las aplicaciones necesitan todas las que les correspondan. La herramienta solo reescribe los patrones que puede identificar con seguridad. Donde no puede, deja un comentario &lt;code&gt;@migration-task&lt;/code&gt;, así que busca ese marcador exacto en el proyecto antes de dar la migración por terminada.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo arreglar &lt;code&gt;$lib&lt;/code&gt; después de migrar a SvelteKit 3?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;$lib&lt;/code&gt; no aparece en la lista de tareas. Cuando &lt;code&gt;sv migrate&lt;/code&gt; termina, cada importación con &lt;code&gt;$lib&lt;/code&gt; en tu código sigue apuntando a un alias que SvelteKit 3 ya no genera. Para arreglarlo hacen falta tres pasos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Declara &lt;/strong&gt;&lt;strong&gt;&lt;code&gt;#lib&lt;/code&gt;&lt;/strong&gt;&lt;strong&gt; en &lt;/strong&gt;&lt;strong&gt;&lt;code&gt;package.json&lt;/code&gt;&lt;/strong&gt;&lt;strong&gt;:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"imports"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"#lib"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./src/lib/index.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"#lib/*"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./src/lib/*"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Reemplaza &lt;/strong&gt;&lt;strong&gt;&lt;code&gt;$lib&lt;/code&gt;&lt;/strong&gt;&lt;strong&gt; por &lt;/strong&gt;&lt;strong&gt;&lt;code&gt;#lib&lt;/code&gt;&lt;/strong&gt;&lt;strong&gt; en todo el código.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Añade la extensión de archivo a esas importaciones.&lt;/strong&gt; Los subpath imports la exigen, así que el cambio no es un simple buscar y reemplazar del prefijo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// antes&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$lib/foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// después&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#lib/foo.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La opción &lt;code&gt;files.lib&lt;/code&gt; también desapareció: si habías personalizado tu directorio lib, apunta las entradas de &lt;code&gt;imports&lt;/code&gt; a ese directorio.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué más puede romperse en producción?
&lt;/h2&gt;

&lt;p&gt;Estos cambios de la guía de migración modifican el comportamiento en tiempo de ejecución, y algunos no producen ningún error de build:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;$app/stores&lt;/code&gt;&lt;/strong&gt;&lt;strong&gt; se eliminó&lt;/strong&gt;, no solo quedó obsoleto. La tarea &lt;code&gt;app-state&lt;/code&gt; migra los archivos &lt;code&gt;.svelte&lt;/code&gt;, así que revisa si quedan usos en otros archivos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;adapter-node&lt;/code&gt;&lt;/strong&gt;&lt;strong&gt; elimina la variable de entorno &lt;/strong&gt;&lt;strong&gt;&lt;code&gt;ORIGIN&lt;/code&gt;&lt;/strong&gt;&lt;strong&gt;.&lt;/strong&gt; Define &lt;code&gt;paths.origin&lt;/code&gt; en tu configuración de Vite.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;adapter-vercel&lt;/code&gt;&lt;/strong&gt;&lt;strong&gt; ya no soporta el runtime &lt;/strong&gt;&lt;strong&gt;&lt;code&gt;edge&lt;/code&gt;&lt;/strong&gt;&lt;strong&gt;.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Las APIs de Cloudflare salen de &lt;/strong&gt;&lt;strong&gt;&lt;code&gt;platform&lt;/code&gt;&lt;/strong&gt;&lt;strong&gt;.&lt;/strong&gt; Importa &lt;code&gt;env&lt;/code&gt; desde &lt;code&gt;cloudflare:workers&lt;/code&gt;; &lt;code&gt;cf&lt;/code&gt; ahora es una propiedad de &lt;code&gt;request&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Las redirecciones externas necesitan permiso explícito.&lt;/strong&gt; Pasa &lt;code&gt;{ external: true }&lt;/code&gt; o una lista de orígenes permitidos a &lt;code&gt;redirect(...)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Los nombres de cookies deben ser ASCII.&lt;/strong&gt; SvelteKit ahora usa &lt;code&gt;cookie&lt;/code&gt; v2, que rechaza caracteres no ASCII como &lt;code&gt;á&lt;/code&gt; en los &lt;em&gt;nombres&lt;/em&gt; de las cookies. Conviene revisarlo en aplicaciones en español.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Las cookies usan &lt;/strong&gt;&lt;strong&gt;&lt;code&gt;path: '/'&lt;/code&gt;&lt;/strong&gt;&lt;strong&gt; por defecto&lt;/strong&gt;, en lugar de la ruta de la petición actual.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;error(...)&lt;/code&gt;&lt;/strong&gt;&lt;strong&gt; recibe un string como segundo argumento.&lt;/strong&gt; Las propiedades adicionales ahora van en un tercer argumento.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;goto()&lt;/code&gt;&lt;/strong&gt;&lt;strong&gt; rechaza las URLs que no corresponden a una ruta de tu aplicación.&lt;/strong&gt; Para navegar a un sitio externo, usa &lt;code&gt;window.location.href&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Las respuestas &lt;/strong&gt;&lt;strong&gt;&lt;code&gt;2xx&lt;/code&gt;&lt;/strong&gt;&lt;strong&gt; vacías se devuelven sin cuerpo&lt;/strong&gt;, como exige la especificación HTTP.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ¿Están listas las remote functions en SvelteKit 3?
&lt;/h2&gt;

&lt;p&gt;Todavía no. Al momento de publicar esta nota, las remote functions seguían siendo experimentales: requieren el flag &lt;code&gt;experimental.remoteFunctions&lt;/code&gt; junto con la opción asíncrona del compilador de Svelte. El equipo de Svelte las señala como su máxima prioridad. Si las estabas esperando, igual vale la pena actualizar ya, porque la migración no depende de ellas.&lt;/p&gt;




&lt;p&gt;Si estás siguiendo otras actualizaciones mayores de esta temporada, ya contamos &lt;a href="https://www.yodev.dev/t/htmx-4-0-ya-esta-disponible-que-cambia-si-vienes-de-htmx-2/4921" rel="noopener noreferrer"&gt;qué cambia en htmx 4.0 si vienes de htmx 2&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://svelte.dev/blog/sveltekit-3-is-here" rel="noopener noreferrer"&gt;https://svelte.dev/blog/sveltekit-3-is-here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>javascript</category>
      <category>migration</category>
      <category>svelte</category>
    </item>
  </channel>
</rss>
