Rig
Solo fatti. Per il modello che sta dietro, leggi Rig e recinti; per aprire una macchina, segui la guida.
Superfici e backend
Sezione intitolata “Superfici e backend”| Superficie | Guida | Backend | Valore | Uscita in rete contenuta |
|---|---|---|---|---|
| Terminale (exec) | Una shell sul canale exec della VM | microVM | smolvm |
Sì |
| Browser | Chromium headless (CDP), Firefox (WebDriver BiDi) o WebKit (W3C WebDriver) | microVM | smolvm |
Sì |
| Computer | Desktop X11: input tramite l’hypervisor, cattura tramite l’agente del guest | QEMU | qemu-hvf (macOS), qemu-kvm (Linux), qemu-tcg (fallback non accelerato, mai scelto automaticamente) |
Sì |
| Android | Android tramite ADB | L’emulatore di Google | android-emulator |
No — l’emulatore gestisce la propria rete |
| iOS | Simulatore iOS tramite WebDriverAgent | CoreSimulator | ios-simulator |
No — la rete segue il Mac host |
Il terminale e la superficie computer_use condividono il valore di superficie
computer; il terminale si distingue per il marcatore dell’immagine exec e non
viene mai riutilizzato come desktop pilotabile (né viceversa). Una
conversazione riutilizza una sola macchina del terminale.
Motori dei browser
Sezione intitolata “Motori dei browser”| Motore | Valore | Protocollo | Vista dal vivo | Fermoimmagine |
|---|---|---|---|---|
| Chromium | chromium (predefinito) |
Chrome DevTools Protocol | Screencast — il browser invia i frame mentre la pagina si ridisegna | JPEG |
| Firefox | firefox |
WebDriver BiDi | Fermoimmagine per polling (BiDi non ha screencast), limitati a 6 fps | JPEG |
| WebKit | webkit |
W3C WebDriver (classico) | Fermoimmagine per polling, transcodificati dall’ffmpeg dell’host | PNG |
Un rig esegue un solo motore per tutta la sua vita. Una conversazione può contenere un rig per motore, ed è questo che rende possibile il confronto affiancato: aprire «Firefox (VM)» accanto a «Chromium (VM)» significa due macchine, e chiuderne una lascia l’altra in esecuzione.
Passa engine a rig.open o allo strumento browser_use. Un nome sconosciuto
viene rifiutato invece di essere sostituito con quello predefinito: chiedere un
browser e riceverne in silenzio un altro risponde alla domanda sulla
compatibilità con la risposta sbagliata.
Limiti specifici di ciascun motore, dichiarati invece che aggirati:
- Firefox non ha un ricaricamento che aggira la cache (rifiuta del tutto
ignoreCachedi BiDi), quindi un ricaricamento forzato è un ricaricamento normale. - WebKit non ha neppure un ricaricamento che aggira la cache, non ha un
flusso della console (l’output viene catturato intercettando
console.*dopo ogni navigazione, quindi tutto ciò che viene registrato durante il caricamento va perso — ogni estrazione della console lo dichiara), e richiedeffmpegsull’host per la sua vista dal vivo. - Nessuno dei due espone un albero di accessibilità della piattaforma sul
proprio protocollo, quindi
extract (a11y)restituisce un’approssimazione derivata dal DOM, etichettata come tale. - Nessuno dei due può ricevere un vero rilascio di file; un campo di input file può comunque essere puntato a percorsi interni alla macchina.
Immagini delle macchine
Sezione intitolata “Immagini delle macchine”| Superficie | Immagine | Recuperata |
|---|---|---|
| Terminale | ubuntu:24.04, fissata per digest |
Automaticamente al primo avvio, tramite la rete controllata della macchina stessa |
| Browser (Chromium, Firefox, WebKit) | debian:trixie-slim, fissata per digest, più i pacchetti del motore stesso |
Automaticamente al primo avvio, poi messa in cache come pacchetto preriscaldato |
| Computer | Un’immagine desktop qcow2 con Chromium, Firefox, WebKit e la stessa base CLI da runner ospitato su GitHub che il terminale preriscalda | Importa in Impostazioni → Server → Rig (download fissati per checksum dove pubblicati) |
| Android | Le immagini di sistema di Google | Tramite l’SDK Android |
| iOS | Un runtime del simulatore Xcode più WebDriverAgent fissato per checksum | Runtime tramite Xcode; bridge di automazione da Impostazioni → Server → Rig |
Dopo il primo avvio di ciascun tipo di microVM il server mette in cache una
copia già estratta nella directory dei dati e avvia da lì ogni macchina
successiva, comprese le immagini preriscaldate con i pacchetti già installati.
Il terminale preriscalda un set di strumenti CLI in stile runner ospitato su
GitHub (git, gcc, python3, jq, rsync, strumenti per archivi e il
resto della base apt; non Docker né le cache degli strumenti dei linguaggi). Il
qcow2 del Computer incorpora gli stessi nomi di CLI al momento della build
dell’immagine, accanto a XFCE e ai tre browser. Ogni browser preriscalda il
proprio motore. Tutti e tre i motori condividono una base Debian ma non
condividono mai un pacchetto: la cache è indicizzata per immagine, motore e
revisione audio (audio-v1-<engine>), perché una macchina preriscaldata per un
motore — o prima che PulseAudio e ffmpeg facessero parte del carico di lavoro —
non contiene nulla dell’altro. Il pacchetto del terminale è indicizzato per
revisione del set di strumenti (tools-v1) per lo stesso motivo: un pacchetto
preriscaldato prima che il compilatore facesse parte dell’immagine non deve
servire una macchina che dovrebbe averlo.
Non esiste un’immagine di automazione preconfezionata che valga la pena usare:
chromedp/headless-shell di Chromium esclude in compilazione sia ALSA sia
PulseAudio, quindi non può mai emettere audio; l’unica per Firefox mantenuta è
33× la dimensione della base Debian e non include comunque socat; per WebKit
non ne esiste affatto una mantenuta. Quindi ogni motore si installa al primo
avvio (chromium, firefox-esr o webkit2gtk-driver) e, mentre lo fa,
raggiunge gli archivi Debian (deb.debian.org, security.debian.org,
cloudfront.debian.net). Chromium è il binario della distribuzione avviato
come chromium --headless=new.
Immagini personalizzate per spazio di lavoro
Sezione intitolata “Immagini personalizzate per spazio di lavoro”| Chiave di impostazione | Sostituisce |
|---|---|
rigs.smolvm.execImage |
L’immagine del Terminale (VM) |
rigs.smolvm.browserImage |
L’immagine del Browser (VM) Chromium |
Scritta tramite l’archivio delle impostazioni dello spazio di lavoro riservato agli amministratori (Impostazioni → Server → Rig → Immagini personalizzate (questo spazio di lavoro)). Il valore deve essere un riferimento di registry — percorsi locali, archivi e stringhe che assomigliano a flag vengono rifiutati, sia nel campo sia di nuovo all’avvio. Un valore memorizzato non valido viene ignorato in modo visibile e al suo posto si avvia quello predefinito. Il registry dell’immagine stessa (più i noti companion blob-CDN per Docker Hub, GHCR, Quay, GitLab e GCR) viene ammesso attraverso il varco dell’uscita in rete per il pull.
Contratto dell’immagine del terminale — bash presente; git, curl,
socat preinstallati oppure una base apt Debian/Ubuntu (il recinto installa
quei tre più un set di strumenti CLI in stile runner ospitato su GitHub al
primo avvio: compilatori, Python 3, jq, strumenti per archivi, rsync. Le
cache degli strumenti dei linguaggi e Docker non vengono installati).
Contratto dell’immagine del browser — una base apt Debian/Ubuntu (o i
pacchetti già installati) con bash e socat, più un binario chromium che
il server avvia da sé come chromium --headless=new con DevTools sul loopback
del guest 9223, inoltrato alla porta del guest 9222. PulseAudio e ffmpeg
vengono installati al primo avvio per la corsia audio. Non costruire
FROM chromedp/headless-shell: headless.gn a monte esclude in compilazione
sia ALSA sia PulseAudio, quindi quel binario non può emettere audio. La
sostituzione si applica solo ai rig Chromium — il comando del carico di
lavoro che avvia è quello di Chromium, e passarlo a Firefox o WebKit avvierebbe
un binario che non c’è. Un rig Firefox o WebKit la ignora in modo visibile e
avvia la propria immagine fissata.
Porte di automazione — ogni macchina browser inoltra esattamente una porta
di loopback dell’host alla porta 9222 del guest. Dietro di essa: DevTools di
Chromium e l’agente remoto di Firefox stanno sul loopback del guest 9223 con
un relay socat davanti (entrambi si legano al loopback incondizionatamente);
il driver di WebKit accetta un --host e si lega direttamente alla NIC del
guest. Firefox inoltre convalida l’header Host rispetto alla propria porta,
quindi il client invia l’authority lato guest anziché quella che ha contattato.
Verbi di azione
Sezione intitolata “Verbi di azione”Ogni azione viene analizzata in modo totale: un payload malformato restituisce un messaggio che nomina il campo, mai un’eccezione. I verbi di osservazione (contrassegnati con ○) restano consentiti mentre una persona detiene il controllo; i verbi mutativi vengono rifiutati.
computer_use
Sezione intitolata “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.
Le coordinate sono pixel del guest nella modalità corrente del guest; ogni
screenshot indica la dimensione del display. Le combinazioni di tasti usano la
grafia X11 (ctrl+s, alt+Tab, Return).
clipboard_read accetta un selection: clipboard (ciò che riempie ctrl+C,
il valore predefinito), primary (selezione-per-copiare di X11) o xdnd (un
trascinamento in corso). Un risultato vuoto è una risposta normale per tutti e
tre. clipboard_write accetta solo text — immagini e file viaggiano sulla
corsia dei file, perché gli argomenti di un’azione vengono memorizzati nel log
di audit e i byte delle immagini non hanno nulla a che fare lì. Il contenuto
degli appunti torna delimitato come dato non attendibile.
browser_use
Sezione intitolata “browser_use”navigate (solo http/https), reload (hard opzionale), stop_loading,
click (selettore o coordinata), fill, type, key (nomi dei tasti DOM),
scroll, mouse_move, drag, left_mouse_down, left_mouse_up,
extract○ (a11y | dom | console), screenshot○ (full_page
opzionale), set_viewport (min 320×240), history, wait_for○ (selettore,
0,1–30 s), clipboard_read○, clipboard_write.
Il contenuto estratto della pagina torna delimitato come dato non attendibile.
Il browser ha esattamente un blocco di appunti, quindi clipboard_read non
accetta selection. Entrambi i verbi degli appunti richiedono un contesto
sicuro: una pagina servita su http:// semplice non ha alcuna API degli
appunti, e il verbo lo dichiara invece di segnalare appunti vuoti — lì usa
type, che inserisce al cursore senza passare dagli appunti.
mobile_use
Sezione intitolata “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 qualsiasi KEYCODE_*),
screenshot○, ui_dump○, install_apk
(limitato al worktree del rig e alla directory dei dati del server),
start_app, stop_app, clear_app_data, uninstall_app, open_url e
shell. shell accetta un elenco argv e viene eseguito dentro Android, mai
tramite una shell dell’host; copre diagnostiche per sviluppatori come logcat,
dumpsys e pm grant.
mobile_use non ha verbi per gli appunti. Da Android 10 solo l’app in primo
piano può leggere gli appunti.
ios_use
Sezione intitolata “ios_use”tap, swipe (50–5000 ms), type, key (enter, backspace, tab,
escape, i tasti freccia o un singolo carattere stampabile; modificatori
opzionali command, control, option e shift), home, lock, unlock,
screenshot○, ui_dump○, install_app (una directory .app del simulatore
limitata al worktree del rig o alla directory dei dati del server),
start_app, stop_app, uninstall_app, open_url e spawn. spawn accetta
argv ed esegue dentro il simulatore tramite simctl; non invoca mai una shell
dell’host.
Le coordinate sono punti dello schermo iOS, non pixel dello screenshot. Il flusso dal vivo mantiene la dimensione fissa del simulatore e lo incornicia con bande nere invece di ridimensionare il dispositivo. Il trasferimento di testo negli appunti dall’host al simulatore e viceversa usa la stessa policy di autorizzazione per utente e per direzione degli altri rig; file e immagini non sono accettati dalla corsia degli appunti di iOS.
Ogni rig crea un dispositivo CoreSimulator e una sessione WebDriverAgent di cui è proprietario. Chiuderlo ferma WebDriverAgent, spegne ed elimina quel dispositivo e rimuove la sua voce dal registry. I rig iOS vengono eseguiti solo su un server macOS con Xcode, un runtime iOS installato e il bridge di automazione fissato. Non espongono audio, microfono, rilascio di file, shell dell’host né alcuna garanzia di rete isolata.
Strumenti di gestione
Sezione intitolata “Strumenti di gestione”| Strumento | Descrizione |
|---|---|
rig_list |
Elenca i rig di uno spazio di lavoro con superficie, stato, display e controller |
rig_close |
Distrugge un rig e ne scarta il disco |
Ciclo di vita
Sezione intitolata “Ciclo di vita”| Fase | Significato |
|---|---|
provisioning |
In avvio; il dettaglio di stato riporta il passo corrente alla lettera |
ready |
Raggiungibile e in grado di accettare azioni |
parked |
In pausa per inattività: vCPU ferme, RAM ancora residente; l’azione successiva la risveglia |
closing |
In spegnimento |
closed |
Sparito; la riga sopravvive per il log di audit |
failed |
Morto o mai avviato; distinguibile così l’interfaccia può offrire un nuovo tentativo |
| Motivo di chiusura | Attivato quando |
|---|---|
requested |
Una persona o un agente l’ha chiesto |
idleTimeout |
Inattivo oltre 2× la finestra di inattività, o espulso per memoria |
ttlExpired |
La durata massima è scaduta |
conversationEnded |
La conversazione proprietaria è terminata |
workspaceGone |
Lo spazio di lavoro è stato eliminato o l’appartenenza è andata persa |
serverShutdown |
Il server si sta arrestando |
backendFailure |
L’hypervisor è morto sotto di essa |
Valori predefiniti e limiti massimi
Sezione intitolata “Valori predefiniti e limiti massimi”| Valore | Terminale | Browser | Computer | Mobile |
|---|---|---|---|---|
| Memoria | 512 MB | 2048 MB (Chromium); 2560 MB (Firefox, WebKit) | 4096 MB | 4096 MB |
| vCPU | 2 | 2 | 4 | 4 |
| TTL rigido | 8 h | 2 h | 2 h | 2 h |
| Finestra di inattività | 45 min | 15 min | 15 min | 15 min |
| Display all’avvio | — | 1280×800 | 1280×800 | 1080×1920 |
- I fermoimmagine della corsia dell’agente sono limitati a 1280×800; la corsia umana negozia fino a 2560×1600.
- Il budget di memoria residente dell’host per tutti i rig è di 12 GB per impostazione predefinita, contato in megabyte residenti (una VM in pausa conserva comunque la sua RAM). L’espulsione è least-recently-used e non sottrae mai una macchina che qualcuno sta guidando, guardando o in cui ha un terminale aperto.
- Un terminale o una corsia di osservazione aperti bloccano il rig impedendone la sosta e la raccolta per inattività; il TTL rigido si applica comunque.
Porte e domini di sviluppo
Sezione intitolata “Porte e domini di sviluppo”| Porta | Dove | Riservata a |
|---|---|---|
7911 |
Guest del terminale | Il multiplexer delle porte su cui viaggia ogni inoltro |
9222, 9223 |
Guest del browser | Il relay e l’endpoint di automazione (WebKit si lega direttamente a 9222 e non usa relay) |
80, 443 |
Loopback del guest del browser | Le corsie HTTP/HTTPS del dominio di sviluppo |
- La scoperta interroga le porte TCP in ascolto del guest del terminale ogni ~4 s, lato server.
- Al massimo 16 porte vengono inoltrate automaticamente per rig; le altre sono elencate nel log, non inoltrate.
- L’inoltro lato host si lega al loopback, preferendo il numero di porta del guest stesso; Condividi sulla rete locale aggiunge una porta LAN assegnata dal sistema operativo.
- I domini di sviluppo devono corrispondere a
name.testoname.localhost(minuscolo, etichetta di massimo 63 caratteri). Un dominio mappa su una porta. - L’HTTPS del dominio di sviluppo usa una CA locale del server (EC P-256,
sotto
<dataDir>/rigs/tls/, chiavi 0600 e mai in un guest) con un unico certificato foglia wildcard per*.test/*.localhost. Nessunopensslsull’host significa nessuna corsia HTTPS; l’HTTP semplice viene comunque instradato.
Valori predefiniti dell’uscita in rete
Sezione intitolata “Valori predefiniti dell’uscita in rete”| Superficie | Allowlist predefinita |
|---|---|
| Terminale | La base da sviluppatore del sandbox (forge, registry dei pacchetti, fornitori di modelli) + i mirror apt di Ubuntu + l’host forge del worktree stesso |
| Browser | usectrl.dev (il sito del prodotto) — più gli archivi Debian al primo avvio di ogni motore, mentre installa i suoi pacchetti. La pagina iniziale è un documento file:// locale e non richiede alcuna uscita in rete |
| Computer | Vuota — nega tutto — finché un chiamante non concede host |
| Mobile | Non applicata (rete gestita dall’emulatore) |
Ogni microVM riceve inoltre gli host del registry della sua immagine, solo per il pull. L’insieme degli host consentiti del broker delle credenziali deriva dalla stessa allowlist: nessun token viene coniato per un host che il guest non può raggiungere.
Appunti e trasferimento di file
Sezione intitolata “Appunti e trasferimento di file”Copia e incolla in entrambe le direzioni, e trascinamento di file dentro e fuori. Disponibile a una persona che guida un rig; un agente ottiene gli appunti attraverso i verbi precedenti e nessun trasferimento di file (ha già una shell dentro il recinto).
Il passaggio degli appunti è per utente e per direzione. L’incolla dall’host al rig è consentito per impostazione predefinita; la copia dal rig all’host chiede conferma (un’autorizzazione di dieci minuti, oppure consenti sempre in Impostazioni → Server → Rig → Accesso agli appunti). Le due scelte sono indipendenti e non sono mai un’impostazione dello spazio di lavoro.
| Corsia | Percorso | Trasporta |
|---|---|---|
| Appunti | GET/POST /rig/clipboard/<rigId> |
Testo, un PNG/JPEG (≤16 MB) e i percorsi nel guest dei file negli appunti |
| File | POST /rig/files/<rigId> |
Fino a 64 file, ≤256 MB ciascuno e ≤512 MB per rilascio, con un punto di rilascio opzionale in pixel del guest |
| File | GET /rig/files/<rigId>?p=<base64url path> |
I byte di un file, in uscita |
- HTTP, non RPC. Il socket RPC chiude una connessione su un frame in ingresso superiore a 256 KB: una protezione anti-DoS giusta per i comandi JSON e fatale per uno screenshot incollato. I byte viaggiano sullo stesso tipo di percorso già usato dai frame dei rig e dall’audio delle riunioni.
- L’autenticazione è il target firmato
rig-files:<workspaceId>/<rigId>più l’appartenenza allo spazio di lavoro — un target a sé, quindi un URL coniato per guardare una macchina non può anche scrivervi file. - La presa in carico si applica. Scrivere negli appunti e rilasciare file sono operazioni mutative e vengono rifiutate mentre qualcun altro detiene il controllo; leggere gli appunti e prelevare un file sono osservazione e non lo sono.
- Dove finiscono i rilasci:
~/Drops(desktop),~/drops(terminale — accanto al worktree, mai al suo interno, così un rilascio non appare mai come modifica non tracciata),/tmp/cc-drops(browser). La directory la sceglie il server; un chiamante non può nominarla. I file esistenti non vengono mai sovrascritti — un nome in conflitto finisce come2-name.ext. - Cosa viene detto al guest: una pagina del browser riceve un vero evento
di drop nel punto richiesto (
Input.dispatchDragEvent); un desktop riceve i file più i loro URI nei propri appunti, perché nessun host può sintetizzare un trascinamento XDND in un toolkit arbitrario senza un demone privilegiato dentro il guest. La risposta indica quale dei due casi si è verificato. - Il trascinamento verso l’esterno è solo per il desktop e legge la
XdndSelectiondel guest mentre un trascinamento è in corso. Un payload identico a ciò che il guest aveva già quando è iniziata la pressione viene trattato come una selezione obsoleta di un trascinamento concluso, non come uno nuovo — X non ha un passaggio «il trascinamento è finito». - Requisiti dell’immagine: l’immagine desktop deve essere protocollo 2 o successivo (costruita dopo l’introduzione del supporto agli appunti). Un’immagine più vecchia risponde 404 e l’app dice di ricostruirla invece di segnalare una macchina guasta.
- Il log di audit registra la forma, mai il contenuto: le righe di
clipboard_read,clipboard_write,drop_fileseread_fileriportano conteggi, dimensioni e percorsi. Gli appunti sono il posto in cui le credenziali vivono qualche secondo alla volta, e nulla di ciò viene scritto.
Guardrail, eventi, archiviazione
Sezione intitolata “Guardrail, eventi, archiviazione”- Gli strumenti dei rig dichiarano la classe di azioni
enclosureControl(piùnetworkEgresseprocessSpawnsugli strumenti use;mobile_useeios_usedichiarano anchepackageInstall).rig_closedichiaraenclosureControl;rig_listnon ne dichiara alcuna. Consentita per impostazione predefinita; le modalità di sola lettura la negano in blocco; la manopola di autonomia per spazio può declassarla a richiesta preventiva. - Eventi di dominio:
RigClosedEvent(con il suo motivo di chiusura),RigControlChanged(presa in carico / restituzione),RigReaped(inattività, TTL o espulsione per memoria, con l’agente che la guidava). L’apertura di un rig non è un evento. Vedi eventi di dominio. - Archiviazione:
rig_sessionserig_action_lognel database di ogni spazio di lavoro. Il log delle azioni registra ogni evento di input con il suo principal e una sequenza monotona per rig; il testo digitato viene ridotto a una lunghezza e a un hash prima di essere scritto. - Directory dei dati:
rigs/images/(immagini qcow2 importate),rigs/smolvm/(stato di runtime per rig),rigs/smolvm-packs/(pacchetti macchina già estratti),rigs/tls/(la CA del dominio di sviluppo),rigs/run/(overlay e seed di QEMU). - Percorsi: la vista dal vivo è una scheda in una pagina di spazio o di PR;
/settings/server/rigsè la schermata delle impostazioni dei Rig.