Ask AI

Cómo trabajamos

Cómo trabajan aquí las personas y los agentes: las herramientas del proyecto primero, encuestas antes de elegir herramientas, shadcn y TanStack, puertas de control, planes y traducciones.

Este documento es el dueño de cómo trabajan las personas y los agentes: los hábitos que ha pedido el propietario, tanto para desarrolladores como para agentes de IA. Lo que el código debe ser vive en principios de desarrollo.

Dónde viven las reglas

  • Escribe cómo trabajamos aquí, en el repositorio, no en la memoria privada de un agente. Cualquiera que abra el repositorio, persona o agente, debe encontrar las mismas reglas. La memoria del agente es solo para cosas que concierne a un único agente, nunca para cómo funciona el proyecto.
  • Cada hecho tiene un único hogar, como exigen los principios de desarrollo; eso también aplica a estas reglas.
  • Los AGENTS.md y CLAUDE.md de la raíz son punteros a Agentes: empieza aquí y no contienen ninguna regla propia: CLAUDE.md es un @import de esa página, así que Claude Code la carga; AGENTS.md la nombra, para Codex y cualquier otra herramienta. Una regla escrita en cualquiera de los dos está en el lugar equivocado (propietario, 2026-10-10: «Agents.md y Claude.md en la raíz deben ser solo un puntero al área de documentación para agentes»).

Ves algo: arréglalo o escríbelo, en el mismo landing

Propietario, 2026-10-09, tras encontrar un hueco cada vez que preguntaba: «Está bastante claro que la documentación de los agentes está mal si estás viendo problemas y no actúas sobre ellos ni te informas a ti mismo ni a los devs». Así que la regla es general, no solo para herramientas que faltan:

  • Un agente o desarrollador que note algo mal, lento, que falte o que haya quedado suelto (un paso que no espera nada, una comprobación que nadie ejecuta, una rama que nadie posee, un documento que dice algo que ya no es cierto) tiene dos opciones, ambas dentro del landing en el que está: arreglarlo cuando es pequeño, o escribirlo en .plans/now.md («Qué queda, en orden»: qué se vio, dónde, y qué lo arreglaría), un archivo de plan cuando es grande. Mencionarlo solo en un chat o en un informe no es ninguna de las dos cosas.
  • Todos se enteran a través del repo: dev:status imprime esa lista en cada sesión (los agentes la abren con esto), así que lo que una persona vio llega a todos, y el siguiente landing toma lo primero de la lista.
  • «Hecho» es el final de una barrida, no de una lista. Antes de decirlo: ramas y worktrees, pull requests abiertas, remy cloudflare versions, remy plans check, una búsqueda de las palabras que el cambio retiró, la documentación que el cambio tocó. Muestra la barrida.

Usa primero las herramientas propias del proyecto

  • Empieza con npm run setup; herramientas para desarrolladores explica qué instala.
  • Antes de hacer cualquier paso a mano (instalar, actualizar, publicar, desplegar, traducir), busca su script: npm run los lista, en cualquier repositorio en el que estés; una app tiene los mismos. Propietario, 2026-09-26, después de que una app fuera actualizada a mano pasando por encima de npm run upgrade: «ya sabes que no reinventamos la rueda».
  • Ejecuta los comandos a través de los scripts de package.json, comprueba la página real con las herramientas de Chrome DevTools (npm run browser), y usa las skills instaladas antes de leer las fuentes originales, buscar en node_modules o escribir scripts de un solo uso.
  • Mira la página real con las herramientas del navegador antes de escribir una prueba para ella.
  • Una vez que las herramientas pueden responder una pregunta, deja de investigar y úsalas.
  • Indica cuánto tardará un paso antes de empezar cualquier cosa más lenta que unos segundos. El comentario de cabecera de cada comando indica su duración y qué puede ejecutarse al mismo tiempo; ejecuta las comprobaciones posteriores al despliegue en segundo plano y sigue trabajando.

Elige herramientas por encuesta, no por el primer hallazgo

Antes de que un plan nombre una librería o herramienta:

  1. Lista los candidatos realistas, incluyendo los más nuevos encontrados en npm y GitHub.
  2. Puntúalos según criterios fijos y ponderados, con una fuente para cada puntuación.
  3. Nombra al segundo clasificado y qué nos haría cambiarnos a él.
  4. Demuestra los dos primeros con pequeñas construcciones de prueba.

Marca como supuesto todo lo que no se haya comprobado.

Una vez elegida una herramienta, adopta su forma

Dobla nuestro sistema hacia la herramienta, no la herramienta hacia nuestro sistema. Antes de construir sobre un framework elegido:

  1. Genera su propia plantilla y ejecuta sus propios generadores (funciones de la CLI) en una app de prueba.
  2. Constrúyela y solicita cada ruta que crea; haz una lista de lo que funciona y lo que no.
  3. Cambia nuestro layout, archivos y lo que nuestro código le pasa a la GUI para que coincidan, conservando solo lo que exige una regla del propietario (las URL de Paraglide, la UI de shadcn).
  4. Elimina lo nuestro que la herramienta ya hace. Un plugin o wrapper hecho a medida tiene que justificarse frente a la forma estándar, no al revés.

Propietario, 2026-09-26, tras descubrir que la documentación de Fumadocs estaba medio personalizada: «Es curioso cómo no te das cuenta hasta que te empujan». (la decisión de Fumadocs).

UI: shadcn y TanStack hasta el final

La UI es difícil y nunca está terminada, así que tomamos lo que shadcn y TanStack han pasado años perfeccionando, y escribimos solo lo que ellos no ofrecen.

  • La CLI de shadcn escribe cada componente y el tema. Los componentes vienen de npm run ui:components, el tema de npm run ui:theme (el estilo Nova por defecto de shadcn, neutral, Geist: sin preset, sin marca propia). npm run ui:verify hace fallar la publicación ante cualquier edición manual. El repositorio usa el layout de monorepo de shadcn, así que shadcn add ejecutado en la app escribe en el paquete compartido.

  • Busca un bloque de shadcn antes de construir un layout o una pantalla: ./node_modules/.bin/shadcn search @shadcn -t registry:block. Añádelo con shadcn add, conserva su estructura, y sustituye solo sus datos de ejemplo. No añadas restricciones que el bloque no tenga (es de ancho completo, así que nosotros también).

  • Compón, no restilices. Usa variantes y tokens semánticos; sigue las reglas de la skill de shadcn instalada (Separator, Skeleton, Badge, Empty, Alert, Field en lugar de equivalentes hechos a mano).

  • Dos tipos de página: páginas del sitio para Google y páginas de la app bajo /app, nunca mezcladas; paths.js define ambas.

  • Adopta la librería de TanStack en lugar de nuestro propio código (Form, el adaptador de Zod de Router, Table, Devtools y demás), instala sus skills de agente, y luego elimina el código que sustituye.

  • Antes de escribir cualquier código de UI, pregunta: ¿esto ya lo hace shadcn, TanStack o Paraglide? Si es así, úsalo.

  • Mírala: antes de dar por terminado un trabajo de UI, haz capturas de las páginas que cambiaste con npm run shots (escritorio y móvil, claro y oscuro, inglés y árabe) y mira las capturas. Las comprobaciones demuestran el comportamiento; solo las capturas muestran el layout, el espaciado, el desbordamiento y el texto de dirección mixta; nombra las páginas que cambiaste (npm run shots -- /formats --phone), usa --all solo para una barrida completa (propietario, 2026-09-26: «Es verdaderamente deprimente lo difícil que es ver bien el aspecto del sitio web»).

Qué librería de TanStack para qué

Comprobado contra tanstack.com el 2026-09-26. Las librerías en beta y alfa cambian rápido: lee su documentación actual y las skills instaladas antes de usarlas, no la memoria de un agente.

LibreríaEstado aquíRegla
Start, Router, QueryEn uso en todas partesLa app, sus páginas y toda la obtención de datos (con oRPC)
FormEn uso: solo en el formulario de reservasTodos los formularios lo usan (inicio de sesión, registro, ajustes); nada de estado de formulario hecho a mano
PacerNo en uso (la búsqueda de la documentación es de Fumadocs)Cualquier debounce, throttle, límite de tasa o cola en el navegador
DevtoolsEn uso en desarrolloMantén los paneles de Router, Query y Form en el único Devtools
TableLo siguiente: con las pantallas de administraciónToda lista con ordenación, filtrado o paginación, a través de la data table de shadcn
VirtualCuando una lista se hace largaListas de cientos de filas, empezando por las zonas horarias
DB (beta)Todavía noSolo si necesitamos uso sin conexión o sincronización en vivo; Query cubre las necesidades de hoy
AI (beta)No se usaEl Ask AI de la documentación es su propia página (/docs/ask, /dev/ask) construida a partir de las piezas de chat de IA de Fumadocs sobre el AI SDK, no una superposición: un solo scroll, la pregunta arriba (la documentación en tus herramientas de IA)
Hotkeys (alfa)Todavía noCandidata para un atajo de búsqueda cuando salga de alfa
Store (alfa), ChartsNo es necesarioTodavía no hay estado de cliente a nivel de app ni dashboards

Pasar una librería de «Todavía no» a en uso sigue elige herramientas por encuesta.

La documentación y la demo se mueven con el código

remy-auth es sobre lo que se construye cualquier otro repo de Remy, y su documentación para desarrolladores es lo que sus agentes y desarrolladores leen (a través de la skill remy, generada a partir de estas páginas). Así que una funcionalidad está terminada cuando se cumplen cuatro cosas: está en el paquete para cada app, la propia app de remy-auth la usa donde cualquiera puede verla funcionar, una comprobación falla cuando se omite, y la página que la describe se actualiza en el mismo cambio. Propietario, 2026-10-09: «Al hacer que remy-auth reutilice todas sus funcionalidades en su propia demo, se facilita incorporar a IAs y devs… la documentación es parte de lo que cualquier otro agente y dev en otros repos recibe». Una página que describe lo que el código ya no hace es un bug; arréglala donde la encuentres.

Idioma: Paraglide es el dueño

Paraglide es dueño de todo el comportamiento del idioma: qué idioma recibe una solicitud, a través de sus estrategias url, cookie, preferredLanguage y baseLocale (configuradas en paraglide.mjs), y los enlaces localizados, que TanStack Router transporta. No escribimos capas neutrales respecto al framework ni código de idioma propio; cuando a Paraglide le falta algo, usa primero sus opciones y registra el hueco en el plan que lo posee.

Traducciones: un único escritor

El inglés es la fuente; las traducciones lo siguen, escritas por un único escritor a la vez. Los agentes cambian estos archivos todo el tiempo, así que traducir dentro de cada rama de funcionalidad choca y deja los idiomas a medio actualizar.

  • Un agente de funcionalidad escribe solo en inglés: la documentación en inglés y el catálogo base (messages/en.json). Nunca edita una traducción (<página>.<idioma>.md en docs/content) ni el catálogo de otro locale.
  • La traducción es su propio paso, en main tras los merges: dev:land ejecuta remy i18n translate ahí, al final, cuando algo está desactualizado; nadie la ejecuta por su cuenta. El agente Claude, fijado en la tarea, traduce exactamente lo que lista remy i18n check, y la tarea lo comitea; el commit es la marca (git decide qué está desactualizado: una traducción está desactualizada cuando su inglés cambió después del último commit de la traducción). Se niega a ejecutarse en otras ramas, con inglés sin comitear, con traducciones sin comitear y en una segunda ejecución mientras otra mantiene el lock, que comparte cada worktree, así que los agentes en paralelo no pueden disparar traducciones ni competir por ellas.
  • El agente no recibe herramientas: se le entrega el inglés (y, para una página desactualizada, el diff del inglés y la traducción actual) y devuelve texto; la tarea escribe los archivos que pidió y nada más.
  • Lo que devuelve el agente se escribe solo cuando es la página: cada campo del frontmatter que tiene su inglés, y el texto que viene después (tasks/i18n/docs/page.ts). Un agente fallido deja la página como estaba, dice por qué y hace fallar la ejecución; dev:land entonces dice que la traducción todavía se debe, y el siguiente landing lo vuelve a intentar. tests/unit/i18n-docs.unit.spec.ts sujeta a cada página traducida del repositorio a la misma regla, en cada comprobación y en GitHub, la única comprobación que recibe el propio commit de una traducción. El 2026-10-09 el null de un agente fallido se comiteó como una página y detuvo la construcción de la documentación en main.
  • Una traducción que no es una página se borra, nunca se restaura a mano: una página que falta se traduce desde el inglés en el siguiente landing, y una restaurada a mano quedaría marcada como actual por su commit.
  • remy i18n check solo lee, sin conexión, así que es seguro en cualquier lugar, en cualquier número de worktrees, y como depends. remy i18n translate nunca es un depends.
  • Desactualizado o faltante es un aviso mientras se avanza (remy check lo imprime) y un error al publicar (dev:release ejecuta remy i18n check con I18N_STRICT=1 primero).
  • Comitea en un archivo de traducción solo cambios de traducción reales: cualquier commit sobre él lo marca como actual. Un cambio estructural (un renombrado, una barrida) que toca traducciones de documentación va seguido de REMY_FLOW=hand npx remy i18n translate docs <archivo>…, que vuelve a comprobar esos archivos contra el inglés por completo. Los catálogos no tienen ese rehacer: cambia la estructura de un catálogo (el archivo de cada locale) en el mismo commit que en.json, para que ninguna clave de inglés cambiada quede oculta.

El layout y los comandos están en la línea de comandos.

Planes: pocos, cortos, cerrados

Propietario, 2026-09-26: «qué agobiante y frustrante es tener tantos planes basura». El trabajo nuevo es una línea en .plans/now.md, en el orden en que se cierra. Un archivo de plan se escribe solo para trabajo lo bastante grande como para aparcarlo o para que se prolongue durante semanas; la investigación, los análisis y las revisiones van en el plan a que sirven, no en un archivo propio. Un plan se cierra el día que su trabajo se publica: una línea de cierre, y luego a .plans/done/. Las grandes funcionalidades esperan en .plans/parked/. Cerrar un plan no necesita un despliegue ni una ejecución de pruebas extra propia: agrupa el código en un único despliegue y una única ejecución completa al final. Las tareas compartidas remy plans … hacen los movimientos: remy plans status lista lo que está abierto, remy plans close, remy plans park y remy plans open (un plan aparcado que se retoma) añaden la línea, mueven el archivo y redirigen cada enlace, y remy plans check (en el check, dev:change) mantiene .plans/ ordenado (tareas).

Cuando el propietario delega decisiones

Cuando el propietario delega decisiones, por ejemplo para terminar trabajo sin supervisión:

  • Decide, y registra cada decisión con sus razones en el plan al que pertenece.
  • Mantén todas las puertas de control en verde; la delegación nunca relaja una comprobación.
  • Deja un informe completo: qué se decidió, qué se hizo, qué se comprobó y qué no.

El flujo: cuatro pasos, y un guardián que rechaza el resto

Propietario, 2026-10-09: «El 95% del tiempo ha sido comprobar y el 5% codificar. Esto no puede continuar así», «Es una cuestión de qué ejecutas localmente y qué ejecutas en GitHub de forma asíncrona», y «Las herramientas formalizan lo que pasa en el desarrollo… asegúrate de que el flujo del desarrollador también esté formalizado para que estas putadas estúpidas no puedan volver a pasar. Y para que tú y los desarrolladores usen ese mismo flujo para que quede arreglado para siempre». Así que el flujo es código, no una regla que recordar: tasks/dev/flow.ts es el único lugar donde viven sus decisiones. Sus cuatro pasos son dev:change, dev:land, dev:promote y dev:release (el Step de flow.ts); dev:start y dev:done enmarcan un trozo de trabajo; dev:status mira; un guardián rechaza lo que no sea uno de ellos. Siete comandos, nada más. remy-auth lo obtiene de la misma forma que cada app, desde las tareas compartidas; npm run setup instala el guardián.

PasoComandoQuién lo ejecuta, y cuándoQué ejecutaTiempo
Mirarnpm run dev:statustodos, primero: cada sesión de agente se abre con esto (un hook), un desarrollador cuando se sienta a trabajarlos últimos commits de main con el veredicto de GitHub, qué ejecuta cada despliegue, cada worktree por delante y por detrás de main, traducciones, pull requests, lo primero de .plans/now.mdsegundos
Antes de un trozo de trabajonpm run dev:start -- <nombre>quien hace el trabajo, para cada trozo, incluida una edición de una líneaun worktree propio a partir de main, instalado, con sus propios puertos, el guardián~1 min
Después de cada cambionpm run dev:changequien esté codificando; el único paso que se esperala comprobación (remy check): planes, tipos con los de las propias tareas, las comprobaciones de funciones simples (tests/**/*.unit.spec.ts), el estado de las traducciones; una build solo cuando cambió un archivo de ruta, la documentación solo cuando cambió la documentación~6 s
El cambio deja la máquinanpm run dev:land -- "<qué cambió>"quien hizo el trabajo, por su cuenta, en cuanto termina y la comprobación está en verdela comprobación, commit, fast-forward de main, push, despliegue en staging, y luego la traducción al final cuando está desactualizada. GitHub entonces ejecuta cada idioma, las auditorías de Google y el fixture de consumer en paralelo, mientras sigues codificando (gh run list)~1 min hasta staging; la traducción después
Producciónnpm run dev:promoteel propietario, o un agente a quien el propietario se lo pidió en esa sesiónremy cloudflare deploy y el Worker de documentación, a partir de un main ya empujado, sin puerta de control: staging y GitHub ya ejecutaron las comprobaciones~1 min
Una publicaciónnpm run dev:releaseel propietario, o un agente a quien el propietario se lo pidió en esa sesiónremy packages release: cada comprobación, cada idioma, localmente, a propósito, y luego la etiqueta~5 min
Cuando está landednpm run dev:donequien hizo el landing, cuando el trozo de trabajo termina; un worktree sobrevive a tantos landings como el trabajo necesiteel worktree y la rama desaparecensegundos
  • Quién ejecuta un paso está en la tabla, y nunca es una pregunta. Un agente aterriza su propio trabajo terminado sin preguntar: staging forma parte del landing, GitHub comprueba cada landing, y nada llega a producción por ese camino. La palabra del propietario es para producción y para una publicación, los dos pasos cuya columna así lo dice, y para el aprovisionamiento (principios de desarrollo). Un agente que lee la tabla y aun así pregunta si debe aterrizar ha dejado de usar el flujo (propietario, 2026-10-10, después de que uno lo hiciera: «¿Está absolutamente claro cuándo te corresponde ejecutar cada paso?»).

  • Un área que parece mal: npm run test -- only <palabras> (las comprobaciones de navegador cuyo título coincide, en y ar, ~30 s). Es la única ejecución de navegador que no es propiedad de un paso.

  • El guardián (remy guard, un hook de Claude Code en cada comando de shell que ejecuta un agente) se niega a ejecutar remy verify, npm run test -- every, npm run test -- quick, npm run test -- remote, npm run test -- google, npm run test -- cwv, npm run test -- consumers, npm run test -- consumers, un playwright test desnudo y remy i18n translate fuera del flujo, y en su lugar nombra el paso correspondiente. Todos ellos siguen pudiendo ejecutarse a mano desde una terminal, con REMY_FLOW=hand por delante (REMY_FLOW=hand npm run test -- every): el propio comando pregunta quién lo está ejecutando (la puerta de control) y se niega ante una ejecución desnuda, en cualquier máquina. Eso es una decisión de una persona; el guardián se niega a ejecutarlo desde un agente aun así, que es el fallo para el que existe. Una tarea cuyo propio trabajo termina con la verificación (npm run setup, npm run packages -- upgrade, npm run upgrade) indica que está preguntando, así que esas se ejecutan tal como están escritas.

  • Estas páginas nunca dan un comando que las herramientas rechacen. Un comando pesado se escribe con REMY_FLOW=hand por delante o se nombra sin npm run; tests/unit/dev-flow.unit.spec.ts lee cada página en inglés y cada tarea en busca de una ejecución desnuda, en cada comprobación (2026-10-10: ocho líneas en seis páginas lo hacían, y npm run setup terminó en el rechazo).

  • Una regla que puede ser una función pertenece a tests/**/*.unit.spec.ts (sin build, sin Worker, sin navegador), así se ejecuta en cada comprobación gratis. El navegador es para lo que solo un navegador muestra.

  • Un agente nunca espera en un paso de larga duración. dev:land, dev:promote, dev:release, una traducción, una suite remota: inícialo en segundo plano, sigue trabajando o responde al propietario, y actúa cuando el harness diga que terminó. Iniciarlo en segundo plano y luego hacer polling de él en primer plano es el mismo fallo (propietario, 2026-10-09: «Acabas de hacerlo otra vez con 2 cosas de larga duración»). Solo dev:change (segundos) se ejecuta y se espera.

  • Cada paso dice cuánto tardó. dev:land termina con sus partes (la comprobación; commit, main y push; staging; traducción) y dice cuánto tardó staging en estar listo desde el inicio; el traductor dice, para cada llamada al agente, cuánto tardó Claude Code, cuánto de eso fue la API, y cuántos tokens escribió. Un paso lento es un número en el log, no una sensación (propietario, 2026-10-10, sobre un landing con staging listo a los 40 segundos cuyo comando tardó seis minutos: «cómo puede ser 6 minutos»).

  • La respuesta de GitHub viene a ti. Una ejecución en rojo comenta en el commit (GitHub se lo dice a su autor), nombrando la ejecución; dev:change empieza diciendo qué hizo la última ejecución en main; dev:promote se niega sobre un commit cuya ejecución no esté en verde o no haya terminado. Para reproducir un job en rojo, una persona ejecuta REMY_FLOW=hand npm run test -- <nivel>, el mismo comando que ejecutó GitHub, ya que el workflow no contiene lógica propia (remy verify tooling comprueba que exista cada script que un workflow nombra). Un agente lee el propio log de la ejecución (gh run view <id> --log-failed) y ejecuta el área concreta (npm run test -- only <palabras>). Informa de qué se probó y qué no; nunca llames verificado a un trabajo no probado.

  • Un landing que falla después del push aun así termina lo que puede, y dice dónde se detuvo. Main se empuja antes que staging; cuando el despliegue de staging o su smoke en vivo falla, dev:land igualmente ejecuta la traducción (está en main, se debe de todos modos), y luego termina con código distinto de cero con el estado en una línea: en qué commit se empujó main, si staging se desplegó o no, qué smoke falló, si la traducción se hizo o no. No se deja nada a medias para que la siguiente persona lo descubra (propietario, 2026-10-10, después de que un landing se detuviera en el smoke con la traducción omitida en silencio: «ahora tú y los demás agentes estáis jodidos»).

  • Nunca encadenes un comando de control con grep o tail mediante un pipe: el pipe oculta su código de salida. Una vez esto publicó una versión cuyas comprobaciones habían fallado, y el 2026-10-10 ocultó un dev:land fallido.

El trabajo manual se convierte en scripts sobre herramientas reales

Propietario, 2026-09-26: «¡Necesitas llegar al punto en que tus comprobaciones usen mise y la herramienta subyacente!» y «asegúrate de tener algo en la documentación sobre usar tu criterio respecto a las cosas que haces manualmente y convertirlas en una tarea de mise que use una herramienta… Es vital porque todos nuestros repos van a usar esto».

  • Cada comprobación se ejecuta a través de un script o un comando de remy que envuelve la herramienta real: los pasos del flujo y las comprobaciones (npm run test, Playwright), el smoke en vivo después de un despliegue, remy plans check, remy i18n check, npm run shots para mirar. (Las palabras del propietario de arriba dicen mise, que los scripts reemplazaron el 2026-10-11; la regla es la misma.) Nada de bucles de curl, scripts de un solo uso o greps improvisados para decidir si algo funciona: no se pueden repetir, las apps sobre el paquete no los reciben, y nadie los ve después.
  • Usa el criterio en todo lo que se hace a mano, no solo en las comprobaciones: la segunda vez que escribes los mismos comandos o recurres a un script descartable, se convierte en un comando del paquete (packages/ui/src/cli, para que cada app lo reciba) que llama a la herramienta que hace el trabajo: Wrangler, Playwright, gh, npm.
  • ¿No se encuentra ninguna herramienta? No escribas un script y sigas adelante. Añade una línea a .plans/now.md para hacer una encuesta (elige herramientas por encuesta); si la búsqueda o el cambio es grande, escribe un plan en .plans/ (o en .plans/parked/) tú mismo. Los agentes crean estas líneas y planes al encontrarse con tales cosas; el propietario no tiene que pedirlo.
  • Todo lo que es más que una línea de una herramienta es TypeScript: un comando de remy (packages/ui/src/cli, con type-check en cada comprobación) o, para lo que es propio de una app, un scripts/*.ts de esa app, nunca lógica en bash ni JavaScript sin tipos: lo que el compilador no puede ver, un agente se lo pierde (propietario, issue #9). Una herramienta de una línea es un script de package.json (el plan).

Ramas: de vida corta, borradas tras el merge

  • El trabajo ocurre en ramas dentro de worktrees de git (uno por agente); se mezclan en main y se borran, junto con su worktree, justo después del merge. Solo se empujan main y las etiquetas de publicación; una rama va a GitHub solo para una pull request, y GitHub la borra cuando la PR se mezcla («Automatically delete head branches», activado para cada repo, 2026-09-26).
  • Una rama mezclada que queda suelta (local o en GitHub) es ruido, no historia: main y las etiquetas la contienen.

Compartir una máquina entre agentes

La máquina se cayó el 2026-09-25 con unos diez agentes construyendo y probando a la vez (carga 188), y las comprobaciones sensibles al tiempo fallaron mucho antes de eso. Así que:

  • Un agente construye y prueba solo en su propio worktree de git, nunca en el checkout principal: las builds escriben en dist/, y dos builds en un mismo checkout se borran los archivos entre sí. dev:start crea el worktree.
  • Cada worktree tiene su propio PREVIEW_PORT y DOCS_PREVIEW_PORT, calculados a partir de su nombre (nunca 4190, que los navegadores bloquean); PREVIEW_PORT=4232 npm run … los sobrescribe.
  • Como máximo tres agentes ejecutan pruebas al mismo tiempo; la investigación, la escritura y los spikes de prueba no cuentan. Cuando se necesitan más, pon PLAYWRIGHT_WORKERS=2 para cada uno.
  • El nivel de Google (npm run test -- google, npm run test -- cwv) toma un lock de toda la máquina, así que una segunda ejecución espera en lugar de distorsionar la primera.
  • Nunca encadenes un despliegue después de una comprobación con ;: los pasos del flujo se ejecutan uno tras otro y se detienen en el primer fallo.

Informar al propietario

Muchos agentes, un flujo

Propietario, 2026-10-09: «formaliza la forma en que gestionamos el trabajo de desarrollo entre muchos agentes para usar el nuevo flujo de desarrollo». Cada trozo de trabajo, quienquiera que lo haga, es un worktree a través de los mismos comandos; main es el único integrador, y GitHub comprueba cada landing. Nada de esto se hace a mano.

ComandoQué hace
Mirarnpm run dev:statusqué está pasando, preguntado a los dueños de los hechos: los últimos commits de main con el veredicto de GitHub, qué ejecuta cada despliegue, cada worktree por delante y por detrás de main, traducciones, pull requests. Cada sesión de agente se abre con esto (un hook que registra remy guard); un desarrollador lo ejecuta cuando se sienta a trabajar
Empezarnpm run dev:start -- <nombre>un worktree en la rama <nombre> a partir de main (.claude/worktrees/<nombre>), instalado (npm ci, el script local de la app), con puertos propios y el guardián del flujo. Los propios worktrees de Claude Code viven en el mismo lugar y son solo una carpeta: dentro de uno, npm run dev:start sin nombre lo prepara de la misma forma
Codificarnpm run dev:changela comprobación, en segundos, después de cada cambio
Aterrizarnpm run dev:land -- "<qué cambió>"primero se mezcla main (un conflicto se detiene nombrando los archivos), la comprobación, commit, fast-forward de main, push, staging, y luego la traducción al final cuando está desactualizada (la suscripción de Claude en esta máquina, nunca GitHub). GitHub ejecuta las comprobaciones pesadas; una ejecución en rojo comenta en el commit
Terminarnpm run dev:doneel worktree y la rama que ya aterrizaron desaparecen; se niega mientras algo quede sin aterrizar
Producciónnpm run dev:promotea partir de main, solo un commit que GitHub aprobó, con la palabra del propietario
  • Divide por independencia. Un orquestador divide el trabajo en partes que tocan archivos diferentes, y inicia un agente por parte con dev:start. Una parte que necesita el resultado de otra espera a ese landing; no comparte worktree.
  • Haz un spike primero cuando el riesgo es desconocido: un agente demuestra el punto arriesgado y aterriza o se detiene.
  • Cada parte se demuestra a sí misma: aterriza con su propia comprobación en tests/, una función simple (tests/**/*.unit.spec.ts) cuando puede serlo, en el navegador cuando solo un navegador lo muestra.
  • Los landings se serializan solos. Dos agentes aterrizando a la vez: el dev:land del segundo ve que main se movió, lo mezcla, vuelve a comprobar y aterriza. El paso de traducción es un único escritor en todos los worktrees.
  • Revisión práctica antes de producción. Pasar las comprobaciones no es el final: usa la pieza en staging en un navegador real, con el ancho de un móvil, y arregla lo que se sienta mal. Luego dev:promote.
  • Un agente nunca espera en primer plano a dev:land, dev:promote o una ejecución de GitHub; los inicia en segundo plano y actúa sobre el resultado. Solo se espera a dev:change.
  • Todo lo asíncrono vuelve a todos (el plan): un job de GitHub en rojo escribe en el commit, nombrándose a sí mismo; dev:land dice cuando main está en rojo; dev:promote escribe en el commit qué se publicó; dev:status muestra todo esto a quien lo pregunte, y cada sesión de agente lo pregunta primero.

On this page