Rigs
Solo hechos. Para el modelo que hay detrás, lee Rigs y recintos; para abrir una máquina, sigue la guía.
Superficies y backends
Sección titulada «Superficies y backends»| 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.
Motores de navegador
Sección titulada «Motores de navegador»| 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
ignoreCachede 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 necesitaffmpegen 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.
Imágenes de máquina
Sección titulada «Imágenes de 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ó.
Verbos de acción
Sección titulada «Verbos de acción»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.
computer_use
Sección titulada «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.
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.
browser_use
Sección titulada «browser_use»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.
mobile_use
Sección titulada «mobile_use»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.
ios_use
Sección titulada «ios_use»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.
Herramientas de administración
Sección titulada «Herramientas de administración»| 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 |
Ciclo de vida
Sección titulada «Ciclo de vida»| 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 |
Valores predeterminados y máximos
Sección titulada «Valores predeterminados y máximos»| 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.
Puertos y dominios de desarrollo
Sección titulada «Puertos y dominios de desarrollo»| 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.testoname.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 hayopensslen el host, no hay canal HTTPS; el HTTP simple sigue enrutándose.
Salidas de red predeterminadas
Sección titulada «Salidas de red predeterminadas»| 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.
Portapapeles y transferencia de archivos
Sección titulada «Portapapeles y transferencia de archivos»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 como2-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
XdndSelectiondel 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_filesyread_filellevan recuentos, tamaños y rutas. Un portapapeles es donde las credenciales viven unos segundos a la vez, y nada de eso queda escrito.
Barandillas, eventos y almacenamiento
Sección titulada «Barandillas, eventos y almacenamiento»- Las herramientas de rigs declaran la clase de acción
enclosureControl(másnetworkEgressyprocessSpawnen las herramientas de uso;mobile_useeios_usetambién declaranpackageInstall).rig_closedeclaraenclosureControl;rig_listno 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_sessionsyrig_action_logen 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/rigses la pantalla de configuración de Rigs.