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 | 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.
Motores de navegador
Sección titulada «Motores de navegador»| 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
ignoreCachede 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 necesitaffmpegen 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.
Imágenes de máquina
Sección titulada «Imágenes de 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ó.
Verbos de acción
Sección titulada «Verbos de acción»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.
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 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.
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 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.
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
(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.
ios_use
Sección titulada «ios_use»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.
Herramientas de gestión
Sección titulada «Herramientas de gestió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 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 |
Valores predeterminados y límites
Sección titulada «Valores predeterminados y límites»| 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.
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 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.testoname.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. Sinopensslen el host no hay canal HTTPS; el HTTP simple sigue enrutándose.
Valores predeterminados de salida
Sección titulada «Valores predeterminados de salida»| 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.
Portapapeles y transferencia de archivos
Sección titulada «Portapapeles y transferencia de archivos»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 como2-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
XdndSelectiondel 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_filesyread_filellevan recuentos, tamaños y rutas. Un portapapeles es donde las credenciales viven unos segundos cada vez, y nada de eso se escribe.
Barandillas, eventos y almacenamiento
Sección titulada «Barandillas, eventos y almacenamiento»- Las herramientas de rig declaran la clase de acción
enclosureControl(másnetworkEgressyprocessSpawnen las herramientas de uso;mobile_useeios_usetambién declaranpackageInstall).rig_closedeclaraenclosureControl;rig_listno 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_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 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/rigses la pantalla de configuración de Rigs.