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.mdyCLAUDE.mdde la raíz son punteros a Agentes: empieza aquí y no contienen ninguna regla propia:CLAUDE.mdes un@importde esa página, así que Claude Code la carga;AGENTS.mdla 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:statusimprime 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 runlos 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 denpm 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 ennode_moduleso 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:
- Lista los candidatos realistas, incluyendo los más nuevos encontrados en npm y GitHub.
- Puntúalos según criterios fijos y ponderados, con una fuente para cada puntuación.
- Nombra al segundo clasificado y qué nos haría cambiarnos a él.
- 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:
- Genera su propia plantilla y ejecuta sus propios generadores (funciones de la CLI) en una app de prueba.
- Constrúyela y solicita cada ruta que crea; haz una lista de lo que funciona y lo que no.
- 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).
- 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 denpm run ui:theme(el estilo Nova por defecto de shadcn, neutral, Geist: sin preset, sin marca propia).npm run ui:verifyhace fallar la publicación ante cualquier edición manual. El repositorio usa el layout de monorepo de shadcn, así queshadcn addejecutado 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 conshadcn 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--allsolo 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ía | Estado aquí | Regla |
|---|---|---|
| Start, Router, Query | En uso en todas partes | La app, sus páginas y toda la obtención de datos (con oRPC) |
| Form | En uso: solo en el formulario de reservas | Todos los formularios lo usan (inicio de sesión, registro, ajustes); nada de estado de formulario hecho a mano |
| Pacer | No en uso (la búsqueda de la documentación es de Fumadocs) | Cualquier debounce, throttle, límite de tasa o cola en el navegador |
| Devtools | En uso en desarrollo | Mantén los paneles de Router, Query y Form en el único Devtools |
| Table | Lo siguiente: con las pantallas de administración | Toda lista con ordenación, filtrado o paginación, a través de la data table de shadcn |
| Virtual | Cuando una lista se hace larga | Listas de cientos de filas, empezando por las zonas horarias |
| DB (beta) | Todavía no | Solo si necesitamos uso sin conexión o sincronización en vivo; Query cubre las necesidades de hoy |
| AI (beta) | No se usa | El 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 no | Candidata para un atajo de búsqueda cuando salga de alfa |
| Store (alfa), Charts | No es necesario | Todaví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>.mdendocs/content) ni el catálogo de otro locale. - La traducción es su propio paso, en
maintras los merges:dev:landejecutaremy i18n translateahí, al final, cuando algo está desactualizado; nadie la ejecuta por su cuenta. El agente Claude, fijado en la tarea, traduce exactamente lo que listaremy 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:landentonces dice que la traducción todavía se debe, y el siguiente landing lo vuelve a intentar.tests/unit/i18n-docs.unit.spec.tssujeta 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 elnullde 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 checksolo lee, sin conexión, así que es seguro en cualquier lugar, en cualquier número de worktrees, y comodepends.remy i18n translatenunca es undepends.- Desactualizado o faltante es un aviso mientras se avanza (
remy checklo imprime) y un error al publicar (dev:releaseejecutaremy i18n checkconI18N_STRICT=1primero). - 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 queen.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.
| Paso | Comando | Quién lo ejecuta, y cuándo | Qué ejecuta | Tiempo |
|---|---|---|---|---|
| Mirar | npm run dev:status | todos, primero: cada sesión de agente se abre con esto (un hook), un desarrollador cuando se sienta a trabajar | 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, lo primero de .plans/now.md | segundos |
| Antes de un trozo de trabajo | npm run dev:start -- <nombre> | quien hace el trabajo, para cada trozo, incluida una edición de una línea | un worktree propio a partir de main, instalado, con sus propios puertos, el guardián | ~1 min |
| Después de cada cambio | npm run dev:change | quien esté codificando; el único paso que se espera | la 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áquina | npm run dev:land -- "<qué cambió>" | quien hizo el trabajo, por su cuenta, en cuanto termina y la comprobación está en verde | la 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ón | npm run dev:promote | el propietario, o un agente a quien el propietario se lo pidió en esa sesión | remy 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ón | npm run dev:release | el propietario, o un agente a quien el propietario se lo pidió en esa sesión | remy packages release: cada comprobación, cada idioma, localmente, a propósito, y luego la etiqueta | ~5 min |
| Cuando está landed | npm run dev:done | quien hizo el landing, cuando el trozo de trabajo termina; un worktree sobrevive a tantos landings como el trabajo necesite | el worktree y la rama desaparecen | segundos |
-
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 ejecutarremy 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, unplaywright testdesnudo yremy i18n translatefuera del flujo, y en su lugar nombra el paso correspondiente. Todos ellos siguen pudiendo ejecutarse a mano desde una terminal, conREMY_FLOW=handpor 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=handpor delante o se nombra sinnpm run;tests/unit/dev-flow.unit.spec.tslee 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, ynpm run setupterminó 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»). Solodev:change(segundos) se ejecuta y se espera. -
Cada paso dice cuánto tardó.
dev:landtermina 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:changeempieza diciendo qué hizo la última ejecución en main;dev:promotese niega sobre un commit cuya ejecución no esté en verde o no haya terminado. Para reproducir un job en rojo, una persona ejecutaREMY_FLOW=hand npm run test -- <nivel>, el mismo comando que ejecutó GitHub, ya que el workflow no contiene lógica propia (remy verify toolingcomprueba 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:landigualmente 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
grepotailmediante 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ó undev:landfallido.
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
remyque 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 shotspara 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 decurl, 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.mdpara 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, unscripts/*.tsde 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 depackage.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
mainy se borran, junto con su worktree, justo después del merge. Solo se empujanmainy 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:
mainy 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:startcrea el worktree. - Cada worktree tiene su propio
PREVIEW_PORTyDOCS_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=2para 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
- Después de cada despliegue, el informe empieza con las URL en vivo de lo que se desplegó, diga lo
que diga después (propietario, 2026-09-26: «te sigo diciendo... dame la url cuando despliegues»): la
app https://remy-auth.gedw99.workers.dev, su staging https://remy-auth-staging.gedw99.workers.dev, y
para el Worker de documentación su guía https://remy-auth-docs.gedw99.workers.dev/docs,
documentación para desarrolladores https://remy-auth-docs.gedw99.workers.dev/dev y referencia de la
API https://remy-auth-docs.gedw99.workers.dev/reference.
remy cloudflare deployyremy cloudflare docs-deploylas imprimen al final. - Todo informe sobre algo que el propietario pueda mirar da sus URL: los sitios en vivo, la vista previa
(
npx remy cloudflare previewla imprime) y un enlace directo a cada página o funcionalidad comentada. - Di qué se comprobó y qué no.
- Lo que está en vivo se pregunta, no se recuerda:
npm run dev:statusimprime qué está ejecutando cada despliegue y cuán lejos está eso de tu checkout. Dilo a partir de ahí, no de lo que desplegaste la última vez.
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.
| Comando | Qué hace | |
|---|---|---|
| Mirar | npm run dev:status | qué 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 |
| Empezar | npm 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 |
| Codificar | npm run dev:change | la comprobación, en segundos, después de cada cambio |
| Aterrizar | npm 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 |
| Terminar | npm run dev:done | el worktree y la rama que ya aterrizaron desaparecen; se niega mientras algo quede sin aterrizar |
| Producción | npm run dev:promote | a 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:landdel 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:promoteo una ejecución de GitHub; los inicia en segundo plano y actúa sobre el resultado. Solo se espera adev: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:landdice cuando main está en rojo;dev:promoteescribe en el commit qué se publicó;dev:statusmuestra todo esto a quien lo pregunte, y cada sesión de agente lo pregunta primero.
Arquitectura y principios de desarrollo
Lo que el código debe ser: propiedad, una única fuente de verdad, gates de pruebas, código generado y decisiones del dueño.
Referencia de herramientas de desarrollo
La referencia de herramientas de desarrollo: los scripts de package.json y los comandos de remy, herramientas fijadas, secretos, skills de agentes y los servicios de Cloudflare detrás de la documentación.