- Compartilha uma metodologia concreta para manter projetos com dezenas de milhares de linhas com baixa taxa de defeitos por meio de um fluxo de trabalho multiagente de arquiteto-desenvolvedor-revisor no desenvolvimento de software com LLMs
- Eu achava que me interessava mais por programar, mas na verdade eu me interessava mais por construir coisas, e agora que os LLMs ficaram bons em codar posso me concentrar nisso
- Mais do que a habilidade de escrever código, as skills de engenharia de projetar a arquitetura do sistema e tomar as decisões certas ficaram muito mais importantes
- Misturar modelos diferentes aumenta a qualidade do code review, separando por papel os pontos fortes e fracos de cada modelo
- O autor publica a sessão completa real de adição de uma funcionalidade de e-mail e registra em detalhes o processo de colaboração com LLMs liderado por humanos, das decisões de arquitetura ao QA
Vantagens de construir com LLMs
- Eu achava que gostava de programação, mas na prática gostava mesmo era de construir coisas; agora que os LLMs programam bem, estou criando sem parar
- Por volta do lançamento do Codex 5.2, e mais recentemente com o Opus 4.6, passou a ser possível escrever software com taxa de defeitos muito baixa. Ela pode ser significativamente menor do que quando eu programo tudo manualmente
- Antes, depois de 2 ou 3 dias de trabalho, o código entrava num estado impossível de manter; hoje consigo trabalhar por semanas seguidas e fazer crescer com estabilidade dezenas de milhares de linhas de código úteis
- As skills de engenharia não ficaram inúteis, elas mudaram de lugar: em vez da capacidade de escrever o código corretamente, o que importa é o julgamento para arquitetar o sistema do jeito certo e torná-lo utilizável
- Em projetos cujo stack eu conheço bem (por exemplo, backend), dezenas de milhares de SLoC não são um problema; mas em tecnologias que conheço menos (por exemplo, app mobile), o código ainda vira bagunça por causa do acúmulo de escolhas erradas
- No começo dos LLMs (depois do davinci), era preciso revisar cada linha de código; nas gerações seguintes, bastava revisar por função; hoje, a tendência é só verificar no nível da arquitetura inteira. No ano que vem, talvez nem isso seja necessário
Projetos feitos desse jeito
- Stavrobot: um assistente pessoal com LLM focado em segurança. Faz gerenciamento de calendário, decide disponibilidade, pesquisa, escreve código para se expandir, envia lembretes, gerencia tarefas domésticas de forma autônoma etc. O valor principal não está em uma única killer feature, mas em eliminar milhares de pequenos incômodos
- Middle: um pequeno dispositivo em forma de pingente que grava memos de voz, converte em texto e envia por webhook. O essencial é estar sempre à mão e poder ser usado sem fricção
- Sleight of Hand: um projeto artístico de relógio de parede que tic-taqueia de forma irregular em segundos, mas continua sempre exato em minutos. Oferece vários modos, como ticks variáveis de 500ms a 1500ms, mudanças de velocidade difíceis de perceber seguidas de paradas aleatórias, corrida em velocidade dupla e espera de 30 segundos, entre outros
- Pine Town: um canvas multiplayer infinito, um projeto interativo de pradaria em que cada pessoa recebe um pequeno terreno para desenhar
- Todos esses projetos foram feitos com LLMs, e eu nunca li a maior parte do código, mas conheço bem a arquitetura e o funcionamento interno de cada projeto
Ferramenta de harness
- Estou usando o OpenCode como harness, e também tive uma boa experiência com o Pi
- Dois requisitos essenciais para um harness:
- Poder usar vários modelos de diferentes empresas: a maioria dos harnesses first-party (Claude Code, Codex CLI, Gemini CLI) só suporta os próprios modelos, então não atende a esse requisito
- Permitir que agentes customizados chamem uns aos outros de forma autônoma
Por que usar vários modelos
- Dá para pensar em um modelo específico como se fosse uma pessoa; mesmo reiniciando o contexto, ele tende a manter as mesmas opiniões, pontos fortes e fracos
- Pedir a um modelo para revisar o código que ele mesmo escreveu é quase inútil, porque ele tende a concordar consigo próprio; mas quando o review é feito por outro modelo, a qualidade melhora muito
- No momento, o Codex 5.4 é minucioso e exigente, então é bom para review; o Opus 4.6 costuma bater bem com as decisões que eu tomaria; e o Gemini 3 Flash às vezes propõe soluções que os outros modelos deixaram passar
- Para obter o melhor resultado, é preciso misturar todos os modelos
Fluxo de trabalho: arquiteto → desenvolvedor → revisor
- O fluxo é composto por arquiteto, desenvolvedor e 1 a 3 revisores. Eles são configurados como agentes do OpenCode (arquivos de skill)
- Três razões para usar múltiplos agentes:
- Modelos caros (Opus) ficam com o planejamento, e modelos baratos (Sonnet) com a escrita de código, economizando tokens
- Fazer reviews com modelos diferentes permite capturar problemas diferentes
- Dá para fazer separação de permissões por papel (por exemplo, somente leitura vs. permissão de escrita)
- Usar dois agentes com o mesmo modelo e as mesmas permissões não muda muita coisa; é como uma pessoa usando chapéus diferentes
- Os arquivos de skill são escritos manualmente. Se você pedir para um LLM escrever as skills, é como pedir para alguém escrever “como se tornar um ótimo engenheiro”, devolver esse texto e dizer “agora seja ótimo”
Papel do arquiteto
- O arquiteto (hoje, Claude Opus 4.6) é o único agente com quem eu converso diretamente e deve ser o modelo mais forte
- Eu apresento um objetivo de funcionalidade ou correção de bug bem específico e passo até 30 minutos conversando até fechar objetivos, restrições e trade-offs
- O resultado é um plano bem de baixo nível, no nível de arquivos individuais e funções
- Não é só prompting; é um processo de formar o plano com ajuda do LLM. Quando ele está errado ou propõe algo diferente do que eu faria, eu corrijo bastante, e essa é a principal contribuição para tornar o projeto “meu”
- Ele é configurado para não começar a implementar até eu dizer explicitamente a palavra "approved". Alguns modelos tendem a sair implementando cedo demais quando acham que já entenderam
- Depois da aprovação, o arquiteto divide o trabalho em tarefas, registra tudo em detalhes em um arquivo de plano e chama o desenvolvedor
Papel do desenvolvedor
- O desenvolvedor pode usar um modelo mais fraco e mais eficiente em tokens (Sonnet 4.6)
- Como o plano deixa pouco espaço para discricionariedade, o papel é estritamente implementar as mudanças previstas no plano
- Quando termina a implementação, ele chama os revisores
Papel do revisor
- Cada revisor analisa e critica de forma independente o plano e o diff
- O Codex é sempre usado no mínimo; às vezes entra o Gemini, e em projetos importantes entra também o Opus
- O feedback volta para o desenvolvedor e, quando há divergência entre revisores, o caso é escalado para o arquiteto
- O Opus é ótimo em escolher o feedback certo e às vezes ignora comentários excessivamente exigentes cuja chance de virarem problema real é baixa em relação ao custo de implementação
Abordagem geral e modos de falha
- Com esse método, eu entendo todas as escolhas acima do nível de função e uso esse conhecimento no trabalho posterior
- Quando o LLM tem um ponto cego e deixa passar algum elemento do codebase, se eu disser “você deve usar Y”, ele passa a perceber a existência de Y e muda para uma abordagem melhor
- Quando não conheço bem uma tecnologia, posso deixar passar decisões erradas do LLM, e então decisões erradas se acumulam até o projeto chegar a um estado sem solução
- Um padrão clássico de falha é repetir “o código não está funcionando”; o LLM responde “entendido! vou corrigir” e acaba piorando ainda mais
- Por isso, mesmo quando não domino uma tecnologia, tento entender o máximo possível já na fase de planejamento
Sessão real: adicionando suporte a e-mail no Stavrobot
- O autor publica a transcrição real comentada da sessão; as chamadas de ferramenta e as partes prolixas foram omitidas, mas a conversa e o processo de decisão foram mantidos como são
- Conversa inicial: apresentação do objetivo em alto nível ("quero adicionar suporte a e-mail a este bot") → o LLM lê o código, entende o padrão atual (webhook de entrada → enqueueMessage → processamento por LLM → resposta) e faz perguntas de design
- Método de entrada (polling IMAP, webhook, servidor SMTP), método de saída, se deve ser bidirecional, arquitetura (container separado vs. in-process), tratamento de e-mail HTML, rastreamento de threads, anexos etc.
- Decisões de design: entrada via webhook do Cloudflare Email Worker, saída via cliente SMTP, conversa totalmente bidirecional, processamento in-process, conversão para Markdown, tratamento como e-mails independentes e suporte a anexos
- Proposta detalhada de design do LLM: apresenta 7 preocupações com soluções concretas, incluindo parsing MIME (usando
mailparser), autenticação do webhook (segredo compartilhado), necessidade de assunto na saída, tratamento de e-mails apenas em HTML, identidade do endereço From, tratamento de e-mails encaminhados e anexos de saída
- Propõe simplificar o payload do Worker para
{ from, to, raw } e fazer o parsing do lado do servidor
- Organiza a estrutura de config, os fluxos de entrada/saída, a lista de arquivos a modificar e os itens explicitamente fora de escopo (YAGNI)
- Refinamento do plano: o humano aponta itens que faltavam, como atualizar
README.md e config.example.toml e remover a validação E.164 da página de allowlist de e-mail → o LLM incorpora tudo
- Divisão em 6 tarefas: config/dependências, allowlist, UI/validação de backend da allowlist, e-mail de entrada, e-mail de saída, README/testes
- Melhoria adicional: surge a ideia de tornar os campos SMTP opcionais, para que o e-mail de entrada funcione mesmo sem configuração SMTP → implementado
- Bug encontrado no QA: as mensagens eram descartadas porque o e-mail do owner não estava registrado → a causa era que
seedOwnerInterlocutor não incluía o canal de e-mail → corrigido
- Sugestão de melhoria de código: refatorar os blocos
if hardcoded por canal para iterar sobre uma lista compartilhada de canais. Depois de discutir o caso especial de conversão numérica do Telegram, decidiu-se aplicar o loop apenas em seedOwnerInterlocutor e manter getOwnerIdentities, já que a diferença de tipos ali é essencial
- Allowlist de e-mail com wildcard: foi adicionado suporte a wildcards no nível de domínio, como
*@example.com. Isso era necessário para um caso de uso real com endereços de e-mail descartáveis
- Consideração de segurança: para evitar ataques como
"me@mydomain.com"@evildomain.com, o * é convertido para [^@]*, de modo que não possa atravessar o limite do @
- Também há suporte a wildcards parciais, como
myusername+*@gmail.com
- O humano aponta que, ao usar regex, é preciso escapar todos os outros caracteres do endereço de e-mail
- Foi confirmado que os wildcards funcionam tanto no campo de owner quanto na allowlist, usando a mesma função helper
matchesEmailEntry
- A implementação da funcionalidade inteira levou cerca de 1 hora
Epílogo
- Não é um setup absurdamente extravagante, mas funciona muito bem, e o autor está satisfeito com a confiabilidade do processo
- O Stavrobot está rodando 24/7 há quase um mês e se mostrou muito estável
9 comentários
Assim como, há mais de 20 anos, a popularização dos editores web e dos blogs de produção em massa gerou uma enxurrada de páginas pessoais e posts que ninguém via, estamos vendo algo parecido na era da IA. Ainda assim, criar apps customizados e compartilhar esse processo ou rotina é, sem dúvida, um excelente e valioso patrimônio. Pessoalmente, acho que este não é um momento para fazer apps ou serviços lucrativos com IA, mas sim para criar com facilidade ferramentas customizadas de que eu preciso e, assim, aumentar a produtividade.
Na verdade, acho que com humanos também deve ser assim. Não seria justamente por isso que os humanos precisam buscar diversidade...
Como é um modelo de linguagem, faz sentido que um modelo caro fique responsável pelo planejamento.
> O modelo caro (Opus) é usado para planejamento, e o modelo barato (Sonnet) para escrever código, economizando tokens
Muita gente costuma fazer o contrário, usando o Sonnet para planejar e o Opus para implementar o código, mas aqui é o inverso.
Também estou colocando o opus e o codex para fazer esse vai e vem com o planejamento.
Deixo o opus cuidar da programação, e faço outra instância do opus e o codex cuidarem da revisão de código.
O que sinto fazendo isso é que, seja IA ou gente, parece que ambos são muito bons em apontar os erros dos outros...
Na configuração padrão do Oh my opencode, o planejamento é feito pelo opus, enquanto a implementação fica a cargo de um modelo mais leve.
Ao meu redor, o pessoal costuma fazer o planejamento/arquitetura com o Sonnet e escrever o código com o GLM-5..
Eu também faço o planejamento com o Sonnet e a implementação do código com o Opus, mas talvez o método do autor seja mais eficiente.
Eu também planejo com o Opus, faço as revisões no Codex high e rodo a codificação de fato no sonet ou no codex medium.