El Archyl Harness: agentes de código que declaran su trabajo antes de empezar
La semana pasada escribí sobre tres agentes, tres pull requests y un sistema incoherente. El post terminaba con un ejercicio: coge la última semana en la que tu equipo mergeó más de una pull request escrita por un agente, léelas una al lado de la otra, y pregúntate qué, en tu setup actual, te habría dicho que no estaban de acuerdo.
Lo hice en nuestro propio repositorio y la respuesta fue nada. Ni "al final se dio cuenta quien revisaba", ni "la CI pilló la mitad". Nada, porque ninguno de los agentes dijo jamás qué estaba a punto de hacer. Cada uno leyó el repositorio, escribió código y abrió una pull request. El primer momento en el que una persona podía ver a dos de ellos trabajando sobre el mismo servicio era la revisión, que es el último momento, y para entonces los dos ya habían terminado de estar seguros.
Así que construimos el paso que faltaba. El Archyl Harness salió esta semana. No es otro agente de código. Se sitúa por encima de los agentes que ya ejecutas, y hace que cada uno de ellos anuncie una unidad de trabajo, contra la arquitectura documentada, antes de tocar nada.
Una sesión de trabajo, por dentro
El bucle tiene cuatro llamadas, expuestas como tools MCP. Un agente planifica, abre una sesión, trabaja mientras manda heartbeats, y cierra la sesión con lo que pasó de verdad.
Esta es la segunda de esas llamadas, de una sesión real sobre el propio proyecto Archyl, recortada:
▶ start_work_session(
task: "rank recalled memories by freshness so stale facts stop winning",
agentName: "claude-code/vincent")
# Harness Session
- **Session ID**: `24643fa6…`
- **Gate**: warn
- 1 target element(s) are being worked on by other active sessions — coordinate before changing them
- **Leased elements** (you are the announced worker on these):
- component `Harness Service`
- container `MCP Server`
- **Conflicts** (someone else is already working here):
- MCP Server — held by claude-code/memory-ui: render the memory graph with element clusters
**Protocol**: call `heartbeat_work_session` at least every 30 minutes while working,
and `finish_work_session` with a summary (and decisions worth recording) when done.
## Most relevant elements
- **Harness Service** (component) — `backend/internal/service/harness`
Work sessions, leases, preflight gate, element memory.
## Related decisions (respect these)
- ADR-5: Agents propose, humans merge [accepted]
## What previous sessions did here
- **MCP Server** [PITFALL] (claude-code/vincent, 1 day ago): every new ID argument
name must be added to idArgumentResolvers in authz.go, or the cross-org check
silently skips it.
En esa única llamada pasaron cuatro cosas, y ninguna de ellas es algo que pueda hacer un archivo de reglas.
La tarea se resolvió contra el modelo C4, así que el agente recibió la porción de arquitectura que importa en vez de toda ella. Se tomaron leases consultivos sobre los elementos que está a punto de cambiar, que es como el siguiente agente se entera de este. El preflight gate devolvió un veredicto. Y el briefing traía las decisiones que restringen el trabajo, además de lo que el último agente que estuvo aquí aprendió por las malas.
Esa última línea es memoria, y merece su propio post en vez de un párrafo en este. La versión corta: las sesiones dejan notas, convenciones y trampas enganchadas a elementos de arquitectura, y la siguiente sesión las recibe de vuelta automáticamente.
El gate tiene tres veredictos, y deny es el raro
El preflight gate es deliberadamente pequeño. Responde a una pregunta, antes de que empiece el trabajo, con un veredicto sobre el que el agente puede actuar.
allow significa que ninguna otra sesión tiene un lease sobre tus elementos objetivo y que ningún guardrail de nivel error aplica a la tarea. Adelante.
warn es el común, y viene con razones. Otra sesión ya está trabajando sobre un elemento que estás a punto de cambiar, o una regla de conformidad con severidad error cubre esta tarea. La cadena exacta en el primer caso es la que has visto arriba: N target element(s) are being worked on by other active sessions — coordinate before changing them. El agente sigue adelante, pero tiene que atender cada razón listada, y las razones dan nombres.
deny solo ocurre cuando una sesión lo pide. Pasa exclusive: true y un conflicto de lease detiene la sesión en vez de avisarla. Ese es el flag para el trabajo que no puede competir con nadie: una migración de esquema, un cambio de contrato, un rename que toca a todos los que llaman. La sesión no llega a abrirse, y al agente se le dice que reporte al usuario en vez de buscar una ruta alternativa.
Ser preciso con esto importa más que hacer que el gate suene ingenioso. deny no es un motor de políticas. No lee tu plan y lo rechaza por principios. Se niega a dejar que dos agentes reclamen el mismo elemento cuando tú has dicho que ese elemento es exclusivo, y todo lo demás es un aviso del que el agente tiene que responder.
El Guard vigila las escrituras
La sesión cubre la intención. El Guard cubre lo que se escribe de verdad.
Es un hook PreToolUse para Claude Code, instalado con el plugin. Antes de que el agente escriba o edite un archivo, el hook reconstruye el archivo tal y como quedaría después de la edición, lo manda a las reglas de conformidad de tu proyecto, y lee el veredicto. Una violación crítica bloquea la escritura y devuelve la razón al agente:
Archyl Guard: this change violates the project's architecture rules for
backend/internal/adapter/http/handlers/report.go:
- [critical] No direct database access from HTTP handlers — move the query
behind a service
Adjust the change to respect these rules, or ask the user whether to override them.
El agente lee eso, arregla el layering, y sigue. No se interrumpió a ninguna persona, y la violación nunca llegó a una rama.
Hay dos decisiones de diseño que vale la pena decir sin rodeos. ARCHYL_GUARD_BLOCK controla el umbral: critical por defecto, high para bloquear más, off para solo avisar. Y el hook es fail-open en todas partes. Sin API key, sin red, sin jq instalado, con una respuesta lenta: la edición sigue intacta. Una herramienta de governance capaz de romperle a alguien la sesión de edición se desinstala en una semana, así que no puede.
Cerrar el bucle
finish_work_session recibe un resultado honesto: un resumen, las decisiones que vale la pena registrar, los pendientes que quedaron sin hacer. Los leases se liberan, el resumen se fija a los elementos que la sesión tenía, y si el trabajo cambió la arquitectura, createChangeRequest: true abre un Architecture Change Request en borrador.
Esa es la parte que evita que el modelo derive en silencio. Un agente que reestructura un servicio no edita el modelo C4 por lo bajo. Presenta una propuesta, una persona lee cómo debería ponerse al día la documentación, y el merge pasa por la comprobación de versión sobre la que escribimos la semana pasada. Los agentes proponen. Las personas mergean. No tenemos pensado quitar esa frontera.
Por encima de todo esto, la Fleet console del Agent Hub muestra en vivo cada sesión de la organización: quién está trabajando, en qué, sujetando qué elementos, detrás de qué gate, cómo de fresco es su último heartbeat. Los elementos bajo un lease activo muestran además un indicador de trabajo en curso directamente en el diagrama C4, que es la vista donde "aquí dentro hay alguien más" resulta realmente útil.
Lo construimos debajo de sí mismo
El Harness lo construyeron agentes trabajando bajo el Harness, sobre un proyecto de Archyl que documenta Archyl.
Eso no era una demo. Era la única manera de averiguar si el bucle sobrevive al contacto con trabajo real, y cambió el producto varias veces. Hubo sesiones que dieron warn de verdad, sobre conflictos reales, porque dos agentes estaban editando genuinamente el mismo container a la misma hora. La trampa del transcript de arriba es una memoria que escribió una sesión después de perder una tarde con ella, y una sesión posterior la recibió de vuelta en su briefing antes de tocar el mismo archivo. De esas sesiones salieron tres Architecture Change Requests, cada uno una persona revisando cómo debería ponerse al día el modelo con lo que un agente acababa de hacer.
También produjo correcciones más pequeñas que solo aparecen haciendo dogfooding. El badge del gate en la consola solía renderizar un chip neutro para allow, hasta que alguien señaló que un badge que dice "no pasa nada" en cada fila es ruido. Ahora no renderiza nada en absoluto cuando el veredicto es allow sin razones, y el razonamiento detrás de eso se guardó como convención en el proyecto, para que el siguiente agente que toque ese component no lo vuelva a añadir con toda su buena intención.
Instalarlo es un solo comando
Desde la raíz de tu repositorio:
curl -fsSL https://raw.githubusercontent.com/archyl-com/agent-skills/main/templates/setup.sh | bash
Te pide tu proyecto y una API key, y luego escribe tres cosas: un .mcp.json apuntando al servidor MCP de Archyl con ?profile=coding, un .archyl.json commiteable que ata el repositorio al proyecto (la key se queda en tu entorno), y el bucle del harness añadido a CLAUDE.md y AGENTS.md:
# Architecture — Archyl Harness
This project's architecture is documented in Archyl. Work under the harness loop:
1. For any non-trivial task, call `plan_work` first — it returns an implementation
plan grounded in the documented architecture.
2. BEFORE changing code, call `start_work_session` (task + your agent name).
Read the briefing: gate verdict, leased elements, conflicts, decisions, guardrails.
...
Después, /plugin marketplace add archyl-com/agent-skills y /plugin install archyl-developer@archyl-marketplace en Claude Code, que trae el skill archyl-harness y el hook del Guard. La versión 0.7.0 del plugin ya está publicada.
?profile=coding es el pequeño detalle que hace que funcione todo lo demás. El servidor MCP de Archyl expone 189 tools, que es el número correcto para gestionar una arquitectura y el número equivocado para ponerle delante a un agente que está intentando añadir rate limiting. El perfil de coding anuncia 16: orientación, contexto acotado a la tarea, los cuatro tools de sesión, memoria, y las comprobaciones de conformidad y de diff. Nada que edite el modelo directamente, porque ese camino pasa por los Change Requests. En nuestras propias pruebas, un agente al que le das el catálogo completo se dedica a explorarlo. Un agente al que le das dieciséis tools sigue el bucle.
Lo que no hace
Los leases son consultivos. No bloquean nada. Un lease le dice al segundo agente que el primero está ahí dentro, en su briefing, en la consola y en el diagrama. No lo detiene. Eso es deliberado por ahora, porque un lock duro sobre un modelo de tu arquitectura es una forma muy eficaz de parar a tu equipo cuando un agente se muere a mitad de sesión, pero no deberías describirle los leases a tu equipo como exclusión mutua.
Un agente que nunca abre una sesión es invisible. Toda garantía de aquí empieza con que el agente llame a start_work_session. Nada en el protocolo fuerza esa llamada. El skill y el snippet de CLAUDE.md la convierten en el comportamiento por defecto; un agente decidido, o uno conectado sin el skill del harness, simplemente escribe código como lo ha hecho siempre. El hook del Guard es la única parte que se dispara sin cooperación, y solo en Claude Code.
deny es tan bueno como lo que hayas escrito. El gate lee tus reglas de conformidad y tus leases. Un conjunto de reglas vacío y un solo agente producen allow para siempre, que es técnicamente correcto y completamente poco informativo.
Los planes están fundamentados, no son correctos. plan_work es un plan de IA construido a partir de tu modelo C4, tus ADR y tus guardrails, con un fallback determinista que devuelve la verdad de base ordenada cuando no hay proveedor de IA configurado o el modelo devuelve algo inservible. Respeta la arquitectura documentada. No sabe si la arquitectura documentada es buena idea.
Un Change Request necesita un autor conocido. Las sesiones arrancadas con una credencial que no está ligada a un usuario no pueden abrir uno, y finish_work_session lo dice en su respuesta en lugar de fallar. Si la key de tu bot de CI tiene alcance de organización, sus resultados aterrizan como memoria pero no como propuesta.
Por dónde empezar
Si ya ejecutas agentes contra un proyecto de Archyl documentado, el comando de setup de arriba lleva unos cinco minutos y la primera sesión te dirá algo. Mira la Fleet console durante una tarde en la que haya dos agentes corriendo. El momento interesante es el primer warn, porque nombra una colisión que antes era invisible hasta la revisión.
Si todavía no tienes una arquitectura documentada, ese es el prerrequisito de verdad, y es el mismo de siempre: el Harness arbitra usando el modelo, así que un modelo vacío no arbitra nada.
El Harness es parte de archyl: sesiones de trabajo, el preflight gate, la Fleet console y la memoria. El plugin, los skills y el hook del Guard y las GitHub Actions son open source. La configuración completa está en la guía del Harness. Lectura relacionada: muchos agentes, una arquitectura, por qué tus agentes tienen un archivo de reglas y no un modelo, y el servidor MCP que hay detrás.