Los scripts que debí escribir primero
En esta página
El 29 de octubre construí este sitio en un día con Claude. Cada parte del trabajo tuvo su propio hilo: la página «Sobre mí», el cursor de papel, la página de proyectos, las traducciones al jemer y al español. Al final del día se habían hecho merge de 33 pull requests.
Esa noche le pedí a Claude que releyera todos los hilos y buscara las tareas que se repetían. Había muchas, y casi ninguna estaba escrita en un lugar donde un hilo posterior pudiera reutilizarla.
Las mismas tareas en cada hilo
Este sitio tiene una regla que lo hace parecer una página de mi cuaderno: cada línea de texto se apoya en un renglón, a 32px uno del otro. Antes del pull request que lo armó, solo 72 de 1.502 líneas de texto caían sobre un renglón. El hilo que lo arregló escribió su propio script para medir, revisó 16 páginas en seis anchos, y luego el script se fue con la sesión.
Cada hilo que vino después tuvo que probar que no había movido nada de los renglones, y cada uno lo hizo a su manera. Algunos corrieron una comprobación de una línea que estaba en AGENTS.md. Otros miraron capturas. Aun así se colaron errores:
- Las etiquetas de las tarjetas de artículos tapaban las fechas de abajo. Ese lo vi yo mismo, en la página de inicio en jemer y en modo oscuro.
- El contador de «me gusta» quedaba 12px fuera de su renglón, y el encabezado se desplazaba hacia los lados en teléfonos de 320px. La revisión de código atrapó los dos.
- Una tarjeta nueva de «trabajemos juntos» sacó el pie de página de su renglón cuando se juntaron dos ramas.
Las otras tareas eran parecidas. Cada página necesitaba capturas en tres idiomas, en modo claro y oscuro, en computadora y en teléfono: doce por página, armadas a mano cada vez. Cada pull request necesitaba su enlace de vista previa y su nivel de riesgo, escritos a mano. Los agentes no podían oír los sonidos que agregaban, así que me pedían que los revisara de oído.
Un agente vuelve a construir una herramienta desechable cada vez que se lo pides, sin quejarse. Pero cada versión revisa cosas un poco distintas, y ninguna sobrevive a la sesión.
Tres scripts
Así que las tres tareas más comunes ahora son scripts en el repositorio, y AGENTS.md le dice a cada agente que los corra.
Medir el texto contra los renglones
bun run lines construye el sitio, lo sirve, abre cada página en Chromium en cinco anchos y mide cada línea de texto contra los renglones.
bun run lines # every page, at 320, 375, 768, 1024 and 1280px
bun run lines --quick # only 320 and 1280px
bun run lines /about/ --darkMide una línea igual que el script de respaldo de la propia página la acomoda. Un texto empieza a la altura del ascendente de la fuente por encima de su línea base, y los renglones están 22px más abajo cada 32px desde el inicio de la página:
for (const rect of range.getClientRects()) {
if (rect.width < 1 || rect.height < 1) continue;
const baseline = rect.top + scrollY + up;
let miss = (((baseline - rules.top) % rules.gap) + rules.gap) % rules.gap;
if (miss > rules.gap / 2) miss -= rules.gap;
const line: Line = {
text: node.textContent!.trim().replace(/\s+/g, ' ').slice(0, 60),
where: where(parent),
miss: Math.round(miss * 10) / 10,
baseline,
box: {
x: rect.left + scrollX,
y: rect.top + scrollY,
width: rect.width,
height: rect.height,
},
};
// …count the line…
if (Math.abs(miss) > tolerance) result.off.push(line);
// …then look for a sticker on top of it.
}También marca como fallida una página cuando una etiqueta tapa una línea de texto, que era el error de las tarjetas. Volví a poner el espaciado viejo para probarlo, y nombró la fecha y la etiqueta que tenía encima.
La primera vez que lo corrí en el sitio publicado, encontró un error que nadie había visto. En la página «Sobre mí», los títulos de los artículos en las tarjetas de «Cómo trabajo» quedaban 2px por debajo de sus renglones. La letra a mano es más grande que el texto que la rodea, así que empujaba toda la línea hacia abajo:
✗ /about/ at 375px
+2px off "How I'd do pull request review today" (… > cite.font-hand.text-xl)Cada problema trae además un acercamiento, con el renglón en azul y la línea base del texto en rojo. Con el modo oscuro incluido, una corrida completa mide más de 10.000 líneas en todas las páginas del sitio en unos 40 segundos.
Tomar las capturas
bun run shots toma cada página que le indiques en inglés, jemer y español, en modo claro y oscuro, a 1280 y 375px. Luego las acomoda en una hoja por página y por tamaño de pantalla, para que un pull request muestre seis capturas en una sola imagen en vez de seis archivos.
bun run shots /about/ --before main --mark 'cite.font-hand' --note 'back on its rule' --widths 1280,375 --publish--before main construye la rama main junto a la tuya y pone las páginas viejas y nuevas lado a lado. --publish sube las hojas a la rama donde viven las capturas e imprime el Markdown para pegar en el pull request.
También quería que la prueba señalara lo que cambió. --mark recibe un selector CSS: enmarca ese elemento en cada captura, le apunta con una flecha con la nota de --note y pone acercamientos arriba de la hoja, antes y después.
Abre las páginas en jemer y en español en sus propias direcciones. La página de inicio elige un idioma para cada visitante y trata a un navegador sin interfaz como un bot, así que un agente que solo abría la página de inicio siempre recibía inglés.
Preparar el pull request
bun run pr check corre todo lo que tiene que pasar antes de un push: el nombre de la rama, los mensajes de commit, el formato, la revisión de tipos, el build y una corrida rápida de la medición de renglones. bun run pr body llena la plantilla del pull request con el enlace de vista previa y un nivel de riesgo sugerido.
const HIGH = [
/^worker\//,
/^wrangler\.(jsonc?|toml)$/,
/^\.github\/workflows\//,
];
// Agent instructions change how every later change gets made.
const MEDIUM = [/^\.claude\//, /^AGENTS\.md$/];
const LOW = [
/^src\/content\//,
/^src\/assets\/articles\//,
/^src\/i18n\/ui\.ts$/,
/^docs\//,
/\.md$/,
];El nivel sale de las rutas que toca un cambio, como en mi forma de revisar pull requests: gana el nivel más alto. El script no puede saber cuándo un cambio agrega un inicio de sesión nuevo o una integración externa, así que lo avisa, y esa decisión queda en manos de quien escribe el cambio.
Lo que aprendí al construirlos
Apaga lo que no estás revisando
La primera versión tardaba más de un minuto en 80 vistas de página. Lo lento resultó ser el avatar 3D. Chromium sin interfaz dibuja WebGL por software, así que cada cuadro de una página con el avatar tardaba casi un segundo. La medición de renglones no necesita el avatar, solo su marco, así que ahora arranca Chromium con el 3D apagado, y cada página tarda medio segundo en vez de cuatro y medio.
export async function launch({ webgl = true } = {}): Promise<Browser> {
try {
return await chromium.launch({ args: webgl ? [] : ['--disable-3d-apis'] });El script de capturas deja el 3D encendido, porque ahí el avatar es lo importante.
Simula lo que no está
El botón de «me gusta» necesita un Worker de Cloudflare que solo corre en producción, así que en un build local queda oculto. Antes, los hilos simulaban su respuesta a mano, cada uno un poco distinto. Ahora el pequeño servidor de los scripts responde siempre con el mismo número inventado, y el botón aparece en todas las capturas.
Los errores que se escapan se vuelven comprobaciones
En mi artículo sobre pull requests dije que cuando un error pasa la revisión, el arreglo debería agregar lo que lo habría atrapado. Las etiquetas encima de las fechas ahora son una comprobación que falla, y no algo que veo de casualidad en una captura. Lo mismo pasa con cualquier página que se desplace hacia los lados.
Los agentes ahora siguen la misma regla. Junto a los scripts hay una skill que lleva a un agente desde una rama nueva hasta un pull request abierto, y su último paso pregunta qué enseñó el cambio. Un error que pasó las comprobaciones se vuelve una comprobación nueva. Un tropiezo que costó un reintento se vuelve una lección de una línea en la skill, y cuando un script ya lo resuelve, la lección se va. Cada cambio a la skill llega en el mismo pull request que el código, así que la reviso igual que el código.
Quedan seis tareas más en la lista, como esperar a que la vista previa se reconstruya antes de decir que está lista, y una revisión de sonidos para oídos que no están. Llegarán de a una, cuando me hayan molestado lo suficiente.
¿Qué es lo que tu agente vuelve a construir desde cero una y otra vez?
0me gusta
¡gracias!