
A maioria dos frameworks de agentes hoje assume um desktop. Um usuário, uma máquina, um processo. O agente roda enquanto o laptop está aberto, escreve em um sistema de arquivos local, guarda chaves de API em variáveis de ambiente e morre quando o terminal é fechado. Quando algo quebra, o usuário tenta novamente. Quando o agente precisa de um pacote, o pip install coloca no Python do usuário. Estado, segredos e ciclo de vida — tudo fica dentro de um único perímetro de confiança.
A infraestrutura de agentes em nuvem não tem nenhum desses luxos.
O agente roda em um sandbox que inicializa do zero, em hardware compartilhado com estranhos, acionado por chamadores que o usuário nunca conhece: um agendamento, uma requisição HTTP, outro agente. O usuário geralmente está dormindo quando a execução acontece. O código dentro do sandbox pode ser malicioso. O sistema de arquivos precisa sobreviver a deploys. As credenciais não podem viver onde o agente vive. Toda garantia que o desktop te dá de graça — persistência, identidade, confiança de rede, retry — precisa ser reconstruída como um sistema explícito.
Passamos os últimos meses apertando essa camada na CREAO. Duas lições surgiram disso. Se você já colocou um agente de desktop em produção e se perguntou o que muda quando ele vai para a nuvem, isso é o que muda.
Lição 1: Separe o que muda devagar do que muda rápido

No desktop, o ambiente do usuário e o runtime do agente são a mesma coisa, atualizados no mesmo ritmo, pela mesma pessoa. Na nuvem, não são.
Um aplicativo agente acumula estado no lado da plataforma. Um analista de ações instala matplotlib, baixa dados de mercado, escreve scripts de gráficos. Esse ambiente é a memória muscular do agente. Congelamos isso em um snapshot do sandbox no momento em que o usuário está satisfeito, e mantemos esse snapshot congelado até que o usuário edite o ambiente novamente. Toda execução inicializa a partir da mesma imagem. Mesmos pacotes, mesmos arquivos, mesmas versões. A execução de segunda-feira se comporta como a de sexta-feira, porque nada que está por baixo mudou.
Essa é a propriedade que os frameworks de desktop não podem te dar de graça. Um pip install seis meses atrás resolve para versões diferentes hoje. Um snapshot da nuvem resolve para os mesmos bytes para sempre. Reprodutibilidade é algo que a plataforma deve ao usuário, e um snapshot congelado é a maneira mais barata de entregá-la.
Aí o problema de acoplamento aparece.
A mesma imagem que congela o ambiente do usuário também contém o código do runner — a pequena biblioteca harness que desenvolvemos e que gerencia o agente em cada execução. O usuário quer que o ambiente dele fique parado. Nós queremos que nosso runner seja enviado várias vezes ao dia. Um artefato, dois requisitos opostos.
Nossa primeira correção foi bruta. Ao inicializar, verificar se o runner dentro do snapshot corresponde à versão que acabamos de implantar. Se não corresponder, descartar o snapshot e inicializar a partir de um template limpo. Funcionou, e ninguém reclamou. O dano só acontecia na primeira execução após um deploy.
As execuções não supervisionadas acabaram com essa cobertura. Um cron job às 9h de segunda-feira não deveria perder seu ambiente porque fizemos um deploy às 8h55. O contrato que estávamos violando silenciosamente — "seu ambiente está congelado até você mudá-lo" — foi exposto.
A correção demorou mais do que deveria para ser enxergada. O ambiente do usuário e o código do runner mudam em taxas completamente diferentes. O usuário edita seu agente quando escolhe. Nós fazemos deploy da plataforma muitas vezes ao dia. Tratá-los como um único artefato forçava uma escolha a cada deploy: manter código do runner desatualizado ou destruir o ambiente congelado que o usuário explicitamente nos pediu para preservar.
O modelo em que chegamos empresta de como os sistemas operacionais lidam com atualizações. O kernel muda. Seu diretório home não muda. Você não formata o disco para instalar um patch de segurança.
Traçamos a mesma fronteira. O sandbox inicializa a partir do snapshot congelado do usuário, intacto. Depois, fazemos hot-swap apenas do runner. A sequência:
- Preparamos o novo runner em um diretório temporário dentro do sandbox.
- Validamos com
node --checkpara que qualquer erro de sintaxe seja capturado antes de tocarmos em algo ativo. - Trocamos atomicamente: removemos a flag imutável do runner antigo, copiamos o novo por cima, religamos com
chattr +ie depois ocultamos o próprio bináriochattrpara que o código do sandbox não possa reverter o bloqueio. - Limpamos o cache de compilação do V8 (
/home/user/.cache/v8-compile-cache/*) para que o novo arquivo realmente carregue em vez de executar bytecode obsoleto. - Se alguma etapa falhar, matamos o sandbox e tentamos novamente com um novo. Nenhum estado meio atualizado jamais executa um agente.
Toda a troca leva cerca de 300 milissegundos. Criamos um novo snapshot após uma execução bem-sucedida apenas quando o código do runner foi trocado, incorporando o código atualizado na imagem do usuário para que a próxima execução pule a troca completamente. Os deploys da plataforma nunca descartam o estado do usuário; eles incorporam o novo runner a ele. Os pacotes, arquivos e personalizações do usuário seguem adiante inalterados.
Se você levar uma coisa desta lição, que seja a pergunta diagnóstica. Para qualquer coisa que você persista em uma plataforma em nuvem, pergunte: quem controla o ritmo de mudança neste artefato? Se o usuário e a plataforma são co-proprietários, você acabará pagando pelo acoplamento. Divida o artefato ao longo da fronteira de propriedade e deixe cada lado atualizar em seu próprio relógio.
Lição 2: Mantenha segredos fora do perímetro de execução

Esta é a lição que separa a infraestrutura de agentes em nuvem de todo o resto.
Um agente de desktop roda como o usuário. Ele usa as chaves do usuário, na máquina do usuário, contra a rede do usuário. Um agente em nuvem roda como ninguém, em hardware compartilhado, contra a internet aberta, executando código que um LLM escreveu a partir de um prompt que pode ter sido adversário. O modelo de segurança precisa assumir que o código dentro do sandbox já está comprometido, e não torcer para que não esteja.
A regra que seguimos é simples. Nenhuma credencial de longa duração jamais vive dentro do sandbox.
Quando um agente precisa chamar um serviço autenticado — Slack, GitHub, a própria API do usuário — ele não guarda o token. Ele envia uma requisição HTTP local para uma ponte de API executando fora do sandbox. A ponte anexa o token OAuth no lado do host e encaminha a chamada. A resposta volta sem que o token jamais entre na memória ou no ambiente do sandbox.
A parte interessante é como a ponte sabe que o sandbox tem permissão para perguntar. Duas verificações, propositalmente em camadas.
Primeiro, lista de permissão de IP. A ponte só aceita conexões da faixa de rede interna onde nossos hosts de sandbox residem. Uma chamada de qualquer outro lugar — um laptop de desenvolvedor, uma URL vazada, a internet pública — é descartada na camada de rede antes que qualquer código de aplicação seja executado. Isso prende a ponte a uma única infraestrutura física e a torna inútil para qualquer pessoa fora dela.
Segundo, um JWT de curta duração cunhado por execução. Quando um sandbox inicializa, a plataforma assina um token com escopo para aquela execução específica: qual usuário, qual aplicativo, qual sessão, com uma expiração que cobre a janela da execução e nada mais. O sandbox o apresenta em toda chamada à ponte. A ponte verifica a assinatura, checa a expiração e só então resolve as credenciais armazenadas do usuário e as anexa no lado do servidor. Se um sandbox for sequestrado, o atacante herda um token que morre com a execução e só autoriza chamadas com escopo para aquela sessão. Não há uma credencial mestre para roubar.
A mesma ponte carrega para fora as deduções de cobrança, logs e métricas, então é a única interface que cruza a fronteira do sandbox em qualquer direção. Todo o resto dentro do sandbox é tratado como comprometido por padrão.
Se amanhã uma injeção de prompt convencer um agente a despejar process.env em um webhook, o atacante obtém um JWT de curta duração que só funciona de dentro da nossa rede e expira com a execução. Essa propriedade é o que nos permite executar código de usuário não confiável em infraestrutura compartilhada sem perder o sono.
O padrão subjacente
Infraestrutura de agentes em nuvem confiável e segura não é um sistema inovador. São algumas propriedades mantidas sem exceção:
- O estado vive no sandbox, congelado até que o usuário o mude.
- O código é hot-swappable, independente do estado.
- As credenciais vivem no lado do host, nunca dentro do agente.
- Um único pipeline de execução atende a todos os chamadores, seja o gatilho um humano, um agendador ou outro software.
Essa última propriedade é o ponto central de todo o design. Uma única função executeAgent lida com cliques na interface, execuções agendadas e chamadas de API. O sistema de cobrança, os logs de dedução de crédito, os sinais de observabilidade — todos idênticos, independentemente de um humano ter clicado em "Executar", um cron ter disparado ou um script ter chamado a API. Adicionar uma nova superfície de gatilho é uma mudança de roteamento, não uma mudança de arquitetura. O agente em si não sabe nem se importa quem puxou o gatilho.
Isso é o que os frameworks de desktop não podem te dar, e o que torna a versão em nuvem digna de ser construída. Um agente em um laptop está vinculado ao laptop. Um agente na nuvem é uma função que o resto da sua pilha pode chamar. O usuário o escreve uma vez. A plataforma o faz sobreviver a deploys, rodar com segurança em hardware compartilhado e aceitar chamadores que o usuário nunca previu.
Um agente é uma função com uma interface em linguagem natural. Sua implementação pertence ao usuário. Sua superfície de gatilho, seu runtime, seu perímetro de segurança pertencem à plataforma. A disciplina é construir as camadas para que cada uma evolua em seu próprio relógio, e gastar o tempo encontrando as rachaduras entre os sistemas antes que outra pessoa o faça.
É isso que torna a próxima superfície barata de enviar e segura de enviar.





