Harness Engineering: Por Qué los Agentes Capaces Siguen Fallando
Hoy todos tenemos acceso a los mismos modelos. Los mismos
agentes de código, las mismas ventanas de contexto, el mismo
tool calling. Y aun así sigo viendo al mismo modelo producir
trabajo de calidad de producción en un repositorio y basura
con mucha confianza en otro.
La variable no es el modelo. La variable es todo lo que rodea
al modelo. A esa capa la llamo el harness, y hoy creo que la
ingeniería del harness es el verdadero trabajo cuando
trabajas con agentes de código.
La Brecha Entre Capacidad y Harness
Los benchmarks miden un modelo en aislamiento: un prompt, una
respuesta, un puntaje. La entrega real mide un sistema: el
modelo más las instrucciones que carga, las herramientas que
puede llamar, los tests que juzgan su salida y las puertas
que su trabajo tiene que pasar antes de que alguien lo
declare terminado.
Son cosas distintas, y en esa brecha viven la mayoría de las
fallas de agentes. Cuando un agente produce algo inutilizable
en mis repos, la autopsia casi nunca encuentra un problema de
capacidad. Encuentra un problema de harness:
- El contrato era ambiguo, así que el agente eligió una
interpretación en silencio y construyó muy bien la cosa
equivocada.
- La documentación que cargó estaba desactualizada, así que
reprodujo una convención que ya habíamos retirado.
- "Terminado" no tenía definición ejecutable, así que el
agente declaró éxito y nada podía contradecirlo.
Nada de eso mejora cuando salga el próximo modelo. Un modelo
más capaz ejecuta un contrato roto más rápido. Si tu harness
no puede atrapar una respuesta incorrecta, un agente más
inteligente solo te da respuestas incorrectas con mejor
prosa.
Los Loops Abiertos Producen Basura con Confianza
La forma default de usar agentes de código es un loop
abierto: describes la tarea, recibes el diff, lo revisas por
encima, lo mergeas. El agente afirma que terminó, y esa
afirmación es la única evidencia.
Un loop cerrado se ve diferente. Cada unidad de trabajo lleva
su propia prueba: un check que falla antes del cambio y pasa
después. No se le confía al agente la declaración de éxito.
Un comando sale con código 0 o no sale.
En mi propio workspace, cada unidad de trabajo planificada
viene con dos archivos junto a la descripción de la tarea: un
prompt que establece el contrato, y un archivo de validación
que lista los comandos exactos que deben salir con 0 antes de
que la unidad pueda marcarse como terminada. Test primero
donde el cambio es testeable, para observar la falla antes de
que exista el fix. Después, una revisión independiente,
ejecutada por un agente distinto al que escribió el código,
antes de mergear nada.
Esa estructura suena pesada hasta que ves lo que atrapa.
Atrapa el scope creep, porque el diff se juzga contra un
contrato escrito y no contra una sensación. Atrapa al agente
debilitando silenciosamente un test para que pase. Atrapa el
resumen de "todo funciona" que no sobrevive el contacto con
la suite de tests real. Los loops abiertos dejan pasar las
tres cosas, con mucha cortesía y mucha confianza.
El Repositorio Es el Sistema de Registro
Los agentes no tienen memoria entre sesiones. Todo el
contexto que necesitan hay que cargarlo, y lo que no está
escrito no existe. Esa restricción, que parece una debilidad,
forzó en mis repositorios una disciplina que debí tener desde
siempre: el repositorio mismo es el sistema de registro.
En concreto, eso significa:
- Un archivo de instrucciones canónico que todas las
herramientas leen, para que Claude Code y cualquier otro
runtime de agentes vean las mismas reglas. Sin forks por
herramienta que divergen con el tiempo.
- Los planes viven en el repo como archivos con estados
explícitos, no en la cabeza de alguien ni en el scroll de
un chat. Un agente puede retomar un epic a medio terminar y
saber exactamente qué unidades están terminadas, cuáles
están listas y qué prueba requiere cada una.
- Las decisiones viven en architecture decision records.
Cuando un agente pregunta "por qué está construido así", la
respuesta es un archivo, no arqueología.
- Los patrones prohibidos están escritos y se hacen cumplir
con greps en la revisión. Mis reglas prohíben fallbacks de
diccionario sobre esquemas tipados, comentarios de
arqueología y código defensivo para casos imposibles,
porque esos son exactamente los modos de falla que los
agentes reproducen a escala si dejas pasar una instancia.
El repositorio deja de ser solo el lugar donde vive el
código. Se convierte en la interfaz entre la intención humana
y la ejecución del agente. Cada mejora a esa interfaz
compone, porque cada sesión futura, humana o agente, la lee.
Lo Que Esto Cambia del Trabajo
La versión incómoda: si un agente con el harness correcto
puede producir un diff mergeable, entonces escribir el diff
no era la parte valiosa. La parte valiosa es todo lo que tuve
que construir para poder confiar en ese diff: el contrato, el
test que falla, la puerta de validación, la revisión
independiente, las reglas escritas.
El esfuerzo de ingeniería sube un nivel. Menos tiempo
tipeando implementación, más tiempo especificando qué
significa correcto y construyendo el loop que lo verifica.
Eso no es menos ingeniería. Es la misma disciplina que hizo
estándar el CI/CD y el code review, aplicada a un colaborador
que trabaja rápido, lo olvida todo y nunca se cansa de que lo
verifiquen.
Los agentes capaces ya están aquí. Los sistemas que
funcionan siguen siendo raros. La diferencia entre los dos se
construye, deliberadamente, un contrato y un loop de
verificación a la vez, y ese trabajo tiene nombre: harness
engineering.
Convertí el playbook completo en un curso, desde specs y
delegación hasta loops de verificación y continuidad de
contexto. Si quieres la versión profunda, empieza con el
curso de Harness Engineering.