Rigs
Des faits uniquement. Pour le modèle qui les sous-tend, consultez Rigs et enceintes ; pour ouvrir une machine, suivez le guide.
Surfaces et backends
Section intitulée « Surfaces et backends »| Surface | Pilote | Backend | Valeur | Sortie réseau confinée |
|---|---|---|---|---|
| Terminal (exec) | Un shell sur le canal exec de la VM | microVM | smolvm |
Oui |
| Navigateur | Chromium sans interface (CDP), Firefox (WebDriver BiDi) ou WebKit (W3C WebDriver) | microVM | smolvm |
Oui |
| Ordinateur | Bureau X11 : entrée via l’hyperviseur, capture via l’agent de l’invité | QEMU | qemu-hvf (macOS), qemu-kvm (Linux), qemu-tcg (repli non accéléré, jamais choisi automatiquement) |
Oui |
| Android | Android via ADB | L’émulateur de Google | android-emulator |
Non — l’émulateur gère son propre réseau |
| iOS | Le simulateur iOS via WebDriverAgent | CoreSimulator | ios-simulator |
Non — le réseau suit le Mac hôte |
Le terminal et la surface computer_use partagent la valeur de surface
computer ; le terminal se distingue par son marqueur d’image exec et n’est
jamais réutilisé comme bureau pilotable (et inversement). Une conversation
réutilise une seule machine terminal.
Moteurs de navigateur
Section intitulée « Moteurs de navigateur »| Moteur | Valeur | Protocole | Vue en direct | Images fixes |
|---|---|---|---|---|
| Chromium | chromium (par défaut) |
Chrome DevTools Protocol | Screencast — le navigateur pousse les images à mesure que la page se redessine | JPEG |
| Firefox | firefox |
WebDriver BiDi | Images fixes par interrogation (BiDi n’a pas de screencast), plafonnées à 6 fps | JPEG |
| WebKit | webkit |
W3C WebDriver (classique) | Images fixes par interrogation, transcodées par le ffmpeg de l’hôte | PNG |
Un rig exécute un seul moteur pendant toute sa vie. Une conversation peut contenir un rig par moteur, ce qui rend possible une comparaison côte à côte : ouvrir « Firefox (VM) » à côté de « Chromium (VM) », c’est deux machines, et fermer l’une laisse l’autre en marche.
Passez engine à rig.open ou à l’outil browser_use. Un nom inconnu est
refusé plutôt que remplacé par la valeur par défaut — demander un navigateur
et en obtenir silencieusement un autre répond à une question de compatibilité
par une mauvaise réponse.
Limites propres à chaque moteur, énoncées plutôt que contournées :
- Firefox n’a pas de rechargement contournant le cache (il rejette
d’emblée
ignoreCachede BiDi), si bien qu’un rechargement forcé est un rechargement normal. - WebKit n’a pas non plus de rechargement contournant le cache, ni de
flux de console (la sortie est capturée en interceptant
console.*après chaque navigation, si bien que tout ce qui est journalisé pendant le chargement est manqué — chaque extraction de console le dit), et a besoin deffmpegsur l’hôte pour sa vue en direct. - Ni l’un ni l’autre n’expose d’arbre d’accessibilité de la plateforme via
son protocole, si bien que
extract (a11y)renvoie une approximation dérivée du DOM, étiquetée comme telle. - Ni l’un ni l’autre ne peut recevoir un vrai dépôt de fichiers ; un champ de fichier peut toujours être pointé vers des chemins à l’intérieur de la machine.
Images de machine
Section intitulée « Images de machine »| Surface | Image | Récupération |
|---|---|---|
| Terminal | ubuntu:24.04, épinglée par empreinte |
Automatiquement au premier démarrage, via le réseau filtré de la machine elle-même |
| Navigateur (Chromium, Firefox, WebKit) | debian:trixie-slim, épinglée par empreinte, plus les paquets propres au moteur |
Automatiquement au premier démarrage, puis mise en cache comme pack préchauffé |
| Ordinateur | Une image de bureau qcow2 avec Chromium, Firefox, WebKit et le même socle d’outils CLI de type runner hébergé par GitHub que celui préchauffé par le terminal | Importer sous Paramètres → Serveur → Rigs (téléchargements épinglés par somme de contrôle lorsqu’ils sont publiés) |
| Android | Les images système de Google | Via le SDK Android |
| iOS | Un runtime Xcode Simulator et un WebDriverAgent épinglé par somme de contrôle | Runtime via Xcode ; pont d’automatisation depuis Paramètres → Serveur → Rigs |
Après le premier démarrage de chaque type de microVM, le serveur met en cache
une copie pré-extraite dans le répertoire de données et démarre toutes les
machines suivantes à partir d’elle — y compris des images préchauffées dont
les paquets sont déjà installés. Le terminal préchauffe un socle d’outils CLI
de type runner hébergé par GitHub (git, gcc, python3, jq, rsync,
les outils d’archivage et le reste du socle apt ; ni Docker ni les caches
d’outils par langage). Le qcow2 Ordinateur intègre ces mêmes noms d’outils
CLI au moment de la construction de l’image, aux côtés de XFCE et des trois
navigateurs. Chaque navigateur préchauffe son moteur. Les trois moteurs
partagent une base Debian mais ne partagent jamais un pack : le cache est
indexé sur l’image, le moteur et une révision audio
(audio-v1-<engine>), car une machine préchauffée pour un moteur — ou avant
que PulseAudio et ffmpeg ne fassent partie de la charge de travail — ne
contient rien de l’autre. Le pack du terminal est indexé sur une révision
d’outillage (tools-v1) pour la même raison : un pack préchauffé avant que le
compilateur ne fasse partie de l’image ne doit pas servir une machine censée
en avoir un.
Il n’existe aucune image d’automatisation préconstruite qui vaille la peine
d’être reprise — le chromedp/headless-shell de Chromium compile ALSA et
PulseAudio hors du binaire, il ne peut donc jamais émettre de son ; la seule
image Firefox maintenue fait 33× la taille de la base Debian et ne fournit
toujours pas socat ; il n’existe aucune image WebKit maintenue. Chaque
moteur s’installe donc au premier démarrage (chromium, firefox-esr ou
webkit2gtk-driver) et atteint les archives Debian (deb.debian.org,
security.debian.org, cloudfront.debian.net) pour ce faire. Chromium est
le binaire de la distribution, lancé sous la forme chromium --headless=new.
Images personnalisées par espace de travail
Section intitulée « Images personnalisées par espace de travail »| Clé de réglage | Remplace |
|---|---|
rigs.smolvm.execImage |
L’image du Terminal (VM) |
rigs.smolvm.browserImage |
L’image du Navigateur Chromium (VM) |
Écrite via le magasin de réglages d’espace de travail réservé aux administrateurs (Paramètres → Serveur → Rigs → Images personnalisées (cet espace de travail)). La valeur doit être une référence de registre — les chemins locaux, les archives et les chaînes ressemblant à des options sont refusés, à la saisie comme au démarrage. Une valeur stockée invalide est ignorée avec un message explicite, et l’image par défaut démarre à la place. Le registre de l’image elle-même (ainsi que les CDN d’objets associés connus pour Docker Hub, GHCR, Quay, GitLab et GCR) est admis par la porte de sortie réseau pour le tirage.
Contrat de l’image Terminal — bash présent ; git, curl, socat
préinstallés ou une base apt Debian/Ubuntu (l’enceinte installe ces trois
outils plus un socle d’outils CLI de type runner hébergé par GitHub au premier
démarrage : compilateurs, Python 3, jq, outils d’archivage, rsync. Les
caches d’outils par langage et Docker ne sont pas installés).
Contrat de l’image Navigateur — une base apt Debian/Ubuntu (ou les
paquets déjà installés) avec bash et socat, plus un binaire chromium que
le serveur lance lui-même sous la forme chromium --headless=new, avec
DevTools sur la boucle locale de l’invité 9223, relayé vers le port invité
9222. PulseAudio et ffmpeg sont installés au premier démarrage pour la voie
audio. Ne construisez pas FROM chromedp/headless-shell : le headless.gn
amont compile ALSA et PulseAudio hors du binaire, celui-ci ne peut donc pas
émettre de son. La surcharge ne s’applique qu’aux rigs Chromium — la
commande de charge de travail qu’elle démarre est celle de Chromium, et la
confier à Firefox ou WebKit lancerait un binaire absent. Un rig Firefox ou
WebKit l’ignore avec un message explicite et démarre son image épinglée.
Ports d’automatisation — chaque machine navigateur transfère exactement un
port de boucle locale de l’hôte vers le port invité 9222. Derrière ce port :
les DevTools de Chromium et l’agent distant de Firefox se trouvent sur la
boucle locale de l’invité 9223, avec un relais socat devant (tous deux se
lient à la boucle locale sans condition) ; le pilote de WebKit accepte un
--host et se lie lui-même à la carte réseau de l’invité. Firefox valide en
outre l’en-tête Host par rapport à son propre port, si bien que le client
envoie l’autorité côté invité plutôt que celle qu’il a contactée.
Verbes d’action
Section intitulée « Verbes d’action »Chaque action est analysée de façon totale : une charge utile mal formée renvoie un message nommant le champ, jamais une exception. Les verbes d’observation (marqués ○) restent autorisés tant qu’un humain détient le contrôle ; les verbes modificateurs sont refusés.
computer_use
Section intitulée « 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.
Les coordonnées sont exprimées en pixels de l’invité, dans le mode actuel de
celui-ci ; chaque capture d’écran indique la taille de l’écran. Les
combinaisons de touches utilisent la notation X11 (ctrl+s, alt+Tab,
Return).
clipboard_read prend une selection : clipboard (ce que remplit ctrl+C,
la valeur par défaut), primary (la sélection pour copie X11) ou xdnd (un
glisser en cours). Un résultat vide est une réponse normale pour les trois.
clipboard_write ne prend que text — les images et les fichiers passent par
la voie des fichiers, car les arguments d’une action sont conservés dans le
journal d’audit et les octets d’image n’y ont rien à faire. Le contenu du
presse-papiers revient encadré comme donnée non fiable.
browser_use
Section intitulée « browser_use »navigate (http/https uniquement), reload (hard facultatif),
stop_loading, click (sélecteur ou coordonnée), fill, type, key (noms
de touches DOM), scroll, mouse_move, drag, left_mouse_down,
left_mouse_up, extract○ (a11y | dom | console), screenshot○
(full_page facultatif), set_viewport (min 320×240), history, wait_for○
(sélecteur, 0,1–30 s), clipboard_read○, clipboard_write.
Le contenu de page extrait revient encadré comme donnée non fiable.
Le navigateur n’a qu’un seul presse-papiers, donc clipboard_read ne prend
pas de selection. Les deux verbes de presse-papiers exigent un contexte
sécurisé : une page servie en http:// simple n’a aucune API de
presse-papiers, et le verbe le signale plutôt que de rapporter un
presse-papiers vide — utilisez type dans ce cas, qui insère au niveau du
curseur sans passer par un presse-papiers.
mobile_use
Section intitulée « 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, ou tout KEYCODE_*), screenshot○,
ui_dump○, install_apk (limité à l’arbre de travail du rig et au répertoire
de données du serveur), start_app, stop_app, clear_app_data,
uninstall_app, open_url, et shell. shell prend une liste d’arguments
et s’exécute dans Android, jamais via un shell de l’hôte ; il couvre des
diagnostics de développeur tels que logcat, dumpsys et pm grant.
mobile_use n’a pas de verbes de presse-papiers. Depuis Android 10, seule
l’application au premier plan peut lire le presse-papiers.
tap, swipe (50–5000 ms), type, key (enter, backspace, tab,
escape, les touches fléchées ou un caractère imprimable ; modificateurs
facultatifs command, control, option et shift), home, lock,
unlock, screenshot○, ui_dump○, install_app (un répertoire .app de
simulateur limité à l’arbre de travail du rig ou au répertoire de données du
serveur), start_app, stop_app, uninstall_app, open_url, et spawn.
spawn prend des arguments et s’exécute dans le simulateur via simctl ; il
n’invoque jamais un shell de l’hôte.
Les coordonnées sont des points d’écran iOS, et non des pixels de capture d’écran. Le flux en direct conserve la taille fixe du simulateur et l’affiche avec des bandes plutôt que de redimensionner l’appareil. Le transfert de texte par presse-papiers de l’hôte vers le simulateur et du simulateur vers l’hôte applique la même politique d’autorisation par utilisateur et par sens que les autres rigs ; les fichiers et les images ne sont pas acceptés par la voie du presse-papiers iOS.
Chaque rig crée un appareil CoreSimulator et une session WebDriverAgent qui lui appartiennent. Sa fermeture arrête WebDriverAgent, éteint et supprime cet appareil, et retire son entrée du registre. Les rigs iOS ne s’exécutent que sur un serveur macOS doté de Xcode, d’un runtime iOS installé et du pont d’automatisation épinglé. Ils n’exposent ni audio, ni microphone, ni dépôt de fichiers, ni shell de l’hôte, ni garantie de réseau confiné.
Outils de gestion
Section intitulée « Outils de gestion »| Outil | Description |
|---|---|
rig_list |
Liste les rigs d’un espace de travail avec leur surface, leur état, leur affichage et leur contrôleur |
rig_close |
Détruit un rig et abandonne son disque |
Cycle de vie
Section intitulée « Cycle de vie »| Phase | Signification |
|---|---|
provisioning |
Démarrage ; le détail d’état reprend l’étape en cours telle quelle |
ready |
Joignable et acceptant des actions |
parked |
Mis en veille : vCPU arrêtés, RAM toujours résidente ; l’action suivante le réveille |
closing |
Arrêt en cours |
closed |
Disparu ; la ligne subsiste pour la piste d’audit |
failed |
Mort ou jamais démarré ; distinguable pour que l’interface puisse proposer un nouvel essai |
| Motif de fermeture | Déclenché quand |
|---|---|
requested |
Une personne ou un agent l’a demandé |
idleTimeout |
Inactif au-delà de 2× la fenêtre d’inactivité, ou évincé pour libérer de la mémoire |
ttlExpired |
La durée de vie maximale a expiré |
conversationEnded |
La conversation propriétaire s’est terminée |
workspaceGone |
L’espace de travail a été supprimé ou l’appartenance a été perdue |
serverShutdown |
Le serveur s’arrête |
backendFailure |
L’hyperviseur est tombé sous lui |
Valeurs par défaut et plafonds
Section intitulée « Valeurs par défaut et plafonds »| Valeur | Terminal | Navigateur | Ordinateur | Mobile |
|---|---|---|---|---|
| Mémoire | 512 Mo | 2048 Mo (Chromium) ; 2560 Mo (Firefox, WebKit) | 4096 Mo | 4096 Mo |
| vCPU | 2 | 2 | 4 | 4 |
| TTL maximal | 8 h | 2 h | 2 h | 2 h |
| Fenêtre d’inactivité | 45 min | 15 min | 15 min | 15 min |
| Affichage au démarrage | — | 1280×800 | 1280×800 | 1080×1920 |
- Les images fixes de la voie de l’agent sont plafonnées à 1280×800 ; la voie humaine négocie jusqu’à 2560×1600.
- Le budget de mémoire résidente de l’hôte pour tous les rigs est par défaut de 12 Go, compté en mégaoctets résidents (une VM en veille conserve sa RAM). L’éviction suit la règle du moins récemment utilisé et ne prend jamais une machine que quelqu’un pilote, regarde ou dans laquelle un terminal est ouvert.
- Un terminal ouvert ou une voie d’observation active empêche la mise en veille et la récupération pour inactivité du rig ; le TTL maximal s’applique toujours.
Ports et domaines de développement
Section intitulée « Ports et domaines de développement »| Port | Où | Réservé à |
|---|---|---|
7911 |
Invité terminal | Le multiplexeur de ports par lequel passe chaque transfert |
9222, 9223 |
Invité navigateur | Le relais et le point de terminaison d’automatisation (WebKit se lie directement à 9222 et n’utilise aucun relais) |
80, 443 |
Boucle locale de l’invité navigateur | Les voies HTTP/HTTPS des domaines de développement |
- La découverte interroge côté serveur les ports TCP en écoute de l’invité terminal toutes les ~4 s.
- Au plus 16 ports sont transférés automatiquement par rig ; au-delà, ils sont listés dans le journal sans être transférés.
- Le transfert côté hôte se lie à la boucle locale, en préférant le numéro de port de l’invité lui-même ; Partager sur le réseau local ajoute un port LAN attribué par le système.
- Les domaines de développement doivent correspondre à
name.testouname.localhost(en minuscules, étiquette de 63 caractères au maximum). Un domaine correspond à un port. - Le HTTPS des domaines de développement utilise une autorité de certification
locale au serveur (EC P-256, sous
<dataDir>/rigs/tls/, clés en 0600 et jamais dans un invité) avec un certificat feuille générique pour*.test/*.localhost. Sansopensslsur l’hôte, pas de voie HTTPS ; le HTTP simple continue d’être routé.
Sortie réseau par défaut
Section intitulée « Sortie réseau par défaut »| Surface | Liste d’autorisation par défaut |
|---|---|
| Terminal | Le socle développeur du bac à sable (forges, registres de paquets, fournisseurs de modèles) + les miroirs apt d’Ubuntu + l’hôte de forge de l’arbre de travail lui-même |
| Navigateur | usectrl.dev (le site du produit) — plus les archives Debian au premier démarrage de chaque moteur, pendant qu’il installe ses paquets. La page d’accueil est un document file:// local et n’a besoin d’aucune sortie réseau |
| Ordinateur | Vide — tout refuser — jusqu’à ce qu’un appelant accorde des hôtes |
| Mobile | Non appliquée (réseau géré par l’émulateur) |
Chaque microVM reçoit en outre les hôtes de registre de son image, pour le tirage uniquement. L’ensemble d’hôtes autorisés du courtier d’identifiants est dérivé de la même liste d’autorisation : aucun jeton n’est émis pour un hôte que l’invité ne peut pas atteindre.
Presse-papiers et transfert de fichiers
Section intitulée « Presse-papiers et transfert de fichiers »Le copier-coller dans les deux sens, ainsi que le glisser-déposer de fichiers dans un sens comme dans l’autre. Disponible pour une personne qui pilote un rig ; un agent obtient le presse-papiers via les verbes ci-dessus et aucun transfert de fichiers (il dispose déjà d’un shell à l’intérieur de l’enceinte).
Le franchissement du presse-papiers se fait par utilisateur et par sens. Le collage de l’hôte vers le rig est autorisé par défaut ; la copie du rig vers l’hôte demande confirmation (une autorisation de dix minutes, ou Toujours autoriser sous Paramètres → Serveur → Rigs → Accès au presse-papiers). Les deux choix sont indépendants et ne constituent jamais un réglage d’espace de travail.
| Voie | Route | Transporte |
|---|---|---|
| Presse-papiers | GET/POST /rig/clipboard/<rigId> |
Du texte, un PNG/JPEG (≤16 Mo) et les chemins invité des fichiers présents dans le presse-papiers |
| Fichiers | POST /rig/files/<rigId> |
Jusqu’à 64 fichiers, ≤256 Mo chacun et ≤512 Mo par dépôt, avec un point de dépôt optionnel en pixels de l’invité |
| Fichiers | GET /rig/files/<rigId>?p=<base64url path> |
Les octets d’un fichier, en sortie |
- HTTP, pas RPC. La socket RPC ferme la connexion sur une trame entrante de plus de 256 Ko — une protection anti-DoS adaptée aux commandes JSON et fatale pour une capture d’écran collée. Les octets empruntent le même genre de route que celle déjà utilisée par les trames des rigs et l’audio des réunions.
- L’authentification repose sur la cible signée
rig-files:<workspaceId>/<rigId>plus l’appartenance à l’espace de travail — une cible à part, afin qu’une URL émise pour regarder une machine ne puisse pas aussi y écrire des fichiers. - La prise de contrôle s’applique. L’écriture dans le presse-papiers et le dépôt de fichiers sont des actions modificatrices et sont refusées tant que quelqu’un d’autre détient le contrôle ; la lecture du presse-papiers et l’extraction d’un fichier relèvent de l’observation et ne le sont pas.
- Où atterrissent les dépôts :
~/Drops(bureau),~/drops(terminal — à côté de l’arbre de travail, jamais dedans, pour qu’un dépôt n’apparaisse jamais comme une modification non suivie),/tmp/cc-drops(navigateur). Le serveur choisit le répertoire ; un appelant ne peut pas le nommer. Les fichiers existants ne sont jamais écrasés — un nom en collision arrive sous la forme2-name.ext. - Ce que l’on annonce à l’invité : une page de navigateur reçoit un vrai
événement de dépôt au point demandé (
Input.dispatchDragEvent) ; un bureau reçoit les fichiers et leurs URI dans son presse-papiers, car aucun hôte ne peut synthétiser un glisser XDND vers une boîte à outils arbitraire sans un démon privilégié dans l’invité. La réponse indique laquelle des deux possibilités s’est produite. - Le glisser vers l’extérieur ne concerne que le bureau et lit la
XdndSelectionde l’invité pendant qu’un glisser est en cours. Une charge utile identique à ce que l’invité détenait déjà au début de l’appui est traitée comme une sélection obsolète d’un glisser terminé, et non comme une nouvelle — X n’a pas d’étape « le glisser est terminé ». - Exigences relatives à l’image : l’image de bureau doit être en protocole 2 ou ultérieur (construite après l’arrivée de la prise en charge du presse-papiers). Une image plus ancienne répond 404 et l’application invite à la reconstruire plutôt que de signaler une machine en panne.
- Le journal d’audit consigne la forme, jamais le contenu : les lignes
clipboard_read,clipboard_write,drop_filesetread_fileportent des compteurs, des tailles et des chemins. Un presse-papiers est l’endroit où des identifiants vivent quelques secondes à la fois, et rien de tout cela n’est écrit.
Garde-fous, événements, stockage
Section intitulée « Garde-fous, événements, stockage »- Les outils de rig déclarent la classe d’actions
enclosureControl(plusnetworkEgressetprocessSpawnsur les outils d’utilisation ;mobile_useetios_usedéclarent aussipackageInstall).rig_closedéclareenclosureControl;rig_listn’en déclare aucune. Autorisée par défaut ; les modes en lecture seule la refusent catégoriquement ; le curseur d’autonomie par espace peut la ramener à « demander d’abord ». - Événements de domaine :
RigClosedEvent(avec son motif de fermeture),RigControlChanged(prise de contrôle / restitution),RigReaped(éviction pour inactivité, TTL ou mémoire, avec l’agent pilote). L’ouverture d’un rig n’est pas un événement. Voir événements de domaine. - Stockage :
rig_sessionsetrig_action_logdans la base de données de chaque espace de travail. Le journal d’actions consigne chaque événement d’entrée avec son principal et une séquence monotone par rig ; le texte saisi est réduit à une longueur et un hachage avant d’être écrit. - Répertoire de données :
rigs/images/(images qcow2 importées),rigs/smolvm/(état d’exécution par rig),rigs/smolvm-packs/(packs de machines pré-extraits),rigs/tls/(l’autorité de certification des domaines de développement),rigs/run/(surcouches et amorces QEMU). - Routes : la vue en direct est un onglet dans un espace ou une page de PR ;
/settings/server/rigsest l’écran de réglages des Rigs.