Ir al contenido

Rigs

Solo hechos. Para el modelo que hay detrás, lee Rigs y recintos; para abrir una máquina, sigue la guía.

Superficie Dirige Backend Valor Salida de red contenida
Terminal (exec) Un shell sobre el canal de ejecución de la VM microVM smolvm Sí
Navegador Chromium sin interfaz gráfica (CDP), Firefox (WebDriver BiDi) o WebKit (W3C WebDriver) microVM smolvm Sí
Computadora Escritorio X11: entrada mediante el hipervisor, captura mediante el agente del huésped QEMU qemu-hvf (macOS), qemu-kvm (Linux), qemu-tcg (alternativa sin aceleración, nunca se elige automáticamente) Sí
Android Android sobre ADB El emulador de Google android-emulator No — el emulador gestiona su propia red
iOS Simulador de iOS a través de WebDriverAgent CoreSimulator ios-simulator No — la red sigue a la Mac anfitriona

El terminal y la superficie computer_use comparten el valor de superficie computer; el terminal se distingue por su marcador de imagen de ejecución y nunca se reutiliza como escritorio que se pueda dirigir (ni al revés). Una conversación reutiliza una máquina de terminal.

Motor Valor Protocolo Vista en vivo Imágenes estáticas
Chromium chromium (predeterminado) Chrome DevTools Protocol Transmisión continua: el navegador empuja fotogramas a medida que la página se vuelve a dibujar JPEG
Firefox firefox WebDriver BiDi Imágenes estáticas por sondeo (BiDi no tiene transmisión continua), limitadas a 6 fps JPEG
WebKit webkit W3C WebDriver (clásico) Imágenes estáticas por sondeo, transcodificadas por el ffmpeg del host PNG

Un rig ejecuta un solo motor durante toda su vida. Una conversación puede tener un rig por motor, que es lo que hace posible una comparación lado a lado: abrir «Firefox (VM)» junto a «Chromium (VM)» son dos máquinas, y cerrar una deja la otra en ejecución.

Pasa engine a rig.open o a la herramienta browser_use. Un nombre desconocido se rechaza en lugar de tomar el valor predeterminado: pedir un navegador y recibir otro en silencio responde una pregunta de compatibilidad con la respuesta equivocada.

Límites específicos de cada motor, declarados en lugar de sorteados:

  • Firefox no tiene recarga que omita la caché (rechaza directamente el ignoreCache de BiDi), así que una recarga forzada es una recarga normal.
  • WebKit tampoco tiene recarga que omita la caché ni fuente de consola (la salida se captura enganchando console.* después de cada navegación, así que todo lo que se registra durante la carga se pierde: cada extracción de consola lo dice), y necesita ffmpeg en el host para su vista en vivo.
  • Ninguno de los dos expone un árbol de accesibilidad de la plataforma por su protocolo, así que extract (a11y) devuelve una aproximación derivada del DOM, etiquetada como tal.
  • Ninguno de los dos puede recibir un soltado de archivos real; aun así se puede apuntar una entrada de archivo a rutas dentro de la máquina.
Superficie Imagen Cómo se obtiene
Terminal ubuntu:24.04, fijada por digest Automáticamente en el primer arranque, a través de la propia red restringida de la máquina
Navegador (Chromium, Firefox, WebKit) debian:trixie-slim, fijada por digest, más los paquetes propios del motor Automáticamente en el primer arranque, y luego se guarda en caché como paquete precalentado
Computadora Una imagen de escritorio qcow2 con Chromium, Firefox, WebKit y la misma base de herramientas de CLI al estilo de un runner alojado en GitHub que precalienta el terminal Importar en Ajustes → Servidor → Rigs (descargas fijadas por suma de comprobación cuando están publicadas)
Android Las imágenes de sistema de Google Mediante el SDK de Android
iOS Un entorno de ejecución de Xcode Simulator más WebDriverAgent fijado por suma de comprobación El entorno de ejecución mediante Xcode; el puente de automatización, desde Ajustes → Servidor → Rigs

Después del primer arranque de cada tipo de microVM, el servidor guarda en caché una copia ya extraída bajo el directorio de datos y arranca desde ella todas las máquinas posteriores, incluidas las imágenes precalentadas con los paquetes ya instalados. El terminal precalienta un conjunto de herramientas de CLI al estilo de un runner alojado en GitHub (git, gcc, python3, jq, rsync, herramientas de archivado y el resto de la base de apt; no Docker ni cachés de herramientas por lenguaje). El qcow2 de Computadora incorpora esos mismos nombres de CLI al compilar la imagen, junto a XFCE y los tres navegadores. Cada navegador precalienta su motor. Los tres motores comparten una base Debian, pero nunca comparten un paquete: la caché se indexa por la imagen, el motor y una revisión de audio (audio-v1-<engine>), porque una máquina precalentada para un motor —o antes de que PulseAudio y ffmpeg formaran parte de la carga de trabajo— no tiene nada del otro. El paquete del terminal se indexa por una revisión del conjunto de herramientas (tools-v1) por la misma razón: un paquete precalentado antes de que el compilador formara parte de la imagen no debe servir a una máquina que se supone que lo tiene.

No hay ninguna imagen de automatización preconstruida que valga la pena tomar: el chromedp/headless-shell de Chromium deja fuera ALSA y PulseAudio en la compilación, así que nunca puede emitir sonido; la única de Firefox que se mantiene tiene 33× el tamaño de la base Debian y aun así no incluye socat; y no hay ninguna de WebKit que se mantenga. Así que cada motor se instala en el primer arranque (chromium, firefox-esr o webkit2gtk-driver) y mientras lo hace accede a los archivos de Debian (deb.debian.org, security.debian.org, cloudfront.debian.net). Chromium es el binario de la distribución que se inicia como chromium --headless=new.

Imágenes personalizadas por espacio de trabajo

Sección titulada «Imágenes personalizadas por espacio de trabajo»
Clave de configuración Sobrescribe
rigs.smolvm.execImage La imagen de la Terminal (VM)
rigs.smolvm.browserImage La imagen del Navegador Chromium (VM)

Se escriben a través del almacén de configuración del espacio de trabajo restringido a administradores (Ajustes → Servidor → Rigs → Imágenes personalizadas (este espacio de trabajo)). El valor debe ser una referencia de registro: las rutas locales, los archivos y las cadenas que parecen opciones se rechazan, tanto en el campo como de nuevo al arrancar. Un valor almacenado inválido se ignora de forma ruidosa y en su lugar arranca el predeterminado. El propio registro de la imagen (más los acompañantes de CDN de blobs conocidos para Docker Hub, GHCR, Quay, GitLab y GCR) se admite a través de la puerta de salida para la descarga.

Contrato de la imagen de terminal — bash presente; git, curl, socat preinstalados o una base apt de Debian/Ubuntu (el recinto instala esos tres más un conjunto de herramientas de CLI al estilo de un runner alojado en GitHub en el primer arranque: compiladores, Python 3, jq, herramientas de archivado, rsync. Las cachés de herramientas por lenguaje y Docker no se instalan).

Contrato de la imagen de navegador — una base apt de Debian/Ubuntu (o los paquetes ya instalados) con bash y socat, más un binario chromium que el servidor inicia él mismo como chromium --headless=new con DevTools en el loopback del huésped 9223, retransmitido al puerto del huésped 9222. PulseAudio y ffmpeg se instalan en el primer arranque para el canal de audio. No compiles FROM chromedp/headless-shell: el headless.gn de aguas arriba deja fuera ALSA y PulseAudio en la compilación, así que ese binario no puede emitir sonido. La anulación se aplica solo a los rigs de Chromium: el comando de carga de trabajo que arranca es el de Chromium, y entregárselo a Firefox o WebKit iniciaría un binario que no está ahí. Un rig de Firefox o de WebKit lo ignora de forma ruidosa y arranca su imagen fijada.

Puertos de automatización — cada máquina de navegador reenvía exactamente un puerto de loopback del host al 9222 del huésped. Detrás de él: los DevTools de Chromium y el agente remoto de Firefox se sitúan en el loopback del huésped 9223 con un relé socat delante (ambos enlazan loopback incondicionalmente); el controlador de WebKit toma un --host y enlaza él mismo la NIC del huésped. Firefox además valida el encabezado Host contra su propio puerto, así que el cliente envía la autoridad del lado del huésped en lugar de la que marcó.

Cada acción se analiza de forma total: una carga útil mal formada devuelve un mensaje que nombra el campo, nunca una excepción. Los verbos de observación (marcados con ○) siguen permitidos mientras una persona tiene el control; los verbos que mutan se rechazan.

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.

Las coordenadas son píxeles del huésped en el modo actual del huésped; cada captura de pantalla indica el tamaño de la pantalla. Las combinaciones de teclas usan la notación de X11 (ctrl+s, alt+Tab, Return).

clipboard_read toma una selection: clipboard (lo que llena ctrl+C, el valor predeterminado), primary (seleccionar para copiar de X11) o xdnd (un arrastre en curso). Un resultado vacío es una respuesta normal para las tres. clipboard_write solo toma text: las imágenes y los archivos viajan por el canal de archivos, porque los argumentos de una acción se conservan en el registro de auditoría y los bytes de una imagen no tienen nada que hacer ahí. El contenido del portapapeles vuelve delimitado como datos no confiables.

navigate (solo http/https), reload (hard opcional), stop_loading, click (selector o coordenada), fill, type, key (nombres de teclas del 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○ (selector, 0.1–30 s), clipboard_read○, clipboard_write.

El contenido de página extraído vuelve delimitado como datos no confiables.

El navegador tiene exactamente un portapapeles, así que clipboard_read no toma selection. Ambos verbos de portapapeles necesitan un contexto seguro: una página servida por http:// simple no tiene ninguna API de portapapeles, y el verbo lo dice en lugar de informar uno vacío; usa type ahí, que inserta en el punto de inserción sin pasar por un portapapeles.

tap, swipe (50–5000 ms), type, key (alias back, home, recents, enter, delete, backspace, tab, escape, search, menu, volume_up, volume_down, power, o cualquier KEYCODE_*), screenshot○, ui_dump○, install_apk (restringido al worktree del rig y al directorio de datos del servidor), start_app, stop_app, clear_app_data, uninstall_app, open_url y shell. shell toma una lista argv y se ejecuta dentro de Android, nunca a través de un shell del host; cubre diagnósticos de desarrollador como logcat, dumpsys y pm grant.

mobile_use no tiene verbos de portapapeles. Desde Android 10, solo la app que tiene el foco puede leer el portapapeles.

tap, swipe (50–5000 ms), type, key (enter, backspace, tab, escape, teclas de flecha o un solo carácter imprimible; con los modificadores opcionales command, control, option y shift), home, lock, unlock, screenshot○, ui_dump○, install_app (un directorio .app del simulador restringido al worktree del rig o al directorio de datos del servidor), start_app, stop_app, uninstall_app, open_url y spawn. spawn toma argv y se ejecuta dentro del simulador a través de simctl; nunca invoca un shell del host.

Las coordenadas son puntos de pantalla de iOS, no píxeles de la captura de pantalla. La transmisión en vivo conserva el tamaño fijo del simulador y lo muestra con barras negras en lugar de cambiar el tamaño del dispositivo. La transferencia de texto del portapapeles de host a simulador y de simulador a host usa la misma política de permisos por usuario y por dirección que los demás rigs; el canal del portapapeles de iOS no acepta archivos ni imágenes.

Cada rig crea un dispositivo CoreSimulator propio y una sesión de WebDriverAgent. Cerrarlo detiene WebDriverAgent, apaga y elimina ese dispositivo, y quita su entrada del registro. Los rigs de iOS solo se ejecutan en un servidor macOS con Xcode, un entorno de ejecución de iOS instalado y el puente de automatización fijado. No ofrecen audio, micrófono, soltado de archivos, shell del host ni garantía de red cerrada.

Herramienta Descripción
rig_list Lista los rigs de un espacio de trabajo con su superficie, estado, pantalla y controlador
rig_close Destruye un rig y descarta su disco
Fase Significado
provisioning Arrancando; el detalle del estado lleva el paso actual tal cual
ready Accesible y acepta acciones
parked En pausa por inactividad: las vCPU detenidas, la RAM aún residente; la siguiente acción lo despierta
closing Apagándose
closed Ya no existe; la fila se conserva para el registro de auditoría
failed Murió o nunca arrancó; se distingue para que la interfaz pueda ofrecer reintentar
Motivo de cierre Se activa cuando
requested Una persona o un agente lo pidió
idleTimeout Lleva inactivo más de 2× la ventana de inactividad, o se expulsó por memoria
ttlExpired Se agotó el tiempo de vida máximo
conversationEnded Terminó la conversación propietaria
workspaceGone Se eliminó el espacio de trabajo o se perdió la membresía
serverShutdown El servidor se está deteniendo
backendFailure El hipervisor murió por debajo
Valor Terminal Navegador Computadora Móvil
Memoria 512 MB 2048 MB (Chromium); 2560 MB (Firefox, WebKit) 4096 MB 4096 MB
vCPU 2 2 4 4
TTL máximo 8 h 2 h 2 h 2 h
Ventana de inactividad 45 min 15 min 15 min 15 min
Pantalla al arrancar — 1280×800 1280×800 1080×1920
  • Las imágenes estáticas del canal del agente se limitan a 1280×800; el canal humano negocia hasta 2560×1600.
  • El presupuesto de memoria residente del host para todos los rigs es de 12 GB de forma predeterminada, contado en megabytes residentes (una VM en pausa sigue ocupando su RAM). La expulsión sigue el criterio de la menos usada recientemente y nunca se lleva una máquina que alguien esté dirigiendo, observando o en la que tenga abierto un terminal.
  • Un terminal abierto o un canal de visualización fija el rig e impide que se ponga en pausa y que se recoja por inactividad; el TTL máximo sigue aplicándose.
Puerto Dónde Reservado para
7911 Huésped del terminal El multiplexor de puertos por el que viaja cada reenvío
9222, 9223 Huésped del navegador El relé y el extremo de automatización (WebKit enlaza 9222 directamente y no usa relé)
80, 443 Loopback del huésped del navegador Los canales HTTP/HTTPS del dominio de desarrollo
  • El descubrimiento sondea los puertos TCP en escucha del huésped del terminal cada ~4 s, del lado del servidor.
  • Como máximo se reenvían automáticamente 16 puertos por rig; los demás se listan en el registro, no se reenvían.
  • El reenvío del lado del host enlaza loopback y prefiere el propio número de puerto del huésped; Compartir en la red local agrega un puerto de LAN asignado por el sistema operativo.
  • Los dominios de desarrollo deben coincidir con name.test o name.localhost (en minúsculas, con una etiqueta de 63 caracteres como máximo). Un dominio se asigna a un puerto.
  • El HTTPS del dominio de desarrollo usa una CA local del servidor (EC P-256, en <dataDir>/rigs/tls/, claves 0600 y nunca dentro de un huésped) con un certificado hoja comodín para *.test / *.localhost. Si no hay openssl en el host, no hay canal HTTPS; el HTTP simple sigue enrutándose.
Superficie Lista de permitidos predeterminada
Terminal La base de desarrollador del sandbox (forjas, registros de paquetes, proveedores de modelos) + los espejos apt de Ubuntu + el propio host de forja del worktree
Navegador usectrl.dev (el sitio del producto), más los archivos de Debian en el primer arranque de cada motor, mientras instala sus paquetes. La página de inicio es un documento file:// local y no necesita salida
Computadora Vacía —se deniega todo— hasta que quien llama conceda hosts
Móvil No se aplica (red gestionada por el emulador)

Cada microVM recibe además los hosts de registro de su imagen, solo para la descarga. El conjunto de hosts permitidos del bróker de credenciales se deriva de la misma lista de permitidos: no se emite ningún token para un host al que el huésped no pueda llegar.

Ambas direcciones de copiar y pegar, y arrastrar archivos hacia dentro y hacia fuera. Disponible para una persona que dirige un rig; un agente obtiene el portapapeles mediante los verbos anteriores y ninguna transferencia de archivos (ya tiene un shell dentro del recinto).

El cruce del portapapeles es por usuario y por dirección. Pegar del host al rig está permitido de forma predeterminada; copiar del rig al host pregunta primero (un permiso de diez minutos, o permite siempre en Ajustes → Servidor → Rigs → Acceso al portapapeles). Las dos opciones son independientes y nunca son una configuración de espacio de trabajo.

Canal Ruta Transporta
Portapapeles GET/POST /rig/clipboard/<rigId> Texto, un PNG/JPEG (≤16 MB) y las rutas del huésped de los archivos que están en el portapapeles
Archivos POST /rig/files/<rigId> Hasta 64 archivos, ≤256 MB cada uno y ≤512 MB por soltado, con un punto de soltado opcional en píxeles del huésped
Archivos GET /rig/files/<rigId>?p=<base64url path> Los bytes de un archivo, de vuelta hacia fuera
  • HTTP, no RPC. El socket RPC cierra una conexión ante un fotograma entrante de más de 256 KB: una defensa contra DoS que es correcta para comandos JSON y fatal para una captura de pantalla pegada. Los bytes viajan por el mismo tipo de ruta que ya usan los fotogramas de los rigs y el audio de las reuniones.
  • La autenticación es el destino firmado rig-files:<workspaceId>/<rigId> más la membresía del espacio de trabajo: un destino propio, de modo que una URL emitida para observar una máquina tampoco pueda escribirle archivos.
  • La toma de control aplica. Escribir en el portapapeles y soltar archivos mutan, así que se rechazan mientras otra persona tiene el control; leer el portapapeles y extraer un archivo son observación y no se rechazan.
  • Dónde caen los soltados: ~/Drops (escritorio), ~/drops (terminal: junto al worktree, nunca dentro, así que un soltado nunca aparece como un cambio sin seguimiento), /tmp/cc-drops (navegador). El servidor elige el directorio; quien llama no puede nombrarlo. Nunca se sobrescriben los archivos existentes: un nombre que colisiona llega como 2-name.ext.
  • Qué se le indica al huésped: una página de navegador recibe un evento de soltado real en el punto solicitado (Input.dispatchDragEvent); un escritorio recibe los archivos más sus URI en su portapapeles, porque ningún host puede sintetizar un arrastre XDND hacia un conjunto de herramientas arbitrario sin un demonio privilegiado dentro del huésped. La respuesta indica cuál de los dos ocurrió.
  • Arrastrar hacia fuera solo funciona en el escritorio y lee la XdndSelection del huésped mientras un arrastre está activo. Una carga útil idéntica a la que el huésped ya tenía cuando comenzó la pulsación se trata como una selección obsoleta de un arrastre terminado, no como una nueva: X no tiene un paso de «el arrastre terminó».
  • Requisitos de la imagen: la imagen de escritorio debe ser de protocolo 2 o posterior (compilada después de que se agregara el soporte de portapapeles). Una imagen anterior responde 404 y la app indica que se vuelva a compilar en lugar de informar una máquina averiada.
  • El registro de auditoría guarda la forma, nunca el contenido: las filas de clipboard_read, clipboard_write, drop_files y read_file llevan recuentos, tamaños y rutas. Un portapapeles es donde las credenciales viven unos segundos a la vez, y nada de eso queda escrito.
  • Las herramientas de rigs declaran la clase de acción enclosureControl (más networkEgress y processSpawn en las herramientas de uso; mobile_use e ios_use también declaran packageInstall). rig_close declara enclosureControl; rig_list no declara ninguna. Permitida de forma predeterminada; los modos de solo lectura la deniegan por completo; el control de autonomía de cada espacio puede degradarla a preguntar primero.
  • Eventos de dominio: RigClosedEvent (con su motivo de cierre), RigControlChanged (toma de control / devolución del control), RigReaped (inactividad, TTL o expulsión por memoria, con el agente que lo dirigía). Abrir un rig no es un evento. Consulta eventos de dominio.
  • Almacenamiento: rig_sessions y rig_action_log en la base de datos de cada espacio de trabajo. El registro de acciones guarda cada evento de entrada con su principal y una secuencia monótona por rig; el texto escrito se censura a una longitud y un hash antes de escribirse.
  • Directorio de datos: rigs/images/ (imágenes qcow2 importadas), rigs/smolvm/ (estado de ejecución por rig), rigs/smolvm-packs/ (paquetes de máquina ya extraídos), rigs/tls/ (la CA del dominio de desarrollo), rigs/run/ (superposiciones y semillas de QEMU).
  • Rutas: la vista en vivo es una pestaña en la página de un espacio o de una PR; /settings/server/rigs es la pantalla de configuración de Rigs.