Rigs
Только факты. Чтобы понять модель, стоящую за ними, читайте Rigs и изолированные среды; чтобы открыть машину, следуйте руководству.
Поверхности и бэкенды
Заголовок раздела «Поверхности и бэкенды»| Поверхность | Управляет | Бэкенд | Значение | Ограниченный исходящий доступ |
|---|---|---|---|---|
| Терминал (exec) | Оболочка через exec-канал VM | microVM | smolvm |
Да |
| Браузер | Безголовый Chromium (CDP), Firefox (WebDriver BiDi) или WebKit (W3C WebDriver) | microVM | smolvm |
Да |
| Компьютер | Рабочий стол X11: ввод через гипервизор, захват через гостевого агента | QEMU | qemu-hvf (macOS), qemu-kvm (Linux), qemu-tcg (неускоренный запасной вариант, никогда не выбирается автоматически) |
Да |
| Android | Android через ADB | Эмулятор Google | android-emulator |
Нет — эмулятор сам управляет своей сетью |
| iOS | Симулятор iOS через WebDriverAgent | CoreSimulator | ios-simulator |
Нет — сеть следует за хостом Mac |
Терминал и поверхность computer_use используют одно значение поверхности —
computer; терминал отличается маркером своего exec-образа и никогда не
переиспользуется как управляемый рабочий стол (и наоборот). Один разговор
переиспользует одну терминальную машину.
Браузерные движки
Заголовок раздела «Браузерные движки»| Движок | Значение | Протокол | Живой просмотр | Статичные кадры |
|---|---|---|---|---|
| Chromium | chromium (по умолчанию) |
Chrome DevTools Protocol | Скринкаст — браузер проталкивает кадры по мере перерисовки страницы | JPEG |
| Firefox | firefox |
WebDriver BiDi | Опрашиваемые статичные кадры (в BiDi нет скринкаста), не чаще 6 кадров/с | JPEG |
| WebKit | webkit |
W3C WebDriver (классический) | Опрашиваемые статичные кадры, транскодируются ffmpeg на хосте | PNG |
Rig работает с одним движком всю свою жизнь. Один разговор может держать по одному rig на движок, и именно это делает возможным сравнение бок о бок: открыть «Firefox (VM)» рядом с «Chromium (VM)» — это две машины, и закрытие одной оставляет другую работать.
Передайте engine в rig.open или в инструмент browser_use. Неизвестное имя
отклоняется, а не подменяется значением по умолчанию: попросить браузер и молча
получить другой — значит ответить на вопрос о совместимости неправильным
ответом.
Ограничения конкретных движков проговариваются, а не обходятся:
- Firefox не умеет перезагружаться в обход кэша (он прямо отклоняет
ignoreCacheиз BiDi), поэтому жёсткая перезагрузка — это обычная перезагрузка. - WebKit тоже не умеет перезагружаться в обход кэша и не имеет потока
консоли (вывод перехватывается хуком на
console.*после каждой навигации, поэтому всё, что залогировано во время загрузки, теряется — об этом сообщает каждое извлечение консоли), а для живого просмотра ему нуженffmpegна хосте. - Ни один из них не отдаёт дерево доступности платформы по своему протоколу,
поэтому
extract (a11y)возвращает приближение, построенное из DOM, и помечено как таковое. - Ни один из них не принимает настоящий сброс файлов; но поле выбора файла всё ещё можно навести на пути внутри машины.
Образы машин
Заголовок раздела «Образы машин»| Поверхность | Образ | Получение |
|---|---|---|
| Терминал | ubuntu:24.04, закреплён по дайджесту |
Автоматически при первой загрузке, через собственную сеть машины за шлюзом |
| Браузер (Chromium, Firefox, WebKit) | debian:trixie-slim, закреплён по дайджесту, плюс собственные пакеты движка |
Автоматически при первой загрузке, затем кэшируется как прогретый пакет |
| Компьютер | Образ рабочего стола qcow2 с Chromium, Firefox, WebKit и тем же базовым набором CLI, как у раннера, размещённого на GitHub, который прогревает терминал | Импорт в разделе Настройки → Сервер → Rigs (загрузки, закреплённые по контрольной сумме, где они опубликованы) |
| Android | Системные образы Google | Через Android SDK |
| iOS | Среда выполнения симулятора Xcode плюс WebDriverAgent, закреплённый по контрольной сумме | Среда выполнения — через Xcode; мост автоматизации — из раздела Настройки → Сервер → Rigs |
После первой загрузки каждого вида microVM сервер кэширует предварительно
распакованную копию в каталоге данных и загружает из неё каждую следующую
машину — включая заранее прогретые образы с уже установленными пакетами.
Терминал прогревает базовый набор CLI, как у раннера, размещённого на GitHub
(git, gcc, python3, jq, rsync, инструменты для архивов и остальной
базовый набор apt; но не Docker и не toolcache языков). Образ «Компьютер» qcow2
запекает те же имена CLI во время сборки образа, рядом с XFCE и тремя браузерами.
Каждый браузер прогревает свой движок. Все три движка используют общий базовый
образ Debian, но никогда не делят один пакет: кэш привязан к образу, движку и
ревизии аудио (audio-v1-<engine>), потому что машина, прогретая для одного
движка — или до того, как PulseAudio и ffmpeg вошли в рабочую нагрузку, — не
содержит ничего из другого. Пакет терминала по той же причине привязан к ревизии
набора инструментов (tools-v1): пакет, прогретый до того, как компилятор стал
частью образа, не должен обслуживать машину, у которой он должен быть.
Готового образа автоматизации, который стоило бы взять, нет: chromedp/headless-shell
от Chromium собирается без ALSA и PulseAudio, поэтому он в принципе не может
издавать звук; единственный поддерживаемый образ Firefox в 33 раза больше
базового Debian и всё равно не содержит socat; поддерживаемого образа WebKit
нет вообще. Поэтому каждый движок устанавливается при первом запуске (chromium,
firefox-esr или webkit2gtk-driver) и делает это, обращаясь к архивам Debian
(deb.debian.org, security.debian.org, cloudfront.debian.net). Chromium —
это дистрибутивный бинарник, запускаемый как chromium --headless=new.
Свои образы для рабочего пространства
Заголовок раздела «Свои образы для рабочего пространства»| Ключ настройки | Что переопределяет |
|---|---|
rigs.smolvm.execImage |
Образ Terminal (VM) |
rigs.smolvm.browserImage |
Образ Chromium Browser (VM) |
Записывается через хранилище настроек рабочего пространства с проверкой администратора (Настройки → Сервер → Rigs → Свои образы (это рабочее пространство)). Значение должно быть ссылкой на реестр — локальные пути, архивы и строки, похожие на флаги, отклоняются, причём и в поле, и повторно при загрузке. Недопустимое сохранённое значение игнорируется с громким предупреждением, и вместо него загружается образ по умолчанию. Собственный реестр образа (а также известные сопутствующие blob-CDN для Docker Hub, GHCR, Quay, GitLab и GCR) допускается через шлюз исходящего доступа для загрузки.
Контракт образа терминала — bash присутствует; git, curl, socat
предустановлены или есть базовый образ Debian/Ubuntu с apt (при первом запуске
изолированная среда ставит эти три пакета плюс базовый набор CLI, как у раннера,
размещённого на GitHub: компиляторы, Python 3, jq, инструменты для архивов,
rsync. Toolcache языков и Docker не устанавливаются).
Контракт образа браузера — базовый образ Debian/Ubuntu с apt (или уже
установленные пакеты) с bash и socat, плюс бинарник chromium, который сервер
сам запускает как chromium --headless=new с DevTools на гостевом loopback
9223, проброшенном на гостевой порт 9222. Для звукового канала при первом
запуске устанавливаются PulseAudio и ffmpeg. Не собирайте
FROM chromedp/headless-shell: вышестоящий headless.gn собирается без ALSA и
PulseAudio, поэтому такой бинарник не может издавать звук. Переопределение
применяется только к Chromium-rig — команда рабочей нагрузки, которую он
загружает, принадлежит Chromium, и передача её Firefox или WebKit запустила бы
бинарник, которого там нет. Rig на Firefox или WebKit игнорирует его с громким
предупреждением и загружает свой закреплённый образ.
Порты автоматизации — каждая браузерная машина пробрасывает ровно один
loopback-порт хоста на гостевой 9222. За ним: DevTools Chromium и удалённый
агент Firefox сидят на гостевом loopback 9223, а перед ними стоит ретранслятор
socat (оба безусловно привязываются к loopback); драйвер WebKit принимает
--host и сам привязывается к сетевому интерфейсу гостя. Firefox вдобавок
проверяет заголовок Host на соответствие своему порту, поэтому клиент
отправляет гостевую authority, а не ту, к которой он подключался.
Глаголы действий
Заголовок раздела «Глаголы действий»Каждое действие разбирается полностью: некорректная полезная нагрузка возвращает сообщение с именем поля, но никогда — исключение. Наблюдательные глаголы (помеченные ○) остаются разрешёнными, пока управление у человека; изменяющие глаголы отклоняются.
computer_use
Заголовок раздела «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 с), type, wait○ (0–60 с), set_display,
clipboard_read○, clipboard_write.
Координаты — это гостевые пиксели в текущем режиме гостя; каждый снимок экрана
указывает размер дисплея. Сочетания клавиш используют написание X11 (ctrl+s,
alt+Tab, Return).
clipboard_read принимает selection: clipboard (то, что заполняет ctrl+C;
значение по умолчанию), primary (выделение-копирование в X11) или xdnd
(перетаскивание в процессе). Пустой результат — нормальный ответ для всех трёх.
clipboard_write принимает только text — изображения и файлы идут по файловому
каналу, потому что аргументы действия сохраняются в журнал аудита, а байтам
изображений там не место. Содержимое буфера обмена возвращается обрамлённым как
недоверенные данные.
browser_use
Заголовок раздела «browser_use»navigate (только http/https), reload (необязательный hard), stop_loading,
click (селектор или координата), fill, type, key (имена клавиш DOM),
scroll, mouse_move, drag, left_mouse_down, left_mouse_up,
extract○ (a11y | dom | console), screenshot○ (необязательный
full_page), set_viewport (минимум 320×240), history, wait_for○ (селектор,
0,1–30 с), clipboard_read○, clipboard_write.
Извлечённое содержимое страницы возвращается обрамлённым как недоверенные данные.
У браузера ровно один буфер обмена, поэтому clipboard_read не принимает
selection. Оба глагола буфера обмена требуют защищённого контекста: у
страницы, отданной по обычному http://, API буфера обмена нет вообще, и глагол
говорит об этом, а не сообщает о пустом буфере — используйте там type, который
вставляет по каретке, не проходя через буфер обмена.
mobile_use
Заголовок раздела «mobile_use»tap, swipe (50–5000 мс), type, key (алиасы back, home,
recents, enter, delete, backspace, tab, escape, search,
menu, volume_up, volume_down, power или любой KEYCODE_*),
screenshot○, ui_dump○, install_apk
(ограничен worktree rig и каталогом данных сервера), start_app,
stop_app, clear_app_data, uninstall_app, open_url и shell.
shell принимает список argv и выполняется внутри Android, никогда через
оболочку хоста; он покрывает диагностику для разработчиков, такую как logcat,
dumpsys и pm grant.
У mobile_use нет глаголов буфера обмена. Начиная с Android 10 читать буфер
обмена может только приложение в фокусе.
ios_use
Заголовок раздела «ios_use»tap, swipe (50–5000 мс), type, key (enter, backspace, tab,
escape, клавиши-стрелки или один печатный символ; необязательные модификаторы
command, control, option и shift), home, lock, unlock,
screenshot○, ui_dump○, install_app (каталог .app симулятора,
ограниченный worktree rig или каталогом данных сервера), start_app, stop_app,
uninstall_app, open_url и spawn. spawn принимает argv и выполняет его
внутри симулятора через simctl; он никогда не вызывает оболочку хоста.
Координаты — это точки экрана iOS, а не пиксели снимка. Живой поток сохраняет фиксированный размер симулятора и добавляет поля вместо изменения размера устройства. Передача текста через буфер обмена хост→симулятор и симулятор→хост использует ту же политику разрешений для каждого пользователя и каждого направления, что и другие rig; файлы и изображения не принимаются каналом буфера обмена iOS.
Каждый rig создаёт собственное устройство CoreSimulator и сессию WebDriverAgent. При его закрытии останавливается WebDriverAgent, устройство выключается и удаляется, а его запись в реестре удаляется. iOS-rig работают только на сервере macOS с Xcode, установленной средой выполнения iOS и закреплённым мостом автоматизации. Они не предоставляют ни звука, ни микрофона, ни сброса файлов, ни оболочки хоста, ни гарантии изолированной сети.
Инструменты управления
Заголовок раздела «Инструменты управления»| Инструмент | Описание |
|---|---|
rig_list |
Перечисляет rig рабочего пространства с поверхностью, статусом, дисплеем и контроллером |
rig_close |
Уничтожает rig и отбрасывает его диск |
Жизненный цикл
Заголовок раздела «Жизненный цикл»| Фаза | Значение |
|---|---|
provisioning |
Загрузка; деталь статуса дословно передаёт текущий шаг |
ready |
Доступен и принимает действия |
parked |
Припаркован по простою: vCPU остановлены, RAM остаётся резидентной; следующее действие его будит |
closing |
Завершает работу |
closed |
Исчез; запись сохраняется для журнала аудита |
failed |
Умер или так и не поднялся; отличается от других, чтобы интерфейс мог предложить повтор |
| Причина закрытия | Когда срабатывает |
|---|---|
requested |
Человек или агент попросил |
idleTimeout |
Простой дольше 2× окна простоя или вытеснение из-за памяти |
ttlExpired |
Истёк жёсткий срок жизни |
conversationEnded |
Разговор-владелец завершился |
workspaceGone |
Рабочее пространство удалено или утрачено членство |
serverShutdown |
Сервер останавливается |
backendFailure |
Гипервизор под ним умер |
Значения по умолчанию и потолки
Заголовок раздела «Значения по умолчанию и потолки»| Значение | Терминал | Браузер | Компьютер | Мобильные |
|---|---|---|---|---|
| Память | 512 МБ | 2048 МБ (Chromium); 2560 МБ (Firefox, WebKit) | 4096 МБ | 4096 МБ |
| vCPU | 2 | 2 | 4 | 4 |
| Жёсткий TTL | 8 ч | 2 ч | 2 ч | 2 ч |
| Окно простоя | 45 мин | 15 мин | 15 мин | 15 мин |
| Экран при загрузке | — | 1280×800 | 1280×800 | 1080×1920 |
- Статичные кадры канала агента ограничены 1280×800; человеческий канал согласует размер вплоть до 2560×1600.
- Бюджет резидентной памяти хоста для всех rig по умолчанию — 12 ГБ, считается в резидентных мегабайтах (припаркованная VM всё ещё удерживает свою RAM). Вытеснение идёт по принципу «дольше всего не использовался» и никогда не забирает машину, которой кто-то управляет, которую смотрит или в которой открыт терминал.
- Открытый терминал или канал наблюдения удерживает rig от парковки и сбора по простою; жёсткий TTL всё равно действует.
Порты и dev-домены
Заголовок раздела «Порты и dev-домены»| Порт | Где | Зарезервирован для |
|---|---|---|
7911 |
Терминальный гость | Мультиплексор портов, через который идёт каждый проброс |
9222, 9223 |
Гостевой браузер | Ретранслятор и конечная точка автоматизации (WebKit привязывается к 9222 напрямую и не использует ретранслятор) |
80, 443 |
Гостевой loopback браузера | Каналы HTTP/HTTPS dev-доменов |
- Обнаружение опрашивает слушающие TCP-порты терминального гостя примерно каждые 4 с, на стороне сервера.
- На каждый rig автоматически пробрасывается не более 16 портов; остальные перечисляются в журнале, но не пробрасываются.
- Проброс на стороне хоста привязывается к loopback, предпочитая собственный номер порта гостя; Открыть в локальной сети добавляет порт в локальной сети, назначенный ОС.
- Dev-домены должны соответствовать
name.testилиname.localhost(нижний регистр, метка не длиннее 63 символов). Один домен соответствует одному порту. - HTTPS dev-домена использует локальный на сервере удостоверяющий центр (EC
P-256, в
<dataDir>/rigs/tls/, ключи с правами 0600 и никогда не в госте) с одним wildcard-сертификатом для*.test/*.localhost. Нетopensslна хосте — нет канала HTTPS; обычный HTTP всё равно маршрутизируется.
Исходящий доступ по умолчанию
Заголовок раздела «Исходящий доступ по умолчанию»| Поверхность | Разрешённые хосты по умолчанию |
|---|---|
| Терминал | Базовый набор разработчика песочницы (хосты кода, реестры пакетов, провайдеры моделей) + зеркала apt Ubuntu + собственный хост кода worktree |
| Браузер | usectrl.dev (сайт продукта) — плюс архивы Debian при первой загрузке каждого движка, пока он ставит свои пакеты. Домашняя страница — локальный документ file://, и исходящий доступ ей не нужен |
| Компьютер | Пусто — запрещено всё — пока вызывающий не предоставит хосты |
| Мобильные | Не применяется (сетью управляет эмулятор) |
Каждая microVM вдобавок получает хосты реестра своего образа, и только для загрузки. Набор разрешённых хостов брокера учётных данных выводится из того же списка: токен не выпускается для хоста, до которого гость не может добраться.
Буфер обмена и передача файлов
Заголовок раздела «Буфер обмена и передача файлов»Копирование и вставка в обе стороны, а также перетаскивание файлов внутрь и наружу. Доступно человеку, управляющему rig; агент получает буфер обмена через глаголы выше и вообще не получает передачу файлов (у него уже есть оболочка внутри изолированной среды).
Пересечение буфера обмена настраивается для каждого пользователя и каждого направления. Вставка хост→rig разрешена по умолчанию; копирование rig→хост запрашивает подтверждение (разрешение на десять минут или «всегда разрешать» в разделе Настройки → Сервер → Rigs → Доступ к буферу обмена). Эти два выбора независимы и никогда не являются настройкой рабочего пространства.
| Канал | Маршрут | Переносит |
|---|---|---|
| Буфер обмена | GET/POST /rig/clipboard/<rigId> |
Текст, одно изображение PNG/JPEG (≤16 МБ) и гостевые пути файлов в буфере обмена |
| Файлы | POST /rig/files/<rigId> |
До 64 файлов, ≤256 МБ каждый и ≤512 МБ на один сброс, с необязательной точкой сброса в гостевых пикселях |
| Файлы | GET /rig/files/<rigId>?p=<base64url path> |
Байты одного файла, обратно наружу |
- HTTP, а не RPC. Сокет RPC закрывает соединение при входящем фрейме больше 256 КБ — защита от DoS, которая правильна для JSON-команд и фатальна для вставленного снимка экрана. Байты идут по тому же виду маршрута, что уже используют кадры rig и звук встреч.
- Аутентификация — это подписанная цель
rig-files:<workspaceId>/<rigId>плюс членство в рабочем пространстве; отдельная цель, поэтому URL, выпущенный, чтобы смотреть машину, не может ещё и писать в неё файлы. - Перехват управления действует. Запись в буфер обмена и сброс файлов — изменяющие операции, и они отклоняются, пока управление у кого-то другого; чтение буфера обмена и вычитывание файла — наблюдение, и они не отклоняются.
- Куда попадают сбросы:
~/Drops(рабочий стол),~/drops(терминал — рядом с worktree, но никогда внутри него, поэтому сброс никогда не появляется как неотслеживаемое изменение),/tmp/cc-drops(браузер). Каталог выбирает сервер; вызывающий не может его назвать. Существующие файлы никогда не перезаписываются — конфликтующее имя попадает как2-name.ext. - Что сообщается гостю: страница браузера получает настоящее событие сброса в
запрошенной точке (
Input.dispatchDragEvent); рабочий стол получает файлы плюс их URI в своём буфере обмена, потому что ни один хост не может синтезировать перетаскивание XDND в произвольный инструментарий без привилегированного демона внутри гостя. Ответ сообщает, что именно из двух произошло. - Перетаскивание наружу работает только на рабочем столе и читает
XdndSelectionгостя, пока перетаскивание активно. Полезная нагрузка, идентичная тому, что гость уже держал в момент начала нажатия, считается устаревшим выделением от завершённого перетаскивания, а не новым, — в X нет шага «перетаскивание завершено». - Требования к образу: образ рабочего стола должен быть протокола 2 или новее (собран после появления поддержки буфера обмена). Старый образ отвечает 404, и приложение говорит пересобрать его, а не сообщает о сломанной машине.
- Журнал аудита фиксирует форму, но никогда содержимое: записи
clipboard_read,clipboard_write,drop_filesиread_fileнесут количества, размеры и пути. Буфер обмена — это место, где учётные данные живут по несколько секунд, и ничего из этого не записывается.
Ограничения, события, хранилище
Заголовок раздела «Ограничения, события, хранилище»- Инструменты rig объявляют класс действий
enclosureControl(плюсnetworkEgressиprocessSpawnу инструментов использования;mobile_useиios_useтакже объявляютpackageInstall).rig_closeобъявляетenclosureControl;rig_listне объявляет ничего. Разрешён по умолчанию; режимы только для чтения запрещают его целиком; регулятор автономии пространства может понизить его до «Спросить сначала». - Доменные события:
RigClosedEvent(с причиной закрытия),RigControlChanged(перехват управления / возврат управления),RigReaped(сбор по простою, TTL или из-за памяти, с указанием управляющего агента). Открытие rig не является событием. См. доменные события. - Хранилище:
rig_sessionsиrig_action_logв базе данных каждого рабочего пространства. Журнал действий записывает каждое событие ввода с его субъектом и монотонно возрастающим номером для каждого rig; введённый текст перед записью обезличивается до длины и хеша. - Каталог данных:
rigs/images/(импортированные образы qcow2),rigs/smolvm/(состояние среды выполнения каждого rig),rigs/smolvm-packs/(предварительно распакованные пакеты машин),rigs/tls/(удостоверяющий центр dev-домена),rigs/run/(оверлеи и seed-файлы QEMU). - Маршруты: живой просмотр — это вкладка в пространстве или на странице PR;
/settings/server/rigs— экран настроек Rigs.