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 Impulsado por Backend Valor Salida contenida
Terminal (exec) Un shell sobre el canal exec de la VM microVM smolvm Sí
Navegador Chromium sin interfaz gráfica (CDP), Firefox (WebDriver BiDi) o WebKit (W3C WebDriver) microVM smolvm Sí
Ordenador Escritorio X11: entrada a través del hipervisor, captura a través del agente del huésped QEMU qemu-hvf (macOS), qemu-kvm (Linux), qemu-tcg (alternativa sin aceleración, nunca elegida 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 al Mac anfitrión

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

Motor Valor Protocolo Vista en directo Imágenes estáticas
Chromium chromium (predeterminado) Chrome DevTools Protocol Transmisión continua: el navegador envía fotogramas a medida que la página se vuelve a pintar 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 en paralelo: abrir «Firefox (VM)» junto a «Chromium (VM)» son dos máquinas, y cerrar una deja la otra en marcha.

Pasa engine a rig.open o a la herramienta browser_use. Un nombre desconocido se rechaza en lugar de aplicarse por defecto: pedir un navegador y recibir otro en silencio responde a 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 evite la caché (rechaza ignoreCache de BiDi de plano), así que una recarga forzada es una recarga normal.
  • WebKit tampoco tiene recarga que evite la caché ni flujo de consola (la salida se captura enganchando console.* después de cada navegación, así que todo lo registrado durante la carga se pierde —cada extracción de consola lo dice—), y necesita ffmpeg en el host para su vista en directo.
  • 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 acepta un soltado de archivo real; aun así, se puede apuntar una entrada de archivo a rutas dentro de la máquina.
Superficie Imagen Obtención
Terminal ubuntu:24.04, fijada por digest Automáticamente en el primer arranque, a través de la propia red controlada de la máquina
Navegador (Chromium, Firefox, WebKit) debian:trixie-slim, fijada por digest, más los propios paquetes del motor Automáticamente en el primer arranque, y luego se guarda en caché como paquete precalentado
Ordenador Una imagen de escritorio qcow2 con Chromium, Firefox, WebKit y la misma línea base 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 se publican)
Android Las imágenes de sistema de Google A través del SDK de Android
iOS Un runtime del Simulador de Xcode más WebDriverAgent fijado por suma de comprobación El runtime a través de Xcode; el puente de automatización desde Ajustes → Servidor → Rigs

Tras el primer arranque de cada tipo de microVM, el servidor guarda en caché una copia ya extraída en el directorio de datos y arranca a partir de ella todas las máquinas posteriores, incluidas las imágenes precalentadas con los paquetes ya instalados. El terminal precalienta un conjunto de herramientas CLI al estilo de un runner alojado en GitHub (git, gcc, python3, jq, rsync, herramientas de archivo y el resto de la línea base de apt; no Docker ni cachés de herramientas por lenguaje). El qcow2 de Ordenador 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 precompilada que merezca la pena: chromedp/headless-shell de Chromium compila ALSA y PulseAudio fuera, así que nunca puede emitir sonido; la única de Firefox que se mantiene es 33× el tamaño de la base Debian y aun así no incluye socat; y de WebKit no hay ninguna mantenida. Así que cada motor se instala en el primer arranque (chromium, firefox-esr o webkit2gtk-driver) y, mientras lo hace, llega a los archivos de Debian (deb.debian.org, security.debian.org, cloudfront.debian.net). Chromium es el binario de la distribución, lanzado 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 Sustituye a
rigs.smolvm.execImage La imagen de la Terminal (VM)
rigs.smolvm.browserImage La imagen del Navegador (VM) de Chromium

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 no válido se ignora de forma ruidosa y en su lugar arranca el valor predeterminado. El registro propio de la imagen (más los acompañantes conocidos de CDN de blobs 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 y socat preinstalados o una base apt de Debian/Ubuntu (el recinto instala esos tres más un conjunto de herramientas CLI al estilo de un runner alojado en GitHub en el primer arranque: compiladores, Python 3, jq, herramientas de archivo, 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 lanza é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 compila ALSA y PulseAudio fuera, así que ese binario no puede emitir sonido. La sustitució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 lanzaría un binario que no está ahí. Un rig de Firefox o WebKit la 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: DevTools de Chromium y el agente remoto de Firefox están en el loopback del huésped 9223 con un relé socat delante (ambos enlazan el loopback incondicionalmente); el controlador de WebKit acepta un --host y enlaza él mismo la NIC del huésped. Firefox, además, valida la cabecera Host contra su propio puerto, así que el cliente envía la autoridad del lado del huésped en lugar de la que marcó.

Toda 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 ortografía de X11 (ctrl+s, alt+Tab, Return).

clipboard_read recibe una selection: clipboard (lo que rellena ctrl+C, el valor predeterminado), primary (la selección para copiar de X11) o xdnd (un arrastre en curso). Un resultado vacío es una respuesta normal para las tres. clipboard_write solo recibe 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 contenido no confiable.

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 contenido no confiable.

El navegador tiene exactamente un portapapeles, así que clipboard_read no recibe selection. Los dos 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 de uno vacío; usa type ahí, que inserta en el punto de inserción sin pasar por el 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 (confinado 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 recibe 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 aplicación con el foco puede leer el portapapeles.

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

Las coordenadas son puntos de la pantalla de iOS, no píxeles de la captura de pantalla. La transmisión en directo mantiene el tamaño fijo del simulador y lo ajusta con bandas negras en lugar de redimensionar el dispositivo. La transferencia de texto del portapapeles del host al simulador y del simulador al 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 borra su entrada del registro. Los rigs de iOS solo se ejecutan en un servidor macOS con Xcode, un runtime 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 contenida.

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 de estado reproduce el paso actual literalmente
ready Accesible y aceptando acciones
parked En pausa por inactividad: vCPU detenidas, la RAM sigue 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 llegó a arrancar; distinguible para que la interfaz pueda ofrecer reintentar
Motivo de cierre Se activa cuando
requested Lo pidió una persona o un agente
idleTimeout Inactivo más de 2× la ventana de inactividad, o desalojado 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 pertenencia
serverShutdown El servidor se está deteniendo
backendFailure El hipervisor murió por debajo
Valor Terminal Navegador Ordenador 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 están limitadas 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 por defecto, contado en megabytes residentes (una VM en pausa sigue ocupando su RAM). El desalojo es por menos usada recientemente y nunca se lleva una máquina que alguien está dirigiendo, observando o en la que tiene un terminal abierto.
  • Un terminal abierto o un canal de observación fija el rig contra la pausa y la recolección 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 todo reenvío
9222, 9223 Huésped del navegador El relé y el endpoint de automatización (WebKit enlaza 9222 directamente y no usa relé)
80, 443 Loopback del huésped del navegador Los canales HTTP/HTTPS de dominios de desarrollo
  • El descubrimiento sondea cada ~4 s los puertos TCP a la escucha del huésped del terminal, en el lado del servidor.
  • Se reenvían automáticamente como máximo 16 puertos por rig; los demás se listan en el registro, no se reenvían.
  • El reenvío del lado del host enlaza el loopback y prefiere el número de puerto propio del huésped; Compartir en la red local añade un puerto de LAN asignado por el sistema operativo.
  • Los dominios de desarrollo deben coincidir con name.test o name.localhost (en minúsculas, etiqueta de 63 caracteres como máximo). Cada dominio se asigna a un puerto.
  • El HTTPS de dominios 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 único certificado comodín para *.test / *.localhost. Sin openssl en el host no hay canal HTTPS; el HTTP simple sigue enrutándose.
Superficie Lista de permitidos predeterminada
Terminal La línea base de desarrollador del entorno aislado (hosts de código, registros de paquetes, proveedores de modelos) + los espejos apt de Ubuntu + el propio host de código 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 local file:// y no necesita salida
Ordenador Vacía — se deniega todo — hasta que quien llama concede hosts
Móvil No se aplica (la red la gestiona el emulador)

Además, cada microVM recibe 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 que el huésped no puede alcanzar.

Copiar y pegar en ambos sentidos, y arrastrar archivos hacia dentro y hacia fuera. Disponible para una persona que dirige un rig; un agente obtiene el portapapeles a través de 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 permitir siempre en Ajustes → Servidor → Rigs → Acceso al portapapeles). Las dos opciones son independientes y nunca son una configuración de espacio de trabajo.

Carril Ruta Transporta
Portapapeles GET/POST /rig/clipboard/<rigId> Texto, un PNG/JPEG (≤16 MB) y las rutas en el huésped de los archivos que hay 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
  • HTTP, no RPC. El socket RPC cierra una conexión ante una trama entrante de más de 256 KB —una protección 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 del rig y el audio de las reuniones.
  • La autenticación es el destino firmado rig-files:<workspaceId>/<rigId> más la pertenencia al espacio de trabajo: un destino propio, de modo que una URL emitida para observar una máquina tampoco puede escribirle archivos.
  • La toma de control se aplica. Escribir el portapapeles y soltar archivos son operaciones que mutan y se rechazan mientras otra persona tiene el control; leer el portapapeles y extraer un archivo son observación y no se rechazan.
  • Dónde acaban los soltados: ~/Drops (escritorio), ~/drops (terminal — junto al worktree, nunca dentro, para que un soltado no aparezca nunca como un cambio sin seguimiento), /tmp/cc-drops (navegador). El servidor elige el directorio; quien llama no puede nombrarlo. Los archivos existentes nunca se sobrescriben: un nombre que colisiona acaba como 2-name.ext.
  • Qué se le dice 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 las dos cosas ha ocurrido.
  • Arrastrar hacia fuera solo funciona en el escritorio y lee la XdndSelection del huésped mientras el arrastre está en curso. Una carga útil idéntica a la que el huésped ya tenía cuando empezó la pulsación se trata como una selección obsoleta de un arrastre terminado, no como una nueva: X no tiene ningún paso de «el arrastre ha terminado».
  • Requisitos de la imagen: la imagen de escritorio debe ser de protocolo 2 o posterior (compilada después de que llegara el soporte de portapapeles). Una imagen más antigua responde 404 y la aplicación pide recompilarla en lugar de informar de una máquina averiada.
  • El registro de auditoría anota 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 cada vez, y nada de eso se escribe.
  • Las herramientas de rig 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. Permitidas de forma predeterminada; los modos de solo lectura las deniegan por completo; el dial de autonomía por espacio puede rebajarlas a preguntar primero.
  • Eventos de dominio: RigClosedEvent (con su motivo de cierre), RigControlChanged (toma de control / devolución), RigReaped (desalojo por inactividad, TTL o memoria, con el agente que la 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 reduce a una longitud y un hash antes de guardarse.
  • 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 de dominios de desarrollo), rigs/run/ (superposiciones y semillas de QEMU).
  • Rutas: la vista en directo es una pestaña en un espacio o una página de PR; /settings/server/rigs es la pantalla de configuración de Rigs.