Rigs
Apenas fatos. Para o modelo por trás deles, leia Rigs e recintos; para abrir uma máquina, siga o guia.
Superfícies e backends
Seção intitulada “Superfícies e backends”| Superfície | Conduz | Backend | Valor | Saída de rede contida |
|---|---|---|---|---|
| Terminal (exec) | Um shell sobre o canal de exec da VM | microVM | smolvm |
Sim |
| Navegador | Chromium headless (CDP), Firefox (WebDriver BiDi) ou WebKit (W3C WebDriver) | microVM | smolvm |
Sim |
| Computador | Desktop X11: entrada pelo hipervisor, captura pelo agente do convidado | QEMU | qemu-hvf (macOS), qemu-kvm (Linux), qemu-tcg (alternativa sem aceleração, nunca escolhida automaticamente) |
Sim |
| Android | Android sobre ADB | Emulador do Google | android-emulator |
Não — o emulador gerencia a própria rede |
| iOS | Simulador de iOS via WebDriverAgent | CoreSimulator | ios-simulator |
Não — a rede acompanha o Mac host |
O terminal e a superfície computer_use compartilham o valor de superfície
computer; o terminal é distinguido pelo seu marcador de imagem de exec e
nunca é reutilizado como um desktop controlável (nem o contrário). Uma
conversa reutiliza uma única máquina de terminal.
Motores de navegador
Seção intitulada “Motores de navegador”| Motor | Valor | Protocolo | Visualização ao vivo | Imagens estáticas |
|---|---|---|---|---|
| Chromium | chromium (padrão) |
Chrome DevTools Protocol | Screencast — o navegador envia quadros conforme a página é repintada | JPEG |
| Firefox | firefox |
WebDriver BiDi | Imagens estáticas por polling (o BiDi não tem screencast), limitadas a 6 fps | JPEG |
| WebKit | webkit |
W3C WebDriver (clássico) | Imagens estáticas por polling, transcodificadas pelo ffmpeg do host | PNG |
Um rig executa um motor por toda a sua vida. Uma conversa pode manter um rig por motor, e é isso que torna possível uma comparação lado a lado: abrir o “Firefox (VM)” ao lado do “Chromium (VM)” são duas máquinas, e fechar uma deixa a outra em execução.
Passe engine para rig.open ou para a ferramenta browser_use. Um nome
desconhecido é recusado em vez de virar padrão — pedir um navegador e receber
outro em silêncio responde a uma pergunta de compatibilidade com a resposta
errada.
Limites específicos de cada motor, declarados em vez de contornados:
- O Firefox não tem recarregamento que ignora o cache (ele rejeita o
ignoreCachedo BiDi de imediato), então um recarregamento forçado é um recarregamento normal. - O WebKit também não tem recarregamento que ignora o cache, nem feed de
console (a saída é capturada interceptando
console.*depois de cada navegação, então tudo o que é registrado durante o carregamento se perde — toda extração de console diz isso), e precisa deffmpegno host para a sua visualização ao vivo. - Nenhum dos dois expõe uma árvore de acessibilidade da plataforma pelo seu
protocolo, então
extract (a11y)retorna uma aproximação derivada do DOM, rotulada como tal. - Nenhum dos dois aceita um drop de arquivo de verdade; ainda assim, um campo de seleção de arquivo pode ser apontado para caminhos dentro da máquina.
Imagens das máquinas
Seção intitulada “Imagens das máquinas”| Superfície | Imagem | Obtida |
|---|---|---|
| Terminal | ubuntu:24.04, fixada por digest |
Automaticamente na primeira inicialização, pela própria rede da máquina que passa pelo portão de saída |
| Navegador (Chromium, Firefox, WebKit) | debian:trixie-slim, fixada por digest, mais os pacotes do próprio motor |
Automaticamente na primeira inicialização e depois em cache como um pacote pré-aquecido |
| Computador | Uma imagem de desktop qcow2 com Chromium, Firefox, WebKit e a mesma base de CLI de um runner hospedado no GitHub que o terminal pré-aquece | Importar em Configurações → Servidor → Rigs (downloads fixados por checksum quando publicados) |
| Android | As imagens de sistema do Google | Pelo Android SDK |
| iOS | Um runtime do Simulador do Xcode mais o WebDriverAgent fixado por checksum | Runtime pelo Xcode; ponte de automação em Configurações → Servidor → Rigs |
Depois da primeira inicialização de cada tipo de microVM, o servidor guarda
em cache uma cópia pré-extraída no diretório de dados e inicializa toda
máquina seguinte a partir dela — inclusive imagens pré-aquecidas com os
pacotes já instalados. O terminal pré-aquece um conjunto de ferramentas de CLI
no estilo de um runner hospedado no GitHub (git, gcc, python3, jq,
rsync, ferramentas de arquivamento e o resto da base do apt; não Docker nem
toolcaches de linguagem). O qcow2 do Computador incorpora os mesmos nomes de
CLI no momento da build da imagem, ao lado do XFCE e dos três navegadores.
Todo navegador pré-aquece o seu motor. Os três motores compartilham uma base
Debian, mas nunca compartilham um pacote: o cache tem como chave a imagem, o
motor e uma revisão de áudio (audio-v1-<engine>), porque uma máquina
pré-aquecida para um motor — ou antes de PulseAudio e ffmpeg fazerem parte da
carga de trabalho — não tem nada do outro. O pacote do terminal tem como
chave uma revisão de conjunto de ferramentas (tools-v1) pelo mesmo motivo:
um pacote pré-aquecido antes de o compilador fazer parte da imagem não pode
servir uma máquina que deveria tê-lo.
Não existe nenhuma imagem de automação pré-montada que valha a pena usar — o
chromedp/headless-shell do Chromium compila ALSA e PulseAudio para fora,
então nunca consegue emitir som; a única imagem mantida de Firefox tem 33× o
tamanho da base Debian e ainda não traz socat; não existe nenhuma imagem
mantida de WebKit. Por isso todo motor se instala na primeira inicialização
(chromium, firefox-esr ou webkit2gtk-driver) e, ao fazer isso, alcança
os arquivos do Debian (deb.debian.org, security.debian.org,
cloudfront.debian.net). O Chromium é o binário da distribuição iniciado como
chromium --headless=new.
Imagens personalizadas por espaço de trabalho
Seção intitulada “Imagens personalizadas por espaço de trabalho”| Chave de configuração | Substitui |
|---|---|
rigs.smolvm.execImage |
A imagem do Terminal (VM) |
rigs.smolvm.browserImage |
A imagem do Navegador Chromium (VM) |
Gravado pelo armazenamento de configurações do espaço de trabalho com portão de administrador (Configurações → Servidor → Rigs → Imagens personalizadas (este espaço de trabalho)). O valor deve ser uma referência de registro — caminhos locais, arquivos e strings semelhantes a flags são recusados, tanto no campo quanto de novo na inicialização. Um valor armazenado inválido é ignorado de forma ruidosa, e o padrão inicializa em seu lugar. O registro da própria imagem (mais os CDNs de blob conhecidos que o acompanham para Docker Hub, GHCR, Quay, GitLab e GCR) é admitido pelo portão de saída para o pull.
Contrato da imagem de terminal — bash presente; git, curl, socat
pré-instalados ou uma base apt Debian/Ubuntu (o recinto instala esses três,
mais um conjunto de ferramentas de CLI no estilo de um runner hospedado no
GitHub, na primeira inicialização: compiladores, Python 3, jq, ferramentas
de arquivamento, rsync. Toolcaches de linguagem e Docker não são
instalados).
Contrato da imagem de navegador — uma base apt Debian/Ubuntu (ou os pacotes
já instalados) com bash e socat, mais um binário chromium que o próprio
servidor inicia como chromium --headless=new com o DevTools no loopback do
convidado 9223, retransmitido para a porta 9222 do convidado. PulseAudio e
ffmpeg são instalados na primeira inicialização para a faixa de áudio. Não
faça build FROM chromedp/headless-shell: o headless.gn upstream compila
ALSA e PulseAudio para fora, então esse binário não consegue emitir som. A
substituição se aplica apenas a rigs de Chromium — o comando de carga de
trabalho que ela inicializa é o do Chromium, e entregá-lo ao Firefox ou ao
WebKit iniciaria um binário que não está lá. Um rig de Firefox ou WebKit a
ignora de forma ruidosa e inicializa a sua imagem fixada.
Portas de automação — toda máquina de navegador encaminha exatamente uma
porta de loopback do host para a 9222 do convidado. Por trás dela: o DevTools
do Chromium e o agente remoto do Firefox ficam no loopback do convidado 9223,
com um relay socat na frente (ambos vinculam ao loopback
incondicionalmente); o driver do WebKit aceita um --host e vincula a própria
NIC do convidado. O Firefox ainda valida o cabeçalho Host contra a sua
própria porta, então o cliente envia a autoridade do lado do convidado em vez
daquela para a qual discou.
Verbos de ação
Seção intitulada “Verbos de ação”Toda ação é analisada de forma total: um payload malformado retorna uma mensagem nomeando o campo, nunca uma exceção. Os verbos de observação (marcados com ○) continuam permitidos enquanto uma pessoa detém o controle; os verbos de mutação são recusados.
computer_use
Seção intitulada “computer_use”screenshot○, cursor_position○, mouse_move, left_click,
right_click, middle_click, double_click, triple_click,
left_mouse_down, left_mouse_up, left_click_drag, scroll, key,
hold_key (0–60 s), type, wait○ (0–60 s), set_display,
clipboard_read○, clipboard_write.
As coordenadas são pixels do convidado no modo atual do convidado; toda
captura de tela informa o tamanho da tela. As combinações de teclas usam a
grafia do X11 (ctrl+s, alt+Tab, Return).
clipboard_read recebe um selection: clipboard (o que ctrl+C preenche, o
padrão), primary (selecionar para copiar do X11) ou xdnd (um arrasto em
andamento). Um resultado vazio é uma resposta normal para os três.
clipboard_write recebe apenas text — imagens e arquivos viajam pela faixa
de arquivos, porque os argumentos de uma ação são persistidos no log de
auditoria e bytes de imagem não têm o que fazer lá. O conteúdo da área de
transferência volta cercado como dado não confiável.
browser_use
Seção intitulada “browser_use”navigate (apenas http/https), reload (hard opcional), stop_loading,
click (seletor ou coordenada), fill, type, key (nomes de tecla do DOM),
scroll, mouse_move, drag, left_mouse_down, left_mouse_up,
extract○ (a11y | dom | console), screenshot○ (full_page
opcional), set_viewport (mín. 320×240), history, wait_for○ (seletor,
0,1–30 s), clipboard_read○, clipboard_write.
O conteúdo extraído da página volta cercado como dado não confiável.
O navegador tem exatamente uma área de transferência, então clipboard_read
não recebe selection. Os dois verbos de área de transferência precisam de um
contexto seguro: uma página servida por http:// simples não tem API de
área de transferência nenhuma, e o verbo diz isso em vez de relatar uma vazia
— nesse caso use type, que insere no cursor sem passar pela área de
transferência.
mobile_use
Seção intitulada “mobile_use”tap, swipe (50–5000 ms), type, key (aliases back, home,
recents, enter, delete, backspace, tab, escape, search,
menu, volume_up, volume_down, power, ou qualquer KEYCODE_*),
screenshot○, ui_dump○, install_apk
(restrito à worktree do rig e ao diretório de dados do servidor), start_app,
stop_app, clear_app_data, uninstall_app, open_url, e shell.
shell recebe uma lista argv e executa dentro do Android, nunca por um shell
do host; ele cobre diagnósticos de desenvolvedor como logcat, dumpsys e
pm grant.
mobile_use não tem verbos de área de transferência. Desde o Android 10,
apenas o app em foco pode ler a área de transferência.
ios_use
Seção intitulada “ios_use”tap, swipe (50–5000 ms), type, key (enter, backspace, tab,
escape, teclas de seta ou um caractere imprimível; modificadores opcionais
command, control, option e shift), home, lock, unlock,
screenshot○, ui_dump○, install_app (um diretório .app de simulador
restrito à worktree do rig ou ao diretório de dados do servidor), start_app, stop_app,
uninstall_app, open_url, e spawn. spawn recebe argv e executa
dentro do simulador por meio do simctl; ele nunca invoca um shell do host.
As coordenadas são pontos de tela do iOS, não pixels da captura de tela. O fluxo ao vivo mantém o tamanho fixo do simulador e o coloca em letterbox em vez de redimensionar o dispositivo. A transferência de texto da área de transferência do host para o simulador e do simulador para o host usa a mesma política de permissão por usuário e por direção dos outros rigs; arquivos e imagens não são aceitos pela faixa da área de transferência do iOS.
Cada rig cria um dispositivo CoreSimulator próprio e uma sessão do WebDriverAgent. Fechá-lo interrompe o WebDriverAgent, desliga e exclui esse dispositivo e remove a sua entrada no registro. Rigs de iOS só rodam em um servidor macOS com Xcode, um runtime de iOS instalado e a ponte de automação fixada. Eles não oferecem áudio, microfone, drop de arquivos, shell do host nem garantia de rede isolada.
Ferramentas de gerenciamento
Seção intitulada “Ferramentas de gerenciamento”| Ferramenta | Descrição |
|---|---|
rig_list |
Lista os rigs de um espaço de trabalho com superfície, status, tela e controlador |
rig_close |
Destrói um rig e descarta o seu disco |
Ciclo de vida
Seção intitulada “Ciclo de vida”| Fase | Significado |
|---|---|
provisioning |
Inicializando; o detalhe do status traz a etapa atual literalmente |
ready |
Acessível e aceitando ações |
parked |
Estacionado por ociosidade: vCPUs paradas, RAM ainda residente; a próxima ação o acorda |
closing |
Desligando |
closed |
Sumiu; a linha sobrevive para a trilha de auditoria |
failed |
Morreu ou nunca subiu; distinguível para que a interface possa oferecer nova tentativa |
| Motivo de fechamento | Disparado quando |
|---|---|
requested |
Uma pessoa ou um agente pediu |
idleTimeout |
Ocioso além do dobro da janela de ociosidade, ou removido por memória |
ttlExpired |
O tempo de vida rígido acabou |
conversationEnded |
A conversa proprietária terminou |
workspaceGone |
O espaço de trabalho foi excluído ou a associação foi perdida |
serverShutdown |
O servidor está parando |
backendFailure |
O hipervisor morreu por baixo dele |
Padrões e limites máximos
Seção intitulada “Padrões e limites máximos”| Valor | Terminal | Navegador | Computador | Mobile |
|---|---|---|---|---|
| Memória | 512 MB | 2048 MB (Chromium); 2560 MB (Firefox, WebKit) | 4096 MB | 4096 MB |
| vCPUs | 2 | 2 | 4 | 4 |
| TTL rígido | 8 h | 2 h | 2 h | 2 h |
| Janela de ociosidade | 45 min | 15 min | 15 min | 15 min |
| Tela na inicialização | — | 1280×800 | 1280×800 | 1080×1920 |
- As imagens estáticas da faixa do agente têm limite de 1280×800; a faixa humana negocia até 2560×1600.
- O orçamento de memória residente do host para todos os rigs tem como padrão 12 GB, contado em megabytes residentes (uma VM estacionada ainda mantém a sua RAM). O despejo segue a ordem de uso menos recente e nunca leva uma máquina que alguém esteja operando, assistindo ou com um terminal aberto nela.
- Um terminal aberto ou uma faixa de observação impede que o rig seja estacionado ou recolhido por ociosidade; o TTL rígido continua valendo.
Portas e domínios de desenvolvimento
Seção intitulada “Portas e domínios de desenvolvimento”| Porta | Onde | Reservada para |
|---|---|---|
7911 |
Convidado do terminal | O multiplexador de portas por onde passa todo encaminhamento |
9222, 9223 |
Convidado do navegador | O relay e o endpoint de automação (o WebKit vincula a 9222 diretamente e não usa relay) |
80, 443 |
Loopback do convidado do navegador | As faixas HTTP/HTTPS do domínio de desenvolvimento |
- A descoberta consulta as portas TCP em escuta do convidado do terminal a cada ~4 s, do lado do servidor.
- No máximo 16 portas são encaminhadas automaticamente por rig; as demais são listadas no log, não encaminhadas.
- O encaminhamento do lado do host vincula ao loopback, preferindo o próprio número de porta do convidado; Compartilhar na rede local adiciona uma porta de LAN atribuída pelo SO.
- Os domínios de desenvolvimento devem corresponder a
name.testouname.localhost(minúsculas, rótulo de no máximo 63 caracteres). Um domínio mapeia para uma porta. - O HTTPS do domínio de desenvolvimento usa uma CA local do servidor (EC
P-256, em
<dataDir>/rigs/tls/, chaves 0600 e nunca em um convidado) com um certificado curinga para*.test/*.localhost. Semopensslno host, não há faixa HTTPS; o HTTP simples continua sendo roteado.
Padrões de saída de rede
Seção intitulada “Padrões de saída de rede”| Superfície | Lista de permissões padrão |
|---|---|
| Terminal | A base de desenvolvedor do sandbox (forges, registros de pacotes, provedores de modelos) + os espelhos apt do Ubuntu + o host de forge da própria worktree |
| Navegador | usectrl.dev (o site do produto) — mais os arquivos do Debian na primeira inicialização de cada motor, enquanto ele instala os seus pacotes. A página inicial é um documento file:// local e não precisa de saída de rede |
| Computador | Vazia — nega tudo — até que quem chama conceda hosts |
| Mobile | Não aplicada (rede gerenciada pelo emulador) |
Toda microVM recebe adicionalmente os hosts de registro da sua imagem, apenas para o pull. O conjunto de hosts permitidos do broker de credenciais é derivado da mesma lista de permissões: nenhum token é emitido para um host que o convidado não consegue alcançar.
Área de transferência e transferência de arquivos
Seção intitulada “Área de transferência e transferência de arquivos”Os dois sentidos de copiar/colar, e o arrasto de arquivos para dentro e para fora. Disponível para uma pessoa que opera um rig; um agente obtém a área de transferência pelos verbos acima e nenhuma transferência de arquivos (ele já tem um shell dentro do recinto).
A travessia da área de transferência é por usuário e por direção. Colar do host no rig é permitido por padrão; copiar do rig para o host pergunta (uma concessão de dez minutos, ou permitir sempre em Configurações → Servidor → Rigs → Acesso à área de transferência). As duas escolhas são independentes e nunca são uma configuração de espaço de trabalho.
| Faixa | Rota | Transporta |
|---|---|---|
| Área de transferência | GET/POST /rig/clipboard/<rigId> |
Texto, um PNG/JPEG (≤16 MB) e os caminhos no convidado dos arquivos na área de transferência |
| Arquivos | POST /rig/files/<rigId> |
Até 64 arquivos, ≤256 MB cada e ≤512 MB por drop, com um ponto de drop opcional em pixels do convidado |
| Arquivos | GET /rig/files/<rigId>?p=<base64url path> |
Os bytes de um arquivo, de volta para fora |
- HTTP, não RPC. O socket RPC fecha uma conexão em um quadro de entrada acima de 256 KB — uma proteção contra DoS correta para comandos JSON e fatal para uma captura de tela colada. Os bytes trafegam pelo mesmo tipo de rota que os quadros do rig e o áudio de reunião já usam.
- A autenticação é o alvo assinado
rig-files:<workspaceId>/<rigId>mais a associação ao espaço de trabalho — um alvo próprio, então uma URL emitida para assistir a uma máquina não pode também gravar arquivos nela. - A assunção de controle se aplica. Gravar na área de transferência e soltar arquivos são mutações e são recusados enquanto outra pessoa detém o controle; ler a área de transferência e ler um arquivo para fora são observação e não são.
- Onde os drops chegam:
~/Drops(desktop),~/drops(terminal — ao lado da worktree, nunca dentro dela, para que um drop nunca apareça como alteração não rastreada),/tmp/cc-drops(navegador). O servidor escolhe o diretório; quem chama não pode nomeá-lo. Arquivos existentes nunca são sobrescritos — um nome em conflito chega como2-name.ext. - O que o convidado recebe: uma página de navegador recebe um evento de
drop real no ponto solicitado (
Input.dispatchDragEvent); um desktop recebe os arquivos mais as suas URIs na área de transferência, porque nenhum host consegue sintetizar um arrasto XDND em um toolkit arbitrário sem um daemon privilegiado dentro do convidado. A resposta diz qual dos dois aconteceu. - Arrastar para fora funciona apenas no desktop e lê a
XdndSelectiondo convidado enquanto um arrasto está em andamento. Um payload idêntico ao que o convidado já continha quando o pressionar começou é tratado como uma seleção obsoleta de um arrasto concluído, não como uma nova — o X não tem uma etapa de “o arrasto acabou”. - Requisitos da imagem: a imagem de desktop deve ser do protocolo 2 ou posterior (compilada depois que o suporte à área de transferência chegou). Uma imagem mais antiga responde 404 e o app diz para recompilá-la em vez de relatar uma máquina quebrada.
- O log de auditoria registra a forma, nunca o conteúdo: as linhas de
clipboard_read,clipboard_write,drop_fileseread_filetrazem contagens, tamanhos e caminhos. A área de transferência é onde credenciais vivem por alguns segundos de cada vez, e nada disso é registrado por escrito.
Barreiras, eventos e armazenamento
Seção intitulada “Barreiras, eventos e armazenamento”- As ferramentas de rig declaram a classe de ação
enclosureControl(maisnetworkEgresseprocessSpawnnas ferramentas de uso;mobile_useeios_usetambém declarampackageInstall).rig_closedeclaraenclosureControl;rig_listnão declara nenhuma. Permitida por padrão; os modos somente leitura a negam por completo; o dial de autonomia por espaço pode rebaixá-la para perguntar antes. - Eventos de domínio:
RigClosedEvent(com o seu motivo de fechamento),RigControlChanged(assunção/devolução de controle),RigReaped(ociosidade, TTL ou despejo por memória, com o agente que a operava). Abrir um rig não é um evento. Consulte eventos de domínio. - Armazenamento:
rig_sessionserig_action_logno banco de dados de cada espaço de trabalho. O log de ações registra todo evento de entrada com o seu principal e uma sequência monotônica por rig; o texto digitado é reduzido a um comprimento e um hash antes de ser gravado. - Diretório de dados:
rigs/images/(imagens qcow2 importadas),rigs/smolvm/(estado de runtime por rig),rigs/smolvm-packs/(pacotes de máquina pré-extraídos),rigs/tls/(a CA do domínio de desenvolvimento),rigs/run/(overlays e seeds do QEMU). - Rotas: a visualização ao vivo é uma aba em uma página de espaço ou de PR;
/settings/server/rigsé a tela de configurações de Rigs.