Cómo Anthropic realiza migraciones de código a gran escala con Claude Code

@ClaudeDevs
INGLÉShace 2 días · 21 jul 2026
460K
3.7K
331
84
4.7K

TL;DR

Anthropic detalla un marco de trabajo de seis pasos para utilizar Claude Code en la automatización de migraciones de lenguaje a gran escala, demostrado mediante la migración de la base de código de un millón de líneas de Bun a Rust.

Migraciones de código, proyectos que trasladan una base de código de producción a un nuevo lenguaje, solían ser esfuerzos de varios años hasta hace poco.

En el último mes, desarrolladores individuales en Anthropic migraron 10 paquetes de código que consisten en decenas a cientos de miles de líneas de código usando Claude Fable 5, Claude Opus 4.8 y flujos de trabajo dinámicos.

Jarred Sumner (@jarredsumner), cofundador de Bun y miembro del personal técnico en Anthropic, usó Claude Code para migrar Bun de Zig a Rust. Se produjeron un millón de líneas de código en menos de dos semanas, con el 100 % del conjunto de pruebas existente de Bun pasando en CI antes de la fusión. Diecinueve regresiones surgieron después de la fusión y ya se han corregido todas. El puerto a Rust se envió dentro de Claude Code en junio.

Mike Krieger (@mikeyk), colíder de Anthropic Labs, migró una base de código de Python a 165,000 líneas de TypeScript durante un fin de semana. Esto incluyó cientos de agentes, ocho compuertas de fase, tres rondas de revisión adversarial y una verificación de paridad final que comparó la salida de cada comando con el original en Python.

Las nuevas capacidades de Claude Code cambian las matemáticas para estos proyectos largamente postergados. A continuación, presentamos el proceso de seis pasos que ahora utilizamos, extraído de lo que nos enseñaron estas migraciones.

La idea central es que no arreglas el código. Arreglas el proceso (bucle) que produjo el código.

Por qué y cuándo migrar lenguajes

Los equipos inician migraciones debido a cambios en el panorama entre su construcción inicial y el proyecto actual. Ya sea que una compensación conocida se haya vuelto limitante, haya surgido un mejor enfoque o el ecosistema original esté disminuyendo.

Por ejemplo, Jarred eligió originalmente Zig porque ofrecía rendimiento a nivel de C con una simplicidad radical, ideal para un fundador solitario "escribiendo Bun en 1 año en un pequeño apartamento de Oakland, en la era pre-LLM". Esta simplicidad conllevaba compensaciones conocidas, sobre las cuales escribe aquí.

La CLI de Bun está obteniendo más de 10 millones de descargas mensuales y se usa extensamente dentro de Claude Code.

Todavía en el trimestre pasado, esas compensaciones no habrían sido suficientes para justificar congelar la hoja de ruta y comprometer recursos a un proyecto de varios trimestres. Podías mantener dos bases de código paralelas durante trimestres o años, y si el resultado final era un 90 % de paridad, tenías un dolor de cabeza mayor que cuando empezaste.

Ahora, el peor escenario es que eliminas la rama y lo intentas de nuevo.

Todavía debe haber un caso de negocio justificable. Si bien las migraciones de un millón de líneas ya no cuestan de $3 a $4 millones de dólares en recursos de ingeniería durante un proyecto de cuatro años, aún cuestan decenas a cientos de miles de dólares o más para ejecutarse. La migración de Bun, por ejemplo, consumió 5.9 mil millones de tokens de entrada no almacenados en caché y 690 millones de tokens de salida, alrededor de $165,000 dólares al precio de API. La parte principal del puerto de Mike fue de 27 millones de tokens.

ClaudeDevs - inline image

El PR de un millón de líneas de Jarred.

Sin embargo, el caso de migración ya no necesita ser existencial. Un año de parches de errores de memoria en el registro de cambios, o un cuello de botella crónico, ahora pueden justificarlo.

El paso de compilación fue el impulso para el proyecto de Mike. La herramienta interna en la que trabaja su equipo se envía a los usuarios como un solo binario. Producir ese binario con la cadena de herramientas de Python tomaba aproximadamente ocho minutos por plataforma, totalizando una espera de 30 minutos en toda la matriz de compilación en cada lanzamiento. Después del puerto, la misma compilación ahora toma aproximadamente dos segundos, el binario se inicia 6 veces más rápido y el equipo pudo retirar una canalización de implementación separada.

Por qué la IA cambia las matemáticas de la migración de código

Fable y Opus 4.8 son particularmente buenos para delegar, dirigir y verificar flujos de trabajo paralelos con subagentes, mientras encuentran múltiples caminos hacia los objetivos establecidos.

Las migraciones grandes de código son un caso de uso particularmente efectivo para estos modelos avanzados porque:

  • El trabajo es paralelo. El trabajo se puede ejecutar a través de miles de unidades independientes, como archivos y paquetes, por lo que los agentes pueden trabajar al mismo tiempo en lugar de que uno espere al otro.
  • El contexto es claro y completo. El código antiguo sirve como una excelente especificación para el modelo.
  • Hay un árbitro incorporado. Muchas bases de código grandes incluirán un conjunto de pruebas que los agentes pueden usar para verificar su trabajo.
  • La cola se escribe sola. Cuando una compilación o ejecución de prueba falla, eso se convierte en el siguiente elemento para que un agente lo arregle.
  • Requieren consistencia y manejo de casos extremos: los revisores citan la regla detrás de cada hallazgo, por lo que una violación se convierte en un elemento de la cola en lugar de una divergencia silenciosa.

Seis pasos para migraciones grandes de código

Para obtener detalles adicionales, puedes leer el blog de Jarred.

Requisitos previos

Un requisito previo antes de comenzar tu proyecto de migración es tener un juez sólido en su lugar; de lo contrario, no tendrás una condición de salida ni una medida de éxito.

Para construir este juez:

  • Categoriza las pruebas existentes. Usa Claude para identificar qué pruebas se pueden expresar como llamadas externas y cuáles dependen de elementos internos que no se trasladarán.
  • Reescribe para portabilidad. Convierte las pruebas orientadas a externos en aserciones que se puedan ejecutar tanto contra el original como contra el puerto. Usa agentes adversariales para verificar que las pruebas reescritas no debiliten las aserciones.
  • Valida el juez. Ejecútalo contra el código original para confirmar que pasa. Luego ejecútalo contra código deliberadamente roto para confirmar que falla — un juez que no detecta roturas no es un juez.

Esto sigue principalmente la metodología de Jarred, con revisiones y compuertas en cada etapa. Mike siguió una estructura general similar usando flujos de trabajo de bucle similares, pero ejecutó toda la migración de principio a fin, revisó las reglas y el flujo de trabajo basándose en los resultados, y lo ejecutó de nuevo — descartando la salida cada vez hasta la tercera ejecución.

ClaudeDevs - inline image

Paso 1 — Crear el libro de reglas, el mapa de dependencias y el inventario de brechas

El orden importa: el libro de reglas debe venir antes del inventario de brechas. El inventario de brechas se define por lo que los valores predeterminados del libro de reglas no cubrirán, y ambos se prueban juntos en una auditoría conjunta.

Libro de reglas

La forma exacta del libro de reglas depende de decisiones arquitectónicas clave que debes tomar al principio. La principal de ellas es si el nuevo código seguirá la misma estructura o si se rediseñará por completo.

Si es el primer caso (Jarred), el libro de reglas será principalmente tablas de búsqueda que traduzcan tipos y modismos entre lenguajes, mientras se apunta al inventario de brechas para los componentes más difíciles de traducir. Si es el segundo caso (Mike), será un documento de diseño.

Jarred creó su libro de reglas conversando con Claude, formando una política para cada área de ambigüedad. También usó ocho subagentes diseñados específicamente para revisar 8 categorías diferentes de modos de falla comunes basados en su propia intuición.

Mapa de dependencias

Necesitas comprender las dependencias de archivos para dividir eficazmente los flujos de trabajo para una migración paralela, de modo que sepas qué archivos migrar primero y qué archivos contener en el mismo lote. Claude Code puede desplegar agentes para crear y ejecutar un script determinista que produzca este mapa.

Inventario de brechas y revisores escépticos

El nuevo lenguaje tiene requisitos diferentes del lenguaje antiguo que deben cumplirse. Para Zig a Rust, la diferencia fue la gestión manual de la memoria (C y C++ funcionan de la misma manera). Por ejemplo:

markdown
1// Zig
2
3fn readConfig(allocator: std.mem.Allocator) ![]u8 {
4 const buf = try allocator.alloc(u8, 1024);
5 // ...llenar buf...
6 return buf; // el llamante debe liberar esto — pero solo el comentario lo dice
7}
8
9// Un llamante que olvida 'defer allocator.free(buf)' aún compila — la fuga solo aparece en tiempo de ejecución.
rust
1fn read_config() -> Vec<u8> {
2 let buf = vec![0u8; 1024];
3 // ...llenar buf...
4 buf // la propiedad se transfiere al llamante; la memoria se libera automáticamente
5}
6
7// ¿Usarlo después de que se haya movido? ¿Liberarlo dos veces? Ninguno compila.
8// ¿Olvidar liberarlo? No hay una llamada a free que olvidar — el drop es automático.

Para Python a TypeScript, la brecha fueron las interfaces y los contratos. Python no requiere un contrato que declare qué forma de objeto aceptará o qué devolverá, pero TypeScript sí.

Tanto Jarred como Mike crearon archivos de inventario de brechas capturando este conocimiento implícito. Jarred inventarió estas brechas por adelantado, que es lo que hacemos aquí, mientras que Mike eligió traducir primero y luego crear el inventario de brechas auditando después. Puede que necesites hacer ambas cosas.

Consulta este ejemplo de prompt de Claude Code para crear un archivo de inventario de brechas.

Paso 2 — Poner a prueba las reglas

ClaudeDevs - inline image

En este paso, Jarred usó un agente para traducir tres archivos usando el libro de reglas, un agente para traducir tres archivos "como un ingeniero senior de Rust" y un agente para usar el diff y crear nuevas reglas de traducción. En esta etapa detectó dos problemas críticos que habrían creado numerosos problemas si se hubieran extendido a los 1,448 archivos.

Este tipo de prueba de estrés solo funciona para migraciones que preservan la estructura, donde dos traducciones del mismo archivo son comparables línea por línea. Si tu libro de reglas es un rediseño — como el de Mike — la prueba equivalente es atacar el documento de diseño directamente con revisores adversariales, luego validarlo con una ejecución de extremo a extremo desechable.

Independientemente, descarta cualquier archivo traducido. El objetivo es refinar las reglas, no hacer progreso incremental.

Paso 3 — Traducir todo

ClaudeDevs - inline image

Para los pasos restantes, ejecutas la misma arquitectura de bucle multiagente: implementar, revisar y corregir.

Puedes delegar el trabajo de implementador a modelos más pequeños y mantener a los revisores en los más grandes. Por ejemplo, Mike usó Claude Sonnet cuando desplegó 12 subagentes para la migración principal.

La cola de trabajo debe ser mecánica. Un script por lotes decide qué está hecho verificando si el archivo traducido existe en el disco, luego divide los archivos pendientes en lotes para los agentes implementadores. Debido a que la cola se reconstruye desde el disco cada vez, la migración es reanudable por construcción.

Cualquier cosa que el traductor no pueda ejecutar con confianza se marca con "// TODO(port): <razón>" para tratarse en el paso 4.

Dos revisores adversariales evalúan el trabajo de los implementadores usando contextos separados, y el desacuerdo entre revisores va a un tercer agente. Cuando un revisor sigue detectando el mismo error en varios archivos, la solución no es archivo por archivo. Agregas una oración al libro de reglas y regeneras el lote afectado. El libro de reglas sigue creciendo durante este paso; el código nunca se parchea a mano en su contra.

Una decisión de diseño importante a tener en cuenta en este paso es dónde se ubica el compilador. Mike ejecutó el compilador de TypeScript dentro de cada bucle, porque verifica una unidad en segundos. Jarred prohibió el compilador del bucle por completo y lo difirió al siguiente paso, porque cargo toma minutos.

Pasos 4, 5, 6 — Compilar, ejecutar y comparar el comportamiento

ClaudeDevs - inline image

Estos tres pasos comparten la misma arquitectura de bucle y necesitan progresivamente menos juicio humano, por lo que los cubrimos juntos.

Jarred ejecutó esto con un script orquestador que invocó al compilador una vez en todo el espacio de trabajo. Luego, los "agentes correctores" recorrieron la lista de errores en paralelo con revisión adversarial. La compilación se ejecuta de nuevo, y se repite el ciclo.

Revisar la lista de errores es útil para detectar problemas sistémicos que pueden requerir ajustes. Por ejemplo, Jarred se encontró con miles de errores de módulos de Rust que surgieron después de corregir importaciones cíclicas que la compilación perezosa de Zig toleraba. Corrigió el bucle codificando lógica para clasificar qué dependencia eliminar, mover o reestructurar el límite.

El paso 5 también tiene una fuente de verdad mecánica similar a la lista de errores del compilador: los fallos de la prueba de humo. Nuevamente, la solución del bucle fue agrupar los problemas en categorías, en este caso agrupando las causas por causa raíz que son revisadas por subagentes adversariales.

El paso 6 y el final de nuestra historia es comparar el comportamiento de los programas en las dos bases de código.

Nuestros archivos ya han sido traducidos, compilados y sometidos a pruebas de humo.

Ahora es el momento de fragmentarlos y ejecutar el conjunto de pruebas (de la etapa de requisitos previos) contra ellos. Aborda los fallos con "agentes correctores" que revisen las pruebas fallidas en ambas bases de código. Los revisores adversariales verifican sus correcciones.

La siguiente etapa en este bucle es un demonio de compilación, que es el único proceso permitido para reconstruir el binario. Los correctores escriben parches; el demonio los agrupa, reconstruye una vez, vuelve a ejecutar las pruebas afectadas y alimenta los resultados de vuelta. Esto serializa la operación más costosa en lugar de permitir que múltiples agentes la activen de forma independiente.

El enfoque de Mike es importante aquí, porque muchos desarrolladores no tendrán un conjunto de pruebas desarrollado o migrado. Mike hizo que Claude creara un pequeño script para ejecutar 7 escenarios del mundo real tanto contra el nuevo puerto como contra la base de código original de Python, y comparó las diferencias. Cada escenario fallido tuvo su propio agente corrector, y el bucle se ejecutó hasta que los siete pasaron.

Luego fue un paso más allá. Claude diseñó su propio conjunto de pruebas de extremo a extremo y lo ejecutó de forma autónoma durante la noche, corrigiendo lo que se rompía y volviéndolo a ejecutar durante cuatro noches seguidas. Como resultado, detectó los pequeños problemas que ninguna lista de escenarios habría predicho.

La lección es que la falta de un conjunto de pruebas no bloquea este paso. Si no puedes heredar un árbitro, haz que Claude construya uno. Tu base de código original es la verdad fundamental de cualquier manera.

Mejores prácticas para migraciones de código

Cada ejecución nos enseñó algo que la anterior no. Pero algunas prácticas se mantuvieron en todos los proyectos:

  • No sigas esta guía a ciegas. Cada migración es diferente. Trata esto como un punto de partida y planifica tu migración específica con Claude antes de comprometerte con ella.
  • No te centres en fallos individuales. Los fallos individuales son trabajo del bucle. Tu atención debe estar en los patrones.
  • Haz que la revisión sea adversarial y la verificación mecánica. Deja que los scripts — un compilador, un diff, un conjunto de pruebas — sean el árbitro.
  • No uses el modelo más grande para todo. Los modelos más pequeños manejan bien la implementación de alto volumen; guarda tu modelo más grande para los revisores y para cualquier cosa que escriba reglas que otros agentes seguirán.
  • Carga las horas humanas al principio. El libro de reglas y la prueba de estrés son lo que más tiempo consume. Todo lo demás son principalmente colas que se consumen.

Revisa los resultados del bucle, no el código

La migración de Bun de Jarred ya está en producción, aunque cada migración tiene compensaciones. Por ejemplo, aproximadamente el 4 % del código de Rust está dentro de bloques "unsafe", principalmente operaciones de puntero de una sola línea en los límites de C/C++.

Pero la nueva base de código es measurablemente mejor. Cada fuga de memoria que las herramientas del equipo pueden detectar se ha corregido: un benchmark de 2,000 compilaciones repetidas pasó de 6,745 MB de memoria a 609. El binario es un 19 % más pequeño en Linux y Windows. Y la optimización entre lenguajes lo hizo un 2–5 % más rápido en el servicio HTTP y cargas de trabajo del mundo real como next build y tsc.

Elige la base de código que has estado tolerando y pregúntale a Claude cómo es el proceso de migración para ella.

Guardar con un clic

Lee artículos virales en profundidad con IA en YouMind

Guarda la fuente, haz preguntas concretas, resume el argumento y convierte un artículo viral en notas reutilizables en un único espacio de trabajo con IA.

Explora YouMind
Para creadores

Convierte tu Markdown en un artículo de 𝕏 impecable

Cuando publicas tus propios textos largos, dar formato en 𝕏 a imágenes, tablas y bloques de código es un fastidio. YouMind convierte un borrador completo en Markdown en un artículo de 𝕏 impecable y listo para publicar.

Prueba Markdown a 𝕏

Más patrones por descifrar

Artículos virales recientes

Explorar más artículos virales