O Archyl Harness: Agentes de Código Que Declaram o Próprio Trabalho Antes de Começar
Na semana passada eu escrevi sobre três agentes, três pull requests e um sistema incoerente. O post terminava com um exercício: pegue a última semana em que seu time mergeou mais de uma pull request escrita por agente, leia todas lado a lado, e pergunte o que, no seu setup atual, teria avisado você de que elas discordavam.
Fiz isso no nosso próprio repositório e a resposta foi nada. Não "o revisor acabou percebendo", não "a CI pegou metade". Nada, porque nenhum dos agentes jamais disse o que estava prestes a fazer. Cada um leu o repositório, escreveu código e abriu uma pull request. O primeiro momento em que uma pessoa conseguia ver dois deles trabalhando no mesmo serviço era a revisão, que é o último momento, e a essa altura os dois já tinham terminado de estar confiantes.
Então construímos o passo que faltava. O Archyl Harness saiu esta semana. Ele não é mais um agente de código. Ele fica acima dos agentes que você já roda, e faz cada um deles anunciar uma unidade de trabalho, contra a arquitetura documentada, antes de tocar em qualquer coisa.
Uma sessão de trabalho, por dentro
O loop tem quatro chamadas, expostas como tools MCP. Um agente planeja, abre uma sessão, trabalha mandando heartbeats, e fecha a sessão com o que de fato aconteceu.
Aqui está a segunda dessas chamadas, de uma sessão real no próprio projeto Archyl, encurtada:
▶ 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.
Quatro coisas aconteceram nessa única chamada, e nenhuma delas é coisa que um arquivo de regras consiga fazer.
A tarefa foi resolvida contra o modelo C4, então o agente recebeu a fatia de arquitetura que importa em vez dela inteira. Leases consultivos foram tomados sobre os elementos que ele está prestes a mudar, e é assim que o próximo agente fica sabendo deste aqui. O preflight gate devolveu um veredito. E o briefing trouxe as decisões que restringem o trabalho, mais o que o último agente que esteve aqui aprendeu do jeito difícil.
Essa última linha é memória, e ela merece um post próprio em vez de um parágrafo neste. A versão curta: as sessões deixam notas, convenções e armadilhas presas a elementos de arquitetura, e a sessão seguinte recebe tudo de volta automaticamente.
O gate tem três vereditos, e deny é o raro
O preflight gate é deliberadamente pequeno. Ele responde a uma pergunta, antes de o trabalho começar, com um veredito sobre o qual o agente consegue agir.
allow quer dizer que nenhuma outra sessão segura um lease sobre os seus elementos alvo e que nenhum guardrail de nível error se aplica à tarefa. Siga em frente.
warn é o comum, e vem com motivos. Outra sessão já está trabalhando num elemento que você está prestes a mudar, ou uma regra de conformidade com severidade error cobre essa tarefa. A string exata no primeiro caso é a que você viu acima: N target element(s) are being worked on by other active sessions — coordinate before changing them. O agente segue em frente, mas tem de tratar cada motivo listado, e os motivos dizem nomes.
deny só acontece quando uma sessão pede por isso. Passe exclusive: true e um conflito de lease para a sessão em vez de avisá-la. Essa é a flag para o trabalho que não pode correr junto com ninguém: uma migração de schema, uma mudança de contrato, um rename que toca em todos os chamadores. A sessão nunca chega a abrir, e o agente é orientado a reportar ao usuário em vez de contornar o problema.
Ser preciso sobre isso importa mais do que fazer o gate parecer esperto. deny não é um motor de políticas. Ele não lê o seu plano e o recusa por princípio. Ele se recusa a deixar dois agentes reivindicarem o mesmo elemento quando você disse que aquele elemento é exclusivo, e todo o resto é um aviso pelo qual o agente tem de responder.
O Guard vigia as escritas
A sessão cobre a intenção. O Guard cobre o que realmente é escrito.
Ele é um hook PreToolUse para o Claude Code, instalado junto com o plugin. Antes de o agente escrever ou editar um arquivo, o hook reconstrói o arquivo como ele ficaria depois da edição, manda para as regras de conformidade do seu projeto, e lê o veredito. Uma violação crítica bloqueia a escrita e devolve o motivo ao 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.
O agente lê aquilo, conserta o layering, e continua. Nenhuma pessoa foi interrompida, e a violação nunca chegou a uma branch.
Duas decisões de design merecem ser ditas com todas as letras. ARCHYL_GUARD_BLOCK controla o limiar: critical por padrão, high para bloquear mais, off para só avisar. E o hook é fail-open em todo lugar. Sem API key, sem rede, sem jq instalado, uma resposta lenta: a edição passa intocada. Uma ferramenta de governance capaz de quebrar a sessão de edição de alguém é desinstalada em uma semana, então ela não pode.
Fechando o loop
finish_work_session recebe um desfecho honesto: um resumo, as decisões que valem a pena registrar, os follow-ups que ficaram por fazer. Os leases são liberados, o resumo é fixado nos elementos que a sessão segurava, e se o trabalho mudou a arquitetura, createChangeRequest: true abre um Architecture Change Request em rascunho.
Essa é a parte que impede o modelo de derivar em silêncio. Um agente que reestrutura um serviço não sai editando o modelo C4 por baixo dos panos. Ele registra uma proposta, uma pessoa lê como a documentação deveria se atualizar, e o merge passa pela verificação de versão sobre a qual escrevemos na semana passada. Agentes propõem. Pessoas mergeiam. Não temos planos de tirar essa fronteira.
Por cima de tudo isso, a Fleet console no Agent Hub mostra ao vivo cada sessão da organização: quem está trabalhando, em quê, segurando quais elementos, atrás de qual gate, quão recente é o último heartbeat. Elementos sob um lease ativo também exibem um indicador de trabalho em andamento direto no diagrama C4, que é a visão em que "tem mais alguém aqui dentro" é de fato útil.
Construímos ele embaixo dele mesmo
O Harness foi construído por agentes trabalhando sob o Harness, num projeto Archyl que documenta o Archyl.
Isso não era uma demo. Era o único jeito de descobrir se o loop sobrevive ao contato com trabalho de verdade, e ele mudou o produto várias vezes. Sessões bateram em warn de verdade, em conflitos reais, porque dois agentes estavam genuinamente editando o mesmo container na mesma hora. A armadilha no transcript acima é uma memória que uma sessão escreveu depois de perder uma tarde com ela, e uma sessão posterior a recebeu de volta no briefing antes de tocar no mesmo arquivo. Três Architecture Change Requests saíram dessas sessões, cada um deles uma pessoa revisando como o modelo deveria se atualizar com o que um agente tinha acabado de fazer.
Também produziu correções menores, dessas que só o dogfooding traz à tona. O badge do gate no console renderizava um chip neutro para allow, até alguém apontar que um badge dizendo "não há nada errado" em toda linha é ruído. Agora ele não renderiza nada quando o veredito é allow sem motivos, e o raciocínio por trás disso foi guardado como convenção no projeto, para que o próximo agente que tocar naquele component não o adicione de volta prestativamente.
Instalar leva um comando
Da raiz do seu repositório:
curl -fsSL https://raw.githubusercontent.com/archyl-com/agent-skills/main/templates/setup.sh | bash
Ele pede o seu projeto e uma API key, e então escreve três coisas: um .mcp.json apontando para o servidor MCP do Archyl com ?profile=coding, um .archyl.json commitável que amarra o repositório ao projeto (a key fica no seu ambiente), e o loop do harness acrescentado ao CLAUDE.md e ao 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.
...
Depois /plugin marketplace add archyl-com/agent-skills e /plugin install archyl-developer@archyl-marketplace no Claude Code, que trazem o skill archyl-harness e o hook do Guard. A versão 0.7.0 do plugin está no ar.
?profile=coding é o detalhe pequeno que faz o resto funcionar. O servidor MCP do Archyl expõe 189 tools, que é o número certo para administrar uma arquitetura e o número errado para colocar na frente de um agente que está tentando adicionar rate limiting. O perfil de coding anuncia 16: orientação, contexto no escopo da tarefa, os quatro tools de sessão, memória, e as verificações de conformidade e de diff. Nada que edite o modelo diretamente, porque esse caminho passa pelos Change Requests. Nos nossos próprios testes, um agente que recebe o catálogo inteiro fica explorando ele. Um agente que recebe dezesseis tools segue o loop.
O que ele não faz
Leases são consultivos. Nada trava. Um lease diz ao segundo agente que o primeiro está lá dentro, no briefing dele, no console e no diagrama. Ele não o impede. Isso é deliberado por enquanto, porque um lock rígido sobre um modelo da sua arquitetura é um jeito muito eficaz de impedir seu time de trabalhar quando um agente morre no meio da sessão, mas você não deveria descrever leases para o seu time como exclusão mútua.
Um agente que nunca abre uma sessão é invisível. Toda garantia aqui começa com o agente chamando start_work_session. Nada no protocolo força essa chamada. O skill e o trecho no CLAUDE.md fazem dela o comportamento padrão; um agente determinado, ou um conectado sem o skill do harness, simplesmente escreve código do jeito que sempre escreveu. O hook do Guard é a única parte que dispara sem cooperação, e só no Claude Code.
deny só é tão bom quanto o que você escreveu. O gate lê as suas regras de conformidade e os seus leases. Um conjunto de regras vazio e um único agente produzem allow para sempre, o que é tecnicamente correto e completamente pouco informativo.
Planos são fundamentados, não corretos. plan_work é um plano de IA construído a partir do seu modelo C4, dos seus ADRs e dos guardrails, com um fallback determinístico que devolve a verdade de base ordenada quando não há provedor de IA configurado ou o modelo devolve algo inutilizável. Ele respeita a arquitetura documentada. Ele não sabe se a arquitetura documentada é uma boa ideia.
Um Change Request precisa de um autor conhecido. Sessões iniciadas com uma credencial que não está vinculada a um usuário não conseguem abrir um, e o finish_work_session diz isso na resposta em vez de falhar. Se a key do bot da sua CI tem escopo de organização, os resultados dele aterrissam como memória, mas não como proposta.
Por onde começar
Se você já roda agentes contra um projeto Archyl documentado, o comando de setup acima leva uns cinco minutos e a primeira sessão vai te dizer alguma coisa. Observe a Fleet console durante uma tarde em que dois agentes estejam rodando. O momento interessante é o primeiro warn, porque ele dá nome a uma colisão que antes ficava invisível até a revisão.
Se você ainda não tem uma arquitetura documentada, esse é o pré-requisito de verdade, e é o mesmo de sempre: o Harness arbitra usando o modelo, então um modelo vazio não arbitra nada.
O Harness faz parte do archyl: sessões de trabalho, o preflight gate, a Fleet console e a memória. O plugin, os skills e o hook do Guard e as GitHub Actions são open source. O setup completo está no guia do Harness. Leitura relacionada: muitos agentes, uma arquitetura, por que seus agentes têm um arquivo de regras e não um modelo, e o servidor MCP por trás disso.