Como Construí a OMLA Dirigindo Agentes de IA em Vez de Escrever o Código

Publicado em
11 julho 2026
Por
Jacob Lloyd — escrito com ajuda de IA, depois do projeto
Tempo de leitura
11 min de leitura

Em termos simples: A história real de como uma pessoa, sem equipe de programação, dirigiu assistentes de IA para construir uma plataforma real de licenciamento online para uma organização sem fins lucrativos. O texto explica o método de trabalho: planos escritos e claros, camadas de checagem dupla, e uma regra de que nada vai ao ar sem aprovação humana. Um roteiro prático para construir software sério com ajuda de IA.

Aqui está o loop exato que usei para fazer agentes de IA construírem a OMLA, o backend de licenciamento de royalties de uma organização sem fins lucrativos, quase sozinho. Roube o processo. O backend pronto é só a prova de que funciona.

resumo

  • O que é: o fluxo de trabalho que fez o Claude Code e um enxame de agentes de IA locais construírem um backend real para uma organização sem fins lucrativos, comigo como arquiteto e porteiro, não digitador.
  • Quanto custa: basicamente nada de novo. Uma assinatura de agente de programação, talvez uma GPU sobrando para segundas opiniões. O custo de verdade é o seu próprio tempo de revisão.
  • O que você precisa: um agente de programação, especificações escritas de verdade em vez de "feeling", e uma regra rígida de que nada é publicado até um humano digitar a palavra.
  • O que você ganha: um backend funcionando com rastro documental. Auditorias em camadas, testes contra uma stack local real, e um script de deploy que se recusa a publicar sem um "GO" humano.

O que você ganha

Antes de qualquer tutorial, aqui está o que saiu do outro lado: OMLA, a Open Model Licensing Association. Um backend de licenciamento de royalties e um site público para modelos de IA abertos.

O quêO resultado
StatusOrganizando-se como entidade sem fins lucrativos em Washington, 501(c)(3) pendente. O site traz o selo "Beta 0.9.0" de propósito.
O acordoGratuito para uso pessoal, de pesquisa e educacional. Uso comercial deve 30% do que for maior: a receita atribuível ou o custo de rodar o modelo.
Banco de dados12 tabelas centrais, Postgres 17 no Supabase, segurança em nível de linha (RLS) em tudo, cálculos monetários em centavos inteiros (nunca floats)
IdentidadeAssinaturas híbridas ed25519 + ML-DSA-65, clássica mais pós-quântica, para que uma futura quebra quântica não derrube o sistema. Sem assinatura verificada, sem demonstrativo de royalties.
Trilha de auditoriaSomente-anexação, encadeada por hash SHA-256, verificada de hora em hora, com uma "âncora" diária da ponta da cadeia guardada totalmente fora do banco de dados
FrontendCerca de 30 páginas HTML estáticas simples, sem framework, em 13 idiomas, em hospedagem compartilhada comum
Quem construiuUm humano dirigindo o tráfego, o Claude Code escrevendo o código, um enxame local de agentes com modelos abertos fazendo passes de revisão e trabalho braçal
Situação atualTotalmente preparado e testado. O deploy é só dry-run até eu digitar pessoalmente "GO."

Uma linha do tempo aproximada, para o caso de você achar que isso aconteceu num fim de semana:

  • Final de maio de 2026 — mudança de rumo de um projeto pessoal de chatbot para uma organização de licenciamento sem fins lucrativos, além do esquema inicial de 12 tabelas
  • Dias depois — reforço das assinaturas pós-quânticas, as edge functions do caminho do dinheiro, e a reescrita "sem custódia" (mais abaixo)
  • Início de junho — backend enviado para produção (o banco de dados, não o frontend público)
  • 16 de junho — reescrita jurídica concluída, a Licença v1.0 entra em vigor
  • 2 de julho — atualização completa do site/backend e retradução para 13 idiomas, preparada e testada, ainda esperando meu "GO" no momento em que escrevo isso

Nota curiosa sobre a origem: OMLA originalmente significava "Open Machine Learning Assistant", um projeto pessoal de chatbot. As escolhas de infraestrutura passaram direto para a virada rumo ao licenciamento; o chatbot foi rebaixado a um ajudante de documentação com escopo travado, deliberadamente desligado em produção. Transformar um chatbot hobby em infraestrutura de licenciamento é uma quantidade normal de scope creep, né?

A regra que tornou o resto possível

Uma decisão de design fez a maior parte do trabalho pesado, antes de qualquer código ser escrito: a OMLA nunca movimenta, guarda ou transmite dinheiro. Ela calcula o que é devido e publica a carteira ou os dados de pagamento fornecidos pelo próprio beneficiário. O usuário comercial paga o criador diretamente, ponto a ponto. Sem processamento de pagamento, sem escrow, sem "saldo OMLA". Os identificadores de carteira são informação de roteamento, não contas.

O texto da licença diz isso sem rodeios: "OMLA publishes; OMLA does not pay." (a OMLA publica; a OMLA não paga)

Por que se preocupar com isso? Ser um transmissor de dinheiro é um pesadelo regulatório à parte, empilhado sobre o do licenciamento. Ao evitar a custódia, o peso de KYC, sanções e impostos passa para as duas partes que realmente estão transacionando — que é onde ele juridicamente pertence de qualquer forma. Essa única decisão é o motivo de um hobbyista solo sequer conseguir tentar este projeto.

Nem era o design original. No meio da construção, o esquema ainda dava a entender custódia, então uma tabela literalmente chamada payments foi renomeada para royalty_statements — uma migração inteira de colunas, índices, triggers, políticas de RLS e enums, só para o banco de dados parar de mentir sobre o que faz. O texto antigo ainda voltou para me morder depois (veja as ciladas).

Aqui está o caminho que um dólar de royalty percorre sem a OMLA jamais segurá-lo.

O passo 4 é o portão: sem assinatura verificada lá atrás no passo 1, nunca há demonstrativo de royalties. A OMLA publica o número e a carteira, e daí em diante é entre as outras duas partes — o mesmo que eu te contar que um amigo te deve vinte dólares e deixar vocês dois resolverem isso.

O loop de verdade: humano, agentes, verificação, deploy

O fluxo de trabalho não é complicado. Ele só é rígido sobre quem faz o quê, e se repete toda vez que algo muda.

O que importa não são as caixas, é que nenhuma caixa é pulada. Toda mudança começa comigo escrevendo o que deve existir e por quê, não "deixa melhor". Os agentes rascunham em cima dessa especificação, outros agentes auditam o rascunho antes de eu sequer ver, e os testes rodam contra uma infraestrutura que se comporta como produção. Só então eu leio o diff.

O backend inteiro roda local primeiro: uma stack real do Supabase, Postgres 17 mais edge functions, na minha própria máquina em containers rootless. Produção é um alvo de deploy, nunca a fonte da verdade. Se o local e o ambiente ao vivo divergem, o ao vivo é que está errado, até eu publicar.

O padrão de qualidade mora na configuração do projeto, não só na minha cabeça: "Audit-ready by default: ship work that can withstand external audit." (pronto para auditoria por padrão: publique apenas trabalho capaz de resistir a uma auditoria externa) Tudo parte do princípio de que um revisor independente, IA ou humano, vai tentar achar falhas nisso depois.

Testando contra uma stack real, não um mock

Nada disso importa se os testes estiverem mentindo para você, então nada aqui é publicado contra um banco de dados simulado. Tudo roda contra uma stack local real e descartável. Três camadas, todas verdes antes de qualquer coisa avançar rumo ao deploy:

deno test                  # 13 unit tests for the edge functions
./test/run.sh              # isolated scratch DB per run, migrations w/ ON_ERROR_STOP,
                            # smoke tests (PQ signatures, wrong-key rejection, audit
                            # hash-chain, payout gate), RLS cross-tenant isolation,
                            # an adversarial suite, then rollback + reapply
./test/integration.sh      # the full money path against the live local stack:
                            # register → tampered payload rejected → wallet verify →
                            # splits → usage report → statement published → replay
                            # (asserts zero duplicate writes) → admin gate → compliance

Aquela linha do "replay que garante zero escritas duplicadas" importa mais do que parece. Relatórios de uso vêm de sistemas de outras pessoas, então cedo ou tarde um vai ser reenviado sem querer; o teste verifica que reproduzir o mesmo relatório gera zero demonstrativos novos, não só que nada quebrou. A suíte foi depois reforçada para fazer assert dos resultados em vez de só registrar em log — parece implicância até você depurar um teste que "passou" sem fazer nada.

Auditorias avaliando outras auditorias

Uma IA revisando o próprio trabalho é só um carimbo de aprovação automático. Por isso as auditorias são propositalmente feitas em camadas: os agentes do enxame local fazem um primeiro passe de correções, e depois um modelo mais forte roda como portão final e independente de auditoria.

Esse portão final não é cerimônia. Numa passagem, ele verificou as correções dos agentes locais e ainda assim encontrou um bypass de search_path, além de lacunas em colunas, assinaturas e linhagem que o primeiro passe deixou passar. Isso virou sua própria migração de reforço: doze descobertas numeradas, cada uma publicada com um teste de regressão para que não volte quietinha.

A escala acompanha a mudança. Coisas de rotina recebem um painel de revisão de 3 agentes. A reformulação completa do frontend e do i18n recebeu um passe de enxame com 24 agentes, que flagrou que o site tinha se desviado (ainda descrevia o antigo produto de chatbot, não o backend de licenciamento em que havia se tornado) e forçou uma reconstrução para bater com a realidade.

O portão de deploy: dry-run até eu digitar

O executor de deploy tem um único trabalho: garantir que nada acima desta linha chegue à produção por acidente. Dry-run por padrão, toda vez; a produção só é tocada com uma flag explícita:

./deploy.sh              # dry run (default) — shows exactly what WOULD happen
./deploy.sh --go         # only a human runs this, only when ready

Um wrapper guiado vai um passo além: você literalmente digita "GO" antes de qualquer etapa que altere a produção. E a regra permanente para os agentes, escrita para parar de ser uma sugestão: nunca adicionar --go sem uma instrução humana explícita.

Outras garantias embutidas no executor, não só política no papel:

  • A sincronização do frontend nunca usa --delete, então não consegue arrasar arquivos no host que não gerencia
  • Um backup do lado do servidor é feito antes de qualquer sobrescrita do frontend
  • O backend se recusa a agir a menos que o projeto vinculado corresponda ao projeto de produção esperado — uma trava rígida contra publicar no banco de dados errado
  • Só migrações aditivas rodam contra o ambiente remoto, nunca um reset
  • A função de chatbot de documentação é excluída de todo deploy, por princípio
  • Segredos vivem só num arquivo modo 600 fora do repositório; uma checagem em texto puro confirma que a chave de service-role nunca aparece no que é publicado

Sinceramente, o log de deploy deste projeto é basicamente um diário de mim tendo frio na barriga: dry run atrás de dry run, enquanto um redesign totalmente preparado ficava esperando a palavra. Isso não é um bug. É exatamente essa a sensação que "com portão" deveria dar.

Ciladas

As partes que doeram:

  • O byte de largura zero. O SQL de migração precisa ser ASCII puro. Um único byte invisível fora do ASCII pode partir um token de dollar-quote $$ e silenciosamente fundir dois comandos SQL. A correção virou ritual: rodar grep atrás de bytes fora do ASCII (quer zero) e contar os tokens $$ (quer um número par), toda vez.
  • O sinal de porcentagem morde. Numa string de formato de RAISE EXCEPTION, %% é um percentual literal e cada valor precisa de exatamente um %. Isso me mordeu uma vez, e esse é o único motivo de estar escrito aqui agora.
  • SECURITY DEFINER precisa de um search_path fixado. Toda função definer e de trigger fixa o próprio search path para que ninguém consiga sombrear uma tabela em pg_temp e alimentá-la com dados errados. O teste adversarial conta as funções fixadas e falha se a contagem cair.
  • O superusuário instável. Depois de um reinício malfeito, o papel local do Postgres às vezes volta sem privilégios de superusuário. A correção é parar e iniciar a stack de forma limpa, não investigar o problema. Escrito aqui para os agentes pararem de redescobrir isso.
  • O i18n sobrescreve o HTML silenciosamente. A camada de tradução substitui o texto da página por completo, então "consertar" o HTML ainda pode servir texto desatualizado se o arquivo de idioma não for consertado também. Foi exatamente assim que o texto antigo da era de custódia continuou reaparecendo depois de supostamente removido.
  • A cadeia de auditoria pode ser enganada, de propósito, para sabermos disso. Um atacante com controle total do banco de dados poderia derrubar o trigger da cadeia de hash e reconstruir um histórico falso autoconsistente; só a checagem interna não pegaria isso. Por isso um job diário ancora o hash da ponta da cadeia totalmente fora do banco de dados, e a suíte de testes prova as duas metades numa única execução: a checagem interna é enganada, a âncora externa ainda assim detecta a reescrita.
  • O site ao vivo não é o site preparado. No momento em que escrevo isso, o site público ainda mostra algum texto de antes do realinhamento (um rascunho antigo de licença, um card desatualizado sobre trilhos de pagamento) porque o redesign está preparado, mas não publicado. Além disso, a URL pública /about é um índice de diretório nu; a página de divulgação de uso de IA fica um nível abaixo.

← Mais de IA e LLM Local