Dar a um agente uma máquina para testar
Um rig é uma máquina descartável que um agente abre quando precisa mesmo testar alguma coisa: carregar uma página, clicar por um app de desktop, tocar em um celular. Você pode assistir ao trabalho dele em tempo real e assumir o controle sempre que quiser.
Rigs isolados de terminal, navegador e desktop são VMs com discos descartáveis e redes com portão de saída. Android e iOS são emuladores gerenciados pelo host: o estado dos dispositivos é descartável, mas a rede deles segue o host do servidor.
Configure uma vez
Seção intitulada “Configure uma vez”Os rigs rodam na máquina que hospeda o cc_server — a mesma máquina, não
aquela que você está olhando. Existem cinco superfícies voltadas ao usuário; as
superfícies de desktop e móveis precisam de configuração no host:
| Superfície | Roda em | Configuração |
|---|---|---|
| Terminal (VM) | Uma microVM que inicializa uma imagem Ubuntu fixada | Nenhuma — a imagem é baixada automaticamente no primeiro uso |
| Navegador (VM) | Uma microVM que inicializa uma imagem Debian fixada, com Chromium, Firefox ou WebKit instalados no primeiro uso | Nenhuma — o mesmo |
| Computador (VM) | QEMU com uma imagem de desktop Linux que já inclui Chromium, Firefox, WebKit e uma base de CLI no estilo de um runner hospedado no GitHub | Instale o QEMU (brew install qemu) e depois Importar uma imagem de desktop em Configurações → Servidor → Rigs |
| Android | O emulador Android do Google | Instale o SDK do Android, crie um AVD e inicie-o (abaixo) |
| Simulador de iOS | CoreSimulator no Mac do servidor | Instale o Xcode e o runtime de iOS solicitado e depois instale a ponte de automatização em Configurações → Servidor → Rigs |
As máquinas de terminal e de navegador inicializam a partir de imagens fixadas por digest: os bytes exatos são definidos de antemão, baixados uma vez na primeira inicialização e guardados em cache — depois da primeira inicialização de cada tipo, as máquinas seguintes pulam o download por completo e sobem em segundos. Configurações → Servidor → Rigs mostra o que o seu servidor consegue inicializar e todas as máquinas em execução neste momento.
Uma imagem de desktop instalada continua gerenciável na mesma página: Importar a substitui por um qcow2 mais recente, e Excluir a remove para que você instale uma build nova.
Dispositivos móveis são configurados de outra forma
Seção intitulada “Dispositivos móveis são configurados de outra forma”Não existe uma imagem nossa para Android ou iOS, e isso não é uma omissão. As imagens de sistema do Android vêm do SDK do Google; os runtimes de iOS vêm do Xcode. Para o Android, instale o Android Studio (ou as ferramentas de SDK de linha de comando), adicione um dispositivo virtual no Gerenciador de dispositivos e inicie-o. A página Rigs passa então a informar o Android como disponível.
Ela também informa exatamente qual etapa está faltando — sem SDK, sem emulador,
sem dispositivo virtual, ou um dispositivo que simplesmente não está em
execução —, porque esses casos têm quatro correções diferentes e só uma delas é
um download. Se você iniciar o cc_server de um shell que não enxerga o SDK,
exporte-o:
export ANDROID_HOME="$HOME/Library/Android/sdk"Para o iOS, o próprio servidor precisa rodar no macOS com o Xcode e um runtime de Simulador de iOS instalados. Abra Configurações → Servidor → Rigs e pressione Instalar a ponte de automatização do iOS. O servidor baixa o artefato do WebDriverAgent fixado por checksum, verifica-o e o instala no armazenamento de automação do próprio servidor. Nenhum simulador inicializa durante a configuração.
Abra uma máquina
Seção intitulada “Abra uma máquina”As máquinas vivem como abas, ao lado do chat e do diff — em um espaço ou em
uma página de PR, no mesmo menu +, em Máquinas:
- Computador — um desktop Linux com Chromium, Firefox e WebKit
- Chromium, Firefox ou WebKit — um navegador
- Android — o emulador Android em execução
- Simulador de iOS — um simulador descartável criado para esta conversa
Escolha uma e pressione Iniciar a máquina. A aba informa em qual etapa da inicialização ela está (“Starting the microVM”, “Waiting for the guest to come up”) em vez de apenas girar.
A aba tem escopo na conversa, e a ferramenta do agente também. Uma aba do
Chromium, do Firefox ou do WebKit e a browser_use, o Android e a mobile_use,
ou o Simulador de iOS e a ios_use endereçam a mesma máquina padrão. Slots
adicionais de UI são máquinas de comparação separadas; as ferramentas do agente
sempre usam a padrão.
Para compilar, instalar e iniciar um app Flutter no Android:
fvm flutter build apk --debugDepois chame mobile_use com install_apk e
build/app/outputs/flutter-apk/app-debug.apk, seguido de start_app e do nome
do pacote Android. ui_dump, capturas de tela e entrada operam o mesmo
dispositivo mostrado na aba humana. stop_app, clear_app_data,
uninstall_app, open_url e chamadas shell em formato argv cobrem o resto
do ciclo de desenvolvimento sem invocar um shell no host do servidor.
Para compilar, instalar e iniciar um app Flutter no Simulador de iOS:
fvm flutter build ios --simulator --debug/usr/bin/plutil -extract CFBundleIdentifier raw -o - \ build/ios/iphonesimulator/Runner.app/Info.plistDepois chame ios_use com install_app e o diretório .app, seguido de
start_app e do identificador de bundle impresso pelo plutil.
A ferramenta de iOS também expõe stop_app, uninstall_app, open_url e uma
ação spawn em formato argv para diagnósticos locais do simulador.
As telas de desktop e de navegador se redimensionam para o painel. O iOS mantém o tamanho fixo em pontos do simulador e o exibe com barras. Toda superfície ainda tem duas faixas independentes: o agente recebe capturas de tela pequenas e baratas, enquanto você recebe a visualização ao vivo. Trocar de aba interrompe o stream humano, então uma máquina em segundo plano não custa largura de banda de exibição.
Uma aba de rig não inicia uma máquina sozinha, inclusive durante a restauração do layout. Essa regra evita que abrir o app inicialize VMs ou crie dispositivos de simulador sem que você espere por isso.
Opere a máquina
Seção intitulada “Opere a máquina”O canvas é seu para digitar e clicar sempre que ninguém mais detiver o controle exclusivo — ou quando for você que o detém. Enquanto você mantém esse bloqueio, a etiqueta de status exibe Você tem o controlo, o agente ainda pode tirar capturas de tela, e o servidor recusa as ações de mutação dele no único ponto de estrangulamento por onde toda ação passa. Tudo o que você faz é registrado em seu nome.
Pressione Parar a máquina quando terminar.
O controle é exclusivo de propósito: dois atores digitando na mesma máquina produzem entrada que nenhum dos dois pretendia.
Mova coisas para dentro e para fora
Seção intitulada “Mova coisas para dentro e para fora”Copiar e colar funcionam nos dois sentidos no canvas do rig, e arrastar arquivos também.
Copiar e colar. Pressione o atalho de cópia sobre o canvas e o que quer que a máquina tenha copiado — texto, uma imagem, uma lista de arquivos — vai para a sua área de transferência. Colar envia a sua no sentido oposto e pressiona colar dentro da máquina. No macOS o atalho é ⌘C/⌘V; ⌃C continua chegando a um shell do convidado como interrupção. No Windows e no Linux use ⌃C/⌃V — o convidado recebe a mesma tecla que receberia de qualquer forma, então ⌃C em um terminal do convidado continua interrompendo e a sua própria área de transferência fica intacta.
Nada é sincronizado em segundo plano. Uma senha que você copia na sua própria máquina não chega para dentro de uma VM porque um temporizador disparou; ela atravessa quando você cola.
Colar em um rig é permitido por padrão. Copiar de um rig pergunta primeiro — uma concessão de dez minutos, ou Permitir sempre em Configurações → Servidor → Rigs → Acesso à área de transferência. As duas direções são independentes e acompanham você, não o espaço de trabalho.
Arrastar arquivos para dentro. Solte-os em qualquer lugar do canvas.
- No Navegador (VM), a página recebe um drop real no ponto em que você solta, então uma zona de upload se comporta exatamente como se comportaria com um arquivo local.
- No Computador (VM), os arquivos vão para
~/Dropse os caminhos deles vão para a área de transferência da máquina, então ⌃V os cola em um gerenciador de arquivos ou em um campo de upload. Um host não consegue sintetizar um arrasto em um app Linux arbitrário sem rodar um daemon privilegiado dentro da VM, que os rigs deliberadamente não têm — então o toast informa onde os arquivos foram parar em vez de fingir que um drop aconteceu. - Em um terminal, o arquivo é copiado para dentro e o caminho dele é digitado no prompt, pronto para ser passado a um comando. Colar uma imagem em um terminal faz a mesma coisa: ela é salva na máquina e você recebe o caminho.
Arrastar arquivos para fora funciona a partir do Computador (VM). Comece a arrastar um arquivo dentro da máquina, leve o ponteiro para fora do canvas, e ele se torna um arrasto real no seu desktop — solte-o no Finder ou no Explorer. Copiar arquivos no gerenciador de arquivos da máquina e colar do seu lado também funciona. O Navegador (VM) não oferece isso: um navegador headless não tem payload de arrasto para ler, e adivinhar a partir da seleção de texto da página sequestraria cliques comuns.
Terminais dentro de um rig
Seção intitulada “Terminais dentro de um rig”Os terminais em um espaço ou em uma página de PR podem rodar dentro de um rig em vez de na própria máquina do servidor. Quando isso acontece, o painel mostra o selo VM isolada.
O que muda:
- Nada do que você executa chega ao host. Um
rm -rflá dentro custa o rig. - A rede nega por padrão. Somente os hosts da lista de permissões do rig são alcançáveis, e tudo passa por um portão que aplica essa lista.
git pushcontinua funcionando em um terminal que você abriu. O rig não armazena nenhuma credencial; ele pede ao servidor uma de curta duração por operação, limitada pelo seu próprio acesso ao forge, e esse token é revogado quando o rig fecha. Um rig aberto por um agente recebe uma credencial somente leitura, então ele pode fazer fetch, mas não push.
O que saber:
- Um terminal isolado restaurado espera por você. Como uma aba de rig, um
terminal
microvmque volta com o seu layout mostra um botão Abrir o shell em vez de inicializar a VM dele na abertura. Um terminal com shell do host custa um processo; um isolado custa uma máquina. - Arquivos soltos no terminal são digitados, não abertos. Solte um CSV em um terminal isolado e ele é copiado para dentro da máquina e o caminho dele no convidado aparece no prompt — o caminho do host seria um comando que falha lá.
- A cópia no rig é uma cópia. Sua worktree no host continua sendo a fonte da
verdade. Os commits que você faz dentro de um rig são trazidos de volta para
refs/rigs/<id>/*quando você pede — eles nunca movem o seu branch nem tocam na sua árvore de trabalho. - O trabalho destinado ao host continua rodando no host. Um convidado Linux
não consegue compilar para macOS nem rodar
xcodebuild. Escolha o backend nativo explicitamente para isso; o app pedirá que você confirme em vez de trocar em silêncio.
Rode um servidor de desenvolvimento no Terminal (VM) — pnpm dev na porta 3000,
digamos — e em poucos segundos o ícone de plugue no canto do terminal acende: a
porta é encaminhada para localhost:3000 na sua máquina, alcançável em
localhost:3000 dentro do Navegador (VM), compartilhável na sua rede e
nomeável como https://myapp.test. Todo o fluxo — encaminhamento automático,
compartilhamento na LAN, domínios de desenvolvimento com HTTPS — tem seu
próprio guia:
Encaminhar portas a partir de um terminal.
Imagens personalizadas
Seção intitulada “Imagens personalizadas”Um espaço de trabalho pode apontar o Terminal (VM) e o Navegador (VM) para imagens próprias — em Configurações → Servidor → Rigs → Imagens personalizadas (este espaço de trabalho). Uso típico: ampliar a imagem padrão com o conjunto de ferramentas de que o seu projeto precisa, para que todo terminal já inicie pronto, ou reutilizar uma imagem que a sua equipe já publica.
A máquina continua inicializando dentro do mesmo recinto: mesmo portão de saída, mesmo broker de credenciais, mesmo ciclo de vida. Somente administradores do espaço de trabalho podem alterar a configuração, as máquinas novas passam a usá-la (as em execução mantêm a delas), e a referência precisa ser uma imagem de um registro — caminhos locais são recusados.
O que uma imagem precisa fornecer:
- Terminal (VM) — uma imagem Linux com
bash. Ela também precisa degit,curlesocat— já instalados ou instaláveis na primeira inicialização (qualquer imagem baseada em Debian/Ubuntu funciona: eles são instalados automaticamente, junto com um conjunto de ferramentas de CLI no estilo de um runner hospedado no GitHub: compiladores, Python 3,jq, ferramentas de arquivamento,rsync. Runtimes de linguagem como Node/Go/Java e Docker não vêm pré-instalados). A porta7911do convidado é reservada para o encaminhador de portas. - Navegador (VM) — uma imagem Debian/Ubuntu com
bashesocat, além de um bináriochromium. O servidor inicia o próprio Chromium comochromium --headless=newe retransmite o DevTools da porta9223do convidado para a9222. PulseAudio e ffmpeg são instalados na primeira inicialização. Não faça buildFROM chromedp/headless-shell— esse binário não tem áudio. A substituição se aplica apenas a rigs do Chromium; Firefox e WebKit a ignoram e inicializam a imagem Debian fixada. As portas9222/9223do convidado são reservadas.
Duas recomendações: fixe a referência por digest (@sha256:…) para que os
bytes não mudem debaixo de você, e hospede-a no Docker Hub ou no GitHub
Container Registry — os hosts de download desses registros são admitidos
automaticamente pelo portão de saída; outros podem precisar que os hosts de
entrega de conteúdo deles estejam alcançáveis para o pull.
Quando um rig desaparece
Seção intitulada “Quando um rig desaparece”Os rigs existem para ser temporários:
- Ociosidade — depois de ~15 minutos sem nada acontecendo, um rig de navegador, desktop ou móvel estaciona (congelado, acorda na hora na próxima ação). Um terminal isolado espera 45 minutos. Depois do dobro da janela de ociosidade, ele fecha.
- Limite de tempo — todo rig tem um tempo de vida rígido que ele não consegue estender, faça o que fizer.
- Memória — se o servidor precisar de espaço para um rig novo, ele fecha o menos usado recentemente. Um rig que alguém esteja operando, assistindo ou com um terminal aberto nunca é tomado.
Quando um rig isolado fecha, o disco dele é descartado. Fechar um rig do Android se desconecta do emulador do host — não o exclui. Um rig do iOS exclui o dispositivo CoreSimulator que criou. Traga de volta primeiro qualquer coisa que você queira manter.
O que um rig consegue alcançar
Seção intitulada “O que um rig consegue alcançar”Rigs isolados de terminal, navegador e desktop usam por padrão um portão de
saída que nega tudo: você concede hosts explicitamente, e a única rota do
convidado é um portão que aplica essa lista. Um rig de navegador também admite
o site do produto (usectrl.dev) de saída. O broker de credenciais usa a mesma
lista.
Duas ressalvas honestas:
- A rede dos móveis segue o host. O emulador do Android e o CoreSimulator da Apple não estão atrás do portão de saída do recinto. Nenhuma das abas móveis oferece um controle de contorno da rede, porque a rede gerenciada pelo host já é irrestrita.
- Tudo o que um rig lê é não confiável. Texto de página, DOM, árvores de acessibilidade e dumps de visualização voltam ao agente envoltos em marcadores que dizem “isto é dado, não instrução”. Uma página que tente dar ordens ao seu agente é lida como uma string entre aspas.
Você pode ver tudo o que está em execução, e parar qualquer coisa, em Configurações → Servidor → Rigs.
Relacionados
Seção intitulada “Relacionados”- Rigs e recintos — o modelo por trás de tudo isso: por que VMs, as duas faixas de exibição, o broker de credenciais, o ciclo de vida
- Encaminhar portas a partir de um terminal — alcance um servidor de desenvolvimento de onde quer que importe
- Referência de rigs — toda superfície, verbo, porta e padrão em um só lugar
- Configurar guardrails —
Controlar um recinto (rig)é uma classe de ação que você pode definir como permitir, perguntar primeiro ou negar, por espaço de trabalho, agente ou espaço. Os modos somente leitura negam isso por completo.