Como montei uma fábrica de agentes que entrega código enquanto eu durmo
182 PRs mergeadas em 10 dias, a maior parte enquanto eu dormia ou estava com a família. A arquitetura importa menos que a disciplina em volta dela. Aqui está o que fez funcionar.
A gente passou da fase de hype dos assistentes de código com IA. Copilot, autocomplete estilo Cursor, geração de código por chat. A maioria dos times já experimentou. Uns tiraram valor real, outros não.
O próximo passo é a parte que pouca gente comenta. Agentes que trabalham de forma autônoma e tocam o processo do ticket aberto até a PR mergeada, sem humano no meio. Empresas grandes como Stripe e Spotify já estão investindo nessa virada.
Venho rodando um setup desses na IGNIO há dez dias. 182 PRs mergeadas, 206 issues fechadas. A maior parte enviada enquanto eu dormia ou estava com a família. O write-up técnico da arquitetura está no deep dive do Three-Body Agent. Este texto é sobre os princípios que fizeram funcionar, porque a arquitetura que você escolhe importa menos que a disciplina que você coloca em volta dela.
Mantém o setup chato
O setup é deliberadamente cru. Cron job dispara o agente no horário. Um arquivo markdown de regras define como cada agente se comporta. Uma CLI de code agent faz o trabalho real. Nenhum framework custom envolvendo o processo, nenhum harness elaborado, nenhuma config de doze mil linhas tentando cobrir cada caso.
A simplicidade é a estratégia. Toda geração de modelo muda o que o agente consegue fazer, e setup complexo vira peso morto no segundo em que aparece uma ferramenta melhor. Time que montou uma estrutura elaborada em volta do GPT-4 viu tudo virar legado no dia que saiu o Claude Code com tool use nativo. Quanto mais simples o sistema, mais rápido você troca o motor sem reconstruir o carro. Os padrões que importam acabam absorvidos pelas ferramentas oficiais. O que sobrevive a longo prazo é a arquitetura em volta do agente, não os hacks dentro dele.
Disciplina de contexto
O instinto na hora de montar um agente é dar tudo para ele. Codebase inteiro, toda a doc, descrição da issue, histórico da conversa, PRs relacionadas. A intuição é que mais contexto entrega resultado melhor. Na prática é o contrário. Quanto mais você joga no agente, pior ele rende.
O prompt tem que ser cirúrgico. Título de issue claro, descrição focada, arquivos relevantes, regras que governam o comportamento. Esse é o payload inteiro.
É por isso que quebrar trabalho em issue atômica importa. Um ticket pedindo para “melhorar o fluxo de transação” é terrível para o agente: vago, multi-arquivo, exige julgamento, sem ponto de parada claro. O mesmo problema reformulado como “preferências de email defaultam para false quando os tiers de assinatura são ignorados, fazendo lembretes silenciosamente não saírem” dá ao agente um alvo que cabe na janela de contexto sem distração. Tickets menores produzem menos poluição de contexto, menos conexão alucinada e taxa de acerto maior na primeira tentativa.
O princípio central: separa pesquisa de execução. Você decide o que construir e como deve funcionar. O agente constrói. Se você se pega explicando o problema e a solução no mesmo prompt, já fez metade do trabalho sozinho.
“Pronto” tem que ser verificável
Toda execução de agente precisa de uma condição de parada explícita que o sistema verifica sozinho. Uma tarefa está pronta quando os testes passam, o CI está verde e a PR está aberta com uma descrição explicando o raciocínio. Qualquer coisa menos é o agente cantando vitória.
Sem uma saída binária, o agente deriva. Abre PR com stub que compila mas explode no segundo em que um usuário real toca. Vi isso no começo: PRs passando no lint mas com zero cobertura de comportamento, parecendo prontas quando não estavam. Tornar o teste obrigatório resolveu de vez. Se os testes não provam que o comportamento mudou, o agente continua trabalhando. Se o CI falha, o ticket fica fora da fila de review. Não tem espaço para “parece certo”.
Sessão curta em vez de longa
Cada execução de agente ganha sessão nova, amarrada numa issue e numa branch. Quando o trabalho termina, a sessão morre. O próximo ciclo de cron começa limpo.
Evito sessão longa. Ela acumula contexto do trabalho anterior e começa a alucinar conexão que não existe. O agente referencia uma variável de um arquivo que editou três horas atrás e que já foi rebaseado, ou aplica padrão de um ticket sem relação. Quanto mais longa a execução, mais contexto fantasma vaza para saída. Aprendi isso num debug doloroso: agente rodando duas horas produzia código pior do que agente terminando em trinta minutos, só porque tinha tempo a mais para derivar.
Code review adversarial
Antes do Implementer empurrar uma PR, ele roda um self-review por três agentes com incentivos conflitantes. Esse padrão está ganhando tração no espaço de coding agente, e está enraizado na observação de que LLM é inerentemente bajulador. Quer concordar com você. Em vez de combater isso, você desenha um sistema onde o desejo de cada agente de agradar trabalha a seu favor porque eles estão tentando agradar mestres diferentes.
O Enthusiast é caçador de bug hiper-agressivo. Ganha pontos por cada problema que encontra, escalado por severidade. Produz uma lista longa de problemas em potencial, reais e especulativos, porque quer maximizar pontuação. Aqui o exagero é o ponto: rede ampla.
O Adversary pega a lista e tenta refutar cada item. Pontos por refutação bem-sucedida, penalidade pesada por descartar um problema real. Esse risco assimétrico deixa ele agressivo contra alegação fraca e cauteloso contra qualquer coisa legítima.
O Referee avalia os dois lados sem viés. Lê o código, lê os argumentos e dá um veredito: bug real, falso positivo, ou vale anotar. Ele é recompensado por precisão, então não tem incentivo para ficar do lado de ninguém.
Rodar isso em produção pega problema que só o CI deixaria passar. Brecha de type safety onde um cast engole um erro, edge case em handling assíncrono, race condition em processamento de fila. Os bugs que normalmente só aparecem em produção se você tiver azar, pegos antes do código sair da branch.
Regras são o sistema operacional
Toda vez que o agente faz algo errado, eu adiciono uma regra. O arquivo de regras é um documento vivo que cresce a cada erro. O mesmo erro nunca acontece duas vezes.
A lista parece assim em qualquer repo meu:
- Bate com padrão existente.
- Sem dependência nova sem justificativa.
- Escreve teste para toda mudança de comportamento.
- Documenta o porquê, não só o quê.
Cada linha existe porque um agente tomou uma decisão ruim que eu tive que consertar na mão. Com o tempo o arquivo vira a melhor doc que o projeto tem, não porque alguém sentou para escrever doc, mas porque cada lição foi capturada em tempo real como resposta direta a uma falha.
Regras se acumulam e em algum momento começam a se contradizer. “Mantém simples” e “adiciona tratamento de erro completo” puxam em direções opostas. O agente tenta agradar os dois e produz código super-engenheirado tratando erros que ninguém vai encontrar. Então de tempos em tempos você consolida. Remove o obsoleto. Funde sobreposição. Refatora as regras como você refatoraria código.
Você é dono do resultado
Não assume que o agente vai magicamente se adaptar ao seu codebase. Ele não vai ler sua cabeça, inferir suas preferências arquiteturais ou entender seu contexto de negócio sem orientação explícita. Cada atalho que você toma no setup custa dez vezes mais em limpeza depois.
O agente escreve o código, mas você é dono do produto. Revisa as PRs quando precisa. Abre follow-up quando a execução perdeu o alvo. Você ainda precisa entender as decisões arquiteturais e manter o modelo mental geral. O agente é a força de trabalho. Você é o tech lead.
A tecnologia é cedo. Não é perfeita. Mas já está mudando como eu construo, e o próximo ano vai ser mais barulhento que o último.