# Reflexiones sobre la ingeniería de harnesses (lo que sea que signifique)

> Original en inglés. Traducción generada por IA, no por el autor. [Leer el original en inglés](https://www.ferueda.com/writing/thoughts-on-harness-engineering).

> Ya no escribo código. Construyo lo que los agentes necesitan para escribirlo.

Hoy los agentes escriben el 100% de mi código. Planeo algo, ellos escriben el código, lo revisamos, corregimos lo que haga falta y lo pasamos a la siguiente sesión. Una y otra vez.

Funciona. Pero puede desordenarse muy rápido si no hay algo fuera del modelo que mantenga todo unido.

A ese algo lo llamo harness. Construirlo y mantenerlo es lo que entiendo por ingeniería de harnesses.

Un harness es, literalmente, un arnés: correas y equipo para controlar o asegurar algo. En inglés, “to harness” significa aprovechar eficazmente un recurso.

> El modelo es inteligente, pero si lo dejas solo se va por todos lados. El harness es la forma de guiarlo sin pelear con él en cada tarea.

Cuando lo pienso, en realidad hay dos capas.

**El harness alrededor del modelo.** Cursor, Codex, Claude Code, lo que uses. Es el producto que envuelve al LLM. Sesiones, herramientas, permisos, cómo el agente lee archivos y ejecuta comandos. Está hecho para todos. Eliges uno, ajustas la configuración, quizá conectas algunos servidores MCP. Pero no lo estás construyendo. Eres usuario. Por definición, tiene que funcionar para miles de personas.

**El harness alrededor del proyecto.** Es lo que _tú_ controlas. Lo que construyes para ti, tu equipo y tu código base. Scripts locales, cómo se organizan las pruebas, el comando que significa “terminado”, `AGENTS.md`, skills y documentos que apuntan a archivos reales. Nadie lo va a escribir por ti. Es lo que permite al agente trabajar _en tu mundo_ sin empezar desde cero en cada sesión.

Ambas capas importan. Este artículo trata principalmente de lo que controlas: la capa que te pertenece, la parte que construyes para tu proyecto y tu equipo.

## El modelo predice. El harness hace cumplir las reglas.

El mismo prompt, otra ejecución, otra respuesta. Ambas pueden sonar correctas. No es un bug. Así funciona la predicción.

- **El modelo** predice el siguiente token plausible. El resultado cambia entre ejecuciones.
- **El harness** define qué cuenta como terminado. El mismo repositorio, las mismas verificaciones, las mismas reglas.

## Entonces, ¿qué es la ingeniería de harnesses?

No es elegir Cursor en lugar de Codex. Tampoco es “escribir un mejor prompt”.

Es la infraestructura que construyes para que el agente no avance a ciegas en _tu_ código base:

- Intención clara. ¿Cómo se ve realmente un trabajo terminado?
- **Conocimiento en el repositorio, no en el chat**
- Verificaciones que demuestren el trabajo sin preguntarle al modelo “¿esto va a funcionar?”
- El hábito de convertir fallos repetidos en algo permanente

Cuando lo mismo falla dos veces, “arréglalo, no cometas errores” quizá vuelva a funcionar. La verdadera pregunta es: ¿qué falta y cómo lo hacemos evidente y verificable?

> Los prompts son sugerencias. Los linters son ley.

## El ciclo que realmente uso

En el día a día se ve así:

**Planificar → Implementar → Verificar → Revisar**

Si la revisión no es satisfactoria, vuelves a implementar. **Verificar no es una sensación.** Es `npm run verify`, o el equivalente en tu repositorio. Pruebas, lint y comprobación de tipos. Cosas que puedes ejecutar.

| Paso        | Quién                    | Qué ocurre                                                      |
| ----------- | ------------------------ | --------------------------------------------------------------- |
| Planificar  | Tú (quizá con el agente) | Qué hacemos, qué entra en el alcance, qué cuenta como terminado |
| Implementar | Agente                   | Código, pruebas y documentación. Esta es la parte incierta.     |
| Verificar   | Verificaciones + agente  | Los mismos comandos siempre. ¿Pasó o no?                        |
| Revisar     | Tú y/u otros agentes     | ¿Realmente tiene sentido? Volver atrás si no.                   |

## Cuando lo mismo falla dos veces, arregla el repositorio

Hay un ciclo paralelo a todo esto:

**Errores / bloqueos / tareas repetidas → capturar lo aprendido → incorporarlo a las herramientas**

Sabrás que llegó el momento cuando:

- Dejas el mismo comentario de PR dos veces
- El agente tropieza con el mismo obstáculo dos veces
- Alguien dice “siempre se nos olvida...”
- Local pasa, CI falla y te das cuenta de que esa verificación nunca estuvo
- Un revisor sigue corrigiendo el mismo patrón

Cuando pasa, suelo avanzar en este orden:

1. Documentación. Escribir el patrón.
2. Pruebas. Cubrir lo que falló.
3. Lint. Hacerlo cumplir si es posible.
4. Scripts. Convertir el flujo en un comando que el agente pueda ejecutar y verificar por su cuenta.

> Cada vez que explicas lo mismo dos veces, le debes un control de protección al código base.
>
> El harness es la parte del sistema que recuerda cuando el modelo olvida.

Eso retroalimenta la planificación y la verificación. Una mejor documentación reduce las malas suposiciones antes de implementar. Mejores verificaciones detectan desviaciones antes de la revisión. Así obtienes resultados confiables de algo que no lo es por naturaleza.

## Lo que realmente necesitas

Puedes organizarlo de muchas maneras. Estas son las piezas de la capa del proyecto que considero importantes:

**Intención y conocimiento.** Si solo vive en el chat, se pierde. El código base es la memoria. `AGENTS.md` debería ser un **mapa, no un libro**. Referencias breves a documentos reales. Notas de arquitectura que no sean obvias. Si haces X, lee Y primero. Skills que traigan el contexto necesario para la tarea, no toda la carpeta de documentación.

**Verificaciones.** **Un comando que signifique terminado.** Comprobaciones rápidas en el commit. La verificación completa antes del merge. El mismo comando en local y en CI. Quieres ver todos los fallos a la vez, no uno por uno. Esto es lo que llama el harness del modelo al ejecutar `npm verify` o `make validate`. **Tú le das la herramienta al agente. El proyecto define qué significa pasar.**

**Reglas.** Las reglas que los agentes realmente encontrarán antes de entregar. Linters que digan cómo corregir el problema, no solo que algo está mal. Reglas propias cuando las genéricas no alcancen. Mi regla: si lo explicas dos veces en revisión, codifícalo.

**Niveles de pruebas.** Una pirámide con reglas claras sobre dónde van las pruebas. Pruebas rápidas junto al código por defecto. Un umbral alto para E2E completo. Desarrollo local que funcione sin conexión para que el agente no espere a que arranque algo en la nube.

**Tu tiempo es el cuello de botella.** Deja a los agentes preparar el entorno, hacer las primeras comprobaciones y buena parte de la revisión mecánica. Tú decides qué importa, qué significa terminar y lo que aún no pueden decidir la documentación y las verificaciones.

> El harness del modelo se vuelve más inteligente cada pocos meses. El harness del proyecto es tuyo para seguir construyéndolo. Esa es la parte que acumula valor.

## Dale herramientas reales a tus agentes

El harness de un modelo puede leer archivos y ejecutar comandos de shell. No alcanza. Debes darle las herramientas _adecuadas_ para _tu_ código base.

Nada de esto es nuevo. Linters, formateadores, comprobadores de tipos, suites de pruebas, un comando que diga que la compilación está bien. Los equipos llevan años usando todo eso.

Lo distinto ahora es cuánto código se escribe. Un agente puede modificar montones de archivos en segundos. ¿Los linters y las verificaciones que quizá omitías un viernes por la tarde? Ya no puedes permitirte eso. Mucho más código que cuando lo escribías tú. Las mismas herramientas de siempre. Solo que ahora importan mucho más.

A lo que me refiero:

- ¿Algo falló? El agente debería enterarse rápido, sin que le expliques cómo ejecutar pruebas.
- ¿El código no sigue tus patrones? Los linters y comprobadores de tipos deberían decirle qué está mal, con suficiente detalle para corregirlo.
- ¿El entorno local es un desastre? Prepararlo debería ser un comando que el agente pueda ejecutar, no un hilo en Slack.
- ¿Fallaron las verificaciones? La herramienta debería decir qué falló y cómo corregirlo, no solo que algo falló. Y luego qué ejecutar (`make fix`, repetir la verificación).

Tipos, lint y formato: deberían funcionar en automático y dar respuestas claras. No “algo falló por ahí”. Archivo, línea, regla y, muchas veces, una pista sobre qué cambiar. El agente lee esa salida como tú leerías errores del compilador. No quieres que adivine si el código sigue las reglas de la casa. **Quieres que la casa se lo diga.**

Esa es la capa de comunicación entre el harness del modelo y el del proyecto. El primero ejecuta el comando. Tu `AGENTS.md` dice cuándo. El Makefile, o script del paquete, dice qué incluye. El linter dice qué está mal. El agente lo corrige y vuelve a ejecutar.

La documentación también importa. No una wiki que nadie actualiza. Guías breves que el agente realmente cargue: nombres, ubicación de pruebas, qué significa “terminado” y qué comando ejecutar para cada parte del monorepo. Skills con contexto específico de la tarea, para que no pegues la misma explicación en cada sesión.

## Un ejemplo concreto

Así se ve algo de esto en la práctica. Harmoney es un monorepo en el que trabajo (móvil, backend, Supabase).

**Preparación.** `make prepare-local-env` crea los archivos `.env` que faltan a partir de ejemplos y completa valores locales seguros. `make check-local-env` dice si estás listo antes de las verificaciones pesadas. Los agentes pueden resolverlo por su cuenta en lugar de pedirte la duodécima variable de entorno.

**Guías.** El `AGENTS.md` raíz es el mapa: intención del producto en `VISION.md`, límites en `ARCHITECTURE.md`, notas transversales en `LEARNINGS.md`. Un `AGENTS.md` por app en `apps/mobile` y `apps/backend`. Reglas fijas que los agentes pueden citar: todo texto visible al usuario está en `pt-BR`, la identidad viene del JWT y no del cuerpo de la petición, los bugs empiezan con una prueba que falla. Verificaciones acotadas: ¿solo cambió móvil? `make check-mobile`. ¿Solo backend? `make check-backend`.

**Niveles de pruebas.** La pirámide está documentada para que los agentes no elijan siempre lo más lento.

- **Pruebas unitarias rápidas, junto al código.** La mayoría de la lógica de handlers tiene un `*.test.ts` al lado del archivo que prueba. `apps/backend/src/payments/handle-refund.ts` junto a `handle-refund.test.ts`. Simula la base de datos, ejecuta un flujo y añade las aserciones necesarias. Es la opción por defecto.
- **Pruebas de base de datos cuando Postgres sea el foco.** ¿Políticas RLS, contratos RPC, comportamiento de migraciones? pgTAP en `supabase/tests/`. ¿Integración del backend con una base local real? `make db-test-ts`. No todos los cambios lo necesitan. Solo cuando la base de datos sea realmente lo que estás verificando.
- **Smoke tests de API, mínimos.** Un pequeño recorrido programado para autenticación y un webhook exitoso. La regla es la misma que en una buena suite E2E: no añadas un caso salvo que necesites de verdad el transporte HTTP real, OAuth y la integración de sesión a la vez. Dos recorridos, no veinte.
- **E2E completo de interfaz, último recurso.** Web o móvil, el mismo umbral: uno o dos recorridos que demuestren que el inicio de sesión y una pantalla crítica funcionan de extremo a extremo. Lentos, frágiles y costosos de mantener. La respuesta por defecto es no. Los agentes empiezan por pruebas unitarias junto al código.

Menos pruebas, más completas, superan a cien de una línea. Sin fijar cadenas exactas en descripciones de herramientas o textos de interfaz. Sin conexión por defecto. El harness le indica al agente qué nivel usar para que no tenga que adivinar.

**Retroalimentación automática.** Cada workspace ejecuta formato, lint y comprobación de tipos como parte de `check`. Las migraciones SQL tienen sus propios scripts de lint. Los controles de invariantes detectan errores de arquitectura de forma estática.

**La verificación.** `make verify` es la definición local de terminado: `make check` más comprobaciones de base de datos (pgTAP, paridad de contratos y pruebas de backend con base de datos). `make fix` entre workspaces cuando sirva la corrección automática, y después repetir la verificación correspondiente.

**Cuando algo falla.** `AGENTS.md` lo dice claramente: si fallan las comprobaciones, ejecutar `make fix` y después el objetivo pertinente. Sin adivinar si hacía falta la verificación de móvil o la suite completa de base de datos.

La estructura siempre es la misma:

1. **Orientarse** — `AGENTS.md` + el documento de la tarea
2. **Implementar** — el agente escribe código y pruebas junto a él
3. **Verificar** — un comando autoritativo (`make verify`)
4. **Revisar** — personas, agentes y preview cuando ayude
5. **Codificar** — el error repetido se convierte en documentación, prueba o regla de lint

**La ventaja no es memorizar seis jobs de CI.** Es **tener una respuesta a “¿terminamos?”** Ejecuta la verificación. Verde en local debería significar verde en CI. Eso es el harness del proyecto haciendo su trabajo.

Tampoco es magia. Las comprobaciones de base de datos necesitan Docker activo. Las verificaciones acotadas no ejecutan toda la suite. Una versión incorrecta de Node sigue arruinándote la tarde. Los agentes omiten pasos si se lo permites. **El harness reduce las suposiciones. No sustituye tu criterio.**

## Lo que realmente creo

1. Los resultados probabilísticos están bien. Los resultados probabilísticos sin controles en producción, no.
2. **Las buenas verificaciones acumulan valor. El caos se desvía.**
3. **El chat no es memoria. El repositorio sí.**
4. Las reglas breves y verificables superan a un documento de instrucciones de 50 páginas.
5. El harness nunca está terminado. Se construye junto al producto.
6. El criterio se incorpora a las herramientas para que no tengas que estar en cada PR.

La ingeniería de harnesses no reemplaza a los ingenieros. Solo cambia dónde inviertes tu tiempo. Menos escribir cada línea. Más diseñar un entorno donde los agentes puedan hacer trabajo real.
