ekky, ou como desisti de me tornar um semideus
Introdução
Arre, estou farto de semideuses!
Onde é que há gente no mundo?Então sou só eu que é vil e errôneo nesta terra?
O discurso sobre IA na área de software tem dois polos separando um espectro. De um lado, temos pessoas que rejeitam a IA e sentem falta do código escrito à mão. Eu entendo, e ideologicamente estou mais perto delas do que este post vai fazer parecer1. Do outro, temos entusiastas tão fanáticos que conectaram agentes no WhatsApp para responder amigos e família quando lançou o OpenClaw.
No meio, semideuses prometem entregar 10x mais com o uso de IA sem terem escrito uma linha de código ou terem ciência dos fundamentos que embasam essa brincadeira chamada “computação” na qual estamos imersos. Alguns mortais, eu incluso, entendem coisa ou outra dos fundamentos e se perguntam se não estamos mais próximos do polo aceleracionista do que pensamos.
Por um tempo, eu tentei me tornar um dos semideuses. Durante alguns meses do fim de 2025, rodei cinco ou seis sessões do Claude Code por vez, cada uma em um terminal. Cheguei a aprender a usar window managers (à época, i3wm) para conseguir transitar entre os terminais de forma mais eficiente.
Entregava muito, atendia as expectativas do novo “10x engineer” de mercado, e no fim do dia nem sabia direito o que eu mesmo tinha entregado. Estava cognitivamente exausto demais para fazer alguma coisa a respeito.
Tinha entregue o controle do meu trabalho à LLM sem oferecer resistência nenhuma, pois não queria de forma alguma ficar para trás. Neste post, vou falar um pouco sobre o que mudou desde então e a construção do meu próprio harness com base nessas conclusões.
Focaremos mais no ideário e na trajetória que levou ao desenvolvimento dessa solução do que sobre a solução em si. Se você quer ler mais sobre a solução, tem uma página sobre esse projeto na aba /lab.
Como chegamos aqui
Eu orbitei grande parte da curva de adoção de IA nos últimos dois anos:
- Primeiro, cético - modelos como o GPT-4o me deixavam tranquilo, sem preocupações em relação ao meu emprego;
- Em meados de 2024, passei a ser usuário de Cursor e adotar LLMs apenas para fazer perguntas, sem gerar código, preferindo escrever o código eu mesmo;
- Ganhando confiança com o Cursor, passei a adotar o uso de “plan mode” e ter a IA gerando o código por mim, revisando cada linha que a LLM escrevia;
- No lançamento do Claude Opus 4.5, finalmente fui convencido a dar autonomia à IA (devido à força do modelo) e passei a trabalhar com spec-driven development.
À época, eu trabalhava como Sênior em um time de 3 pessoas onde eu tinha autonomia sobre a plataforma inteira e a direção técnica, então era natural que eu me dividisse em vários terminais:
- Um terminal para elaborar planejamentos de arquitetura a longo prazo para o nosso produto na época (por meio de RFCs);
- Um para elaborar specs com base nas RFCs que montei;
- Um para cada spec que estava executando por vez (aqui costumavam ser 2-3 terminais);
- Um para revisar o código (eu usava a própria IA para direcionar a minha revisão do código, pois era muito código gerado para revisar manualmente).
Acho que vale uma menção honrosa para uma parte importante da curva de adoção, que vi muitos adotarem mas não segui intencionalmente, que são os “agent swarms” - usar vários agentes para realizar uma única tarefa.
flowchart TD accTitle: Agent swarm accDescr: Um agente coordenador de estado delega a mesma tarefa a três subagentes: segurança, arquitetura e bugfixes. coord[Agente Coordenador de Estado] coord --> seg[Subagent Segurança] coord --> arq[Subagent Arquitetura] coord --> bug[Subagent Bugfixes]
Eu nunca fui um grande fã dessa ideia. Na minha visão, uma única spec bem definida é suficiente para focar em qualidade de arquitetura, segurança, corretude, etc. - isso molda bastante o formato da solução que uso hoje em dia. Isso é uma premissa difícil de provar, mas é o que a minha experiência tem embasado.
É importante notar que eu não sou contra ter agentes independentes - eu apenas creio que uma única tarefa deve ser feita por um único agente, e o corte da tarefa deve ser feito justamente para que um agente seja capaz de fazê-la sozinho.
Os problemas com essa abordagem
Vamos assumir que chegamos em um ponto em que seja possível usar as técnicas de context engineering e prompt engineering para que o modelo faça um trabalho satisfatório. A LLM se comporta como um “solver” - dada uma spec e um conjunto de restrições, ela traz a melhor solução possível2.
O modelo dava conta do trabalho que era passado pra ele, quem não dava conta de sustentar a atenção era eu. O excesso de contextos fazia com que eu entregasse um trabalho bom o suficiente em todas as frentes, mas sem profundidade sobre nenhuma. Semanas depois, eu encontrava problemas óbvios de estilo de código, como funções toCents duplicadas no back-end em serviços diferentes, e me perguntava a razão pela qual não percebi no momento em que a duplicação aconteceu.
Creio que o único motivo pelo qual não enfrentei problemas de arquitetura é por prezar muito por ela nas RFCs - eu não escrevia uma spec sem antes ter escrito uma RFC - e cortar absolutamente todas as specs partindo de uma RFC ou design document equivalente (ex: TDD).
Eu ainda acredito na revisão humana de código, mesmo que seja mais veloz / menos minuciosa, pois a RFC protege o macro, mas não consegue proteger o micro (como a toCents mencionada anteriormente). Quanto mais sutil o problema, maior a chance de um agente de revisão alucinar e resolver o problema errado.
Pra mim, o problema deixou de ser “como entregar mais usando IA” e passou a ser “onde colocar, e onde deixar de colocar, a minha atenção”. Com cinco terminais, ela ficava intercalada: um pouco em cada frente, o dia inteiro, sem profundidade em nenhuma. O que eu queria era o contrário, uma atenção em lote: despachar as tarefas, fazer outras atividades de Engenharia e depois sentar para julgar o resultado de uma vez só.
O loop atual
Atualmente, meu fluxo de trabalho para execução de tasks3 é quase análogo ao fluxo dos vários terminais: a diferença é que eu não estou mais presente em metade das ações. Os vários terminais para revisar e executar spec foram substituídos por um único terminal em que eu defino a direção técnica, seguido por um terminal em que eu reviso os resultados (em geral, tenho cerca de 2 a 3h para fazer outras coisas entre esses dois momentos4).
flowchart LR accTitle: O loop atual accDescr: Definição da direção técnica, por mim; corte em tasks, por mim com IA; execução das tasks, pela IA via ekky; revisão das tasks, por mim. dir["Definição da direção técnica<span class='who'>eu :)</span>"]:::eu cut["Corte em tasks<span class='who'>eu + IA</span>"]:::par exe["Elaboração das specs + Execução das tasks<span class='who'>IA, via ekky</span>"] rev["Revisão das tasks<span class='who'>eu</span>"]:::eu dir --> cut --> exe --> rev
Isso não desvia muito do fluxo de SDD regular que você encontrará pesquisando sobre spec-driven development internet afora. O que difere é a minha visão sobre context engineering e sobre o papel do humano nesse fluxo.
O “ekky” é o harness que eu construí para que os agentes executem as tasks. O nome vem de ekkyklema5, a plataforma com rodas que o teatro grego usava para trazer ao palco o que tinha acontecido nos bastidores. Eu não vejo a IA trabalhar, eu apenas vejo o resultado que ela me traz.
Os agentes não possuem acesso para fazer push no git. Tudo o que eles conhecem sobre a task é a sua definição: um markdown curto com três seções - o que significa dizer que a task está pronta, as decisões que já tomei e as restrições do que não pode acontecer. A partir dele, o agente escreve a própria spec e executa. Eles não sabem como pegar contexto sobre regras de negócio ou nada parecido - tudo que eles conhecem é o repo em cima do qual a tarefa será feita.
Isso vai na contramão da maioria das dicas de context engineering que você verá na internet, que tentam encontrar a melhor forma de fornecer um contexto de qualidade, usar RAG, LLM Wiki ou similares.
RAG e LLM Wikis resolvem o problema de dar informação ao agente. O problema que eu quero resolver é outro: fazer a minha intenção chegar até ele. A task é curta de propósito. Ela perde informação, mas eu escolho o que importa para a execução: o que significa estar pronto, o que eu já decidi e o que não pode acontecer. O resto o agente encontra sozinho no repositório. Na minha visão, informação não é o principal gargalo na geração de código6. Escrever essa intenção é, pra mim, a principal função de um engenheiro de software. Aposto que vai continuar sendo, até o dia em que um agente conseguir gerar a própria intenção a partir das prioridades do negócio.
Se o problema é de intenção (a task foi mal definida ou o agente entendeu errado o que eu queria), eu escrevo uma nota de retrabalho e o agente começa de novo, do zero, com a nota anexada. Retomar a sessão antiga seria retomar os mal-entendidos dela junto. Se o problema é pequeno, do tipo toCents duplicada, eu mesmo corrijo na branch e faço o rebase nas seguintes. O macro volta pra IA; o micro fica comigo (sim, o micro eu faço com IA também, mas dessa vez faço parte do loop).
Na prática, esse fluxo tem me permitido finalizar a etapa de geração de código de um “épico” em 2-3h. Um exemplo específico no qual trabalhei recentemente foi a fase de coleta de dados de Open Finance por meio de um integrador terceiro dentro de uma API em Nest.js, parte de um design document muito maior que detalhava outras fases e funcionalidades necessárias para completar a integração.
Nesse caso, eram 6 tasks em cadeia. A geração de código levou 2-3h; a revisão, 3-4h: uns 40 minutos de código, o resto do meu próprio processo de QA7. Houve 2 duplicações, que corrigi manualmente. Nesse épico, em nenhum momento o agente entregou uma solução plausível que não fosse a que eu queria, e eu atribuo isso mais à definição da task do que ao modelo. Pode ser que isso aconteça no futuro e eu mude a forma com que o meu harness funciona, mas por enquanto, me serve bem.
Na minha visão, a revisão também ficou mais eficiente pois consigo me concentrar em revisar um único tópico em uma levada só, sem pagar os custos cognitivos pela troca de contexto.
Considerações finais
Os números desse épico contam uma história que eu já esperava ouvir: gerar o código é rápido e plausível, o problema continua sendo a revisão. A diferença é que, com esse harness, eu consigo focar na revisão sabendo que existem outras partes do meu trabalho sendo feitas por baixo dos panos. Eu não acho que isso seja um defeito do fluxo - a IA fica com o volume de execução, eu fico com o julgamento das decisões a serem tomadas. Pelo menos por enquanto, é onde eu acho que um engenheiro de software deveria estar.
Voltando para a metáfora do teatro grego: os gregos tinham duas máquinas. A mechane baixava um deus no palco para resolver o enredo, a origem do conceito deus ex machina. O ekkyklema só trazia para fora o que tinha acontecido nos bastidores, e deixava a plateia julgar e trazer seus palpites. Rejeito, e seguirei rejeitando, todas as perspectivas do hype da IA que prometam uma mechane, e aposto cada vez mais fichas no uso de IA nos bastidores para trazer um trabalho agradável aos que trabalham comigo.
Não sei se isso me tira da lista dos vis e errôneos. Ainda não sou um semideus, não tenho um time de agentes trabalhando enquanto eu durmo, mas pelo menos agora consigo me manter focado por tempo suficiente para saber o que entreguei.
- Estou ciente dos custos ambientais e das consequências sociais da adoção desenfreada de IA e, sinceramente, sinto falta de vários aspectos da nossa sociedade pré-IA. Uso mesmo assim porque o gap entre um dev que a usa com maestria e um dev que não usa é, no caso médio, um abismo.↩
- Sim, essa é uma premissa difícil de se provar e de se engolir. Eu mesmo não creio nela. No entanto, para montar o nosso modelo mental desse harness, é mais fácil pensar desta forma.↩
- O trabalho de um engenheiro de software sênior vai bem além da execução de tasks. Tenho muitas opiniões sobre o uso de IA para definição de direção técnica e outras responsabilidades do trabalho de um dev, mas essa parte vai ficar para outros artigos.↩
- Poderia ser mais rápido se eu otimizasse o CI dos nossos repos (o agente roda o fluxo localmente para verificar a corretude do que acabou de escrever), mas como a maioria dos projetos de mundo real, ainda não consegui parar para fazer isso.↩
- Por mais que eu goste muito de mitologia grega (tenho lido Os Hinos Órficos no período em que esse artigo foi escrito), a ideia foi do Claude. Eu acho muito maneiro quando o Claude consegue me trazer esse tipo de referência :)↩
- Existem várias coisas importantes que um repo precisa ter para que isso seja verdade (regras, guardrails, documentação) - aqui, aceitamos como uma premissa de que esses pré-requisitos estejam sólidos.↩
- Eu não gosto de fazer QA, meus próximos artigos provavelmente vão falar sobre tentativas de automatizar esse processo…↩