terminal-mac: полноценный macOS для ИИ-агентов в терминале

· 8 мин чтения
computer-use macos virtualization mcp terminal
📂 Исходный код на GitHub

Отдельный рабочий стол macOS для computer-use агентов: виртуальная машина на Apple Virtualization, просмотр и управление из терминала.

terminal-mac: полноценный macOS для ИИ-агентов в терминале

terminal-mac — утилита для Mac на Apple Silicon, которая запускает настоящую виртуальную машину с macOS и показывает её экран прямо в окне терминала. ИИ-агент получает внутри этой машины управление компьютером (computer use): он видит экран, двигает курсор, набирает текст и нажимает клавиши. При этом ваш основной рабочий стол, буфер обмена и курсор физического Mac остаются нетронутыми. Проект написан на Swift, распространяется по лицензии MIT и сейчас находится на стадии раннего релиз-кандидата.

Зачем нужен отдельный виртуальный Mac

Современные агенты вроде Claude Code, Cursor или Codex уверенно работают с кодом через файлы и API. Но многие задачи требуют полноценного графического интерфейса: установить и настроить приложение, пройтись по системным настройкам, поработать в браузере. Давать агенту управление своим основным Mac рискованно — он получит доступ к вашим файлам, сессиям и учётным записям.

terminal-mac решает эту проблему: агент работает внутри отдельного виртуального Mac, у которого собственные приложения, файлы, учётные записи и разрешения. Гость не наследует ни запущенные приложения хоста, ни ваши залогиненные сессии. Единственная цена — ВМ потребляет CPU, память и диск основного Mac.

Как это устроено

Архитектура состоит из трёх частей:

  • Гость. Apple Virtualization запускает настоящий macOS. Внутри гостя работает вспомогательное приложение TerminalMacGuest.app: оно захватывает экран через ScreenCaptureKit и отправляет события ввода.
  • Просмотрщик в терминале. Экран гостя транслируется в терминал через графические протоколы Kitty, Ghostty или iTerm2. Кадры отправляются только при изменении экрана, до 30 кадров в секунду, со сжатием lz4 без потерь. Kitty и Ghostty получают кадры через разделяемую память, а не через pty. Простой рабочий стол не передаёт ничего, поток останавливается через 15 секунд после закрытия просмотрщика.
  • Управление. Команды агента идут через тот же гостевой хелпер, поэтому физический курсор и буфер обмена хоста не затрагиваются.

Новые ВМ по умолчанию используют дисплей 2x HiDPI: для стандартных 1280×800 точек это 2560×1600 пикселей, поэтому текст остаётся чётким на Retina-терминалах. Переключить режим можно командой terminal-mac display default --hidpi или --standard на остановленной ВМ.

Требования и установка

Что понадобится:

  • Mac на Apple Silicon с macOS 14 или новее;
  • интернет при первом запуске — образ macOS скачивается прямо с серверов Apple (или готовый локальный файл .ipsw);
  • место под кэш образа и растущий диск ВМ (по умолчанию 64 ГиБ логического объёма);
  • терминал Ghostty, Kitty или iTerm2 для встроенного просмотрщика; остальные терминалы получают нативное окно ВМ и CLI.

Для готового релиза инструменты разработчика не нужны. Установка одной командой:

curl -fsSL https://github.com/govijr/terminal-mac/releases/latest/download/get.sh | bash

Установщик скачивает последний релиз, проверяет его SHA-256 и кладёт лаунчер в ~/.local/bin, а рантайм — в ~/.local/lib/terminal-mac. Права администратора не нужны, конфигурацию шелла он не меняет.

Первый запуск terminal-mac up ведёт вас по шагам: скачивает и кэширует подходящий образ восстановления Apple, устанавливает виртуальный Mac, загружает его и проверяет гостевой хелпер. Последующие запуски переиспользуют существующую ВМ и просто подключаются к ней.

Есть и другие варианты запуска:

terminal-mac up work                  # another virtual Mac
terminal-mac up --ipsw /path/mac.ipsw  # use a local image
terminal-mac up --no-view             # wait for agent readiness, then return JSON
terminal-mac up --detach              # install/boot, return without waiting for guest setup
terminal-mac up --plan                # show steps without network access or disk changes

Первая загрузка образа может занять время — скачать и установить macOS за один момент не выйдет. Кэш образа переиспользуется, а недокачанная загрузка возобновляется после сбоя сети.

Настройка гостя (один раз)

Первый запуск открывает окно виртуального Mac. Дальше по шагам:

  1. Пройдите Setup Assistant macOS и создайте учётную запись гостя.
  2. Внутри гостя откройте Finder → /Volumes/My Shared Files/tools → TerminalMacGuest.app. Хелпер установит себя в ~/Applications гостя и зарегистрируется на будущие входы в систему.
  3. Кнопками хелпера выдайте в госте два разрешения: Screen Recording и Accessibility. Основному Mac они не нужны.
  4. Держите гостя залогиненным и хелпер запущенным.

После этого CLI автоматически перейдёт к терминальному рабочему столу. Это управляемая настройка, а не безлюдная установка: более новый автоматический механизм из macOS 27 этот сборка пока не использует.

Подключение ИИ-агента

terminal-mac даёт агентам computer use через два интерфейса: MCP-инструменты (screenshot, click, drag, scroll, type, key, status) и skill, который обучает агента циклу observe → act → verify: посмотреть на экран, сделать действие, проверить результат.

Claude Code — всё сразу одним плагином:

/plugin install terminal-mac --marketplace govijr/terminal-mac

Или по отдельности:

claude mcp add terminal-mac -- terminal-mac mcp
terminal-mac skills install                 # → ~/.claude/skills/terminal-mac/SKILL.md

Другие MCP-клиенты (Cursor, VS Code, Codex, Windsurf…): вставьте вывод команды terminal-mac mcp --config в настройки MCP своего клиента. terminal-mac mcp NAME подключает ВМ с именем, отличным от default.

Любой агент с папкой skills: terminal-mac skills install --dir PATH или npx skills add govijr/terminal-mac --skill terminal-mac. В AGENTS.md достаточно строки вида «Before using the virtual Mac, run terminal-mac skills get» — агент получит инструкции, соответствующие установленной версии.

Инструменты управляют только гостевым хелпером и никогда не трогают ваш рабочий стол. Если гость стоит на экране входа, инструменты об этом сообщают — и агент попросит вас войти в систему.

Управление агентом из CLI

Помимо MCP, гостем можно управлять прямо из командной строки:

./dist/terminal-mac action default screenshot --output /tmp/guest.png
./dist/terminal-mac action default click 640 400
./dist/terminal-mac action default type 'Hello from the agent'
./dist/terminal-mac action default key cmd+space
./dist/terminal-mac action default key return
./dist/terminal-mac action default scroll --dy -300 --x 640 --y 400

Команды возвращают JSON, а при ошибке — ненулевой код выхода. Скриншоты сохраняются в PNG на хосте. Координаты отсчитываются от левого верхнего угла и соответствуют размерам скриншота, поэтому агенту легко сопоставить картинку с точкой клика даже на Retina. Команда snapshot пока что просто псевдоним screenshot, а не снимок accessibility-дерева.

Просмотрщик поддерживает набор текста, одиночные, двойные и тройные клики, перетаскивание, прокрутку и стандартные клавиши. Ctrl+G открывает палитру мак-шорткатов (Spotlight, Mission Control, копирование и вставка) — терминалы держат ⌘ для себя. Ctrl+] выходит из просмотрщика, не останавливая ВМ.

Готовые инструкции для агентов лежат в docs/AGENT.md. Глобальные настройки агентов проект не меняет.

Жизненный цикл и ресурсы

./dist/terminal-mac ls
./dist/terminal-mac status default
./dist/terminal-mac pause default
./dist/terminal-mac resume default
./dist/terminal-mac show default
./dist/terminal-mac stop default          # request a normal guest shutdown
./dist/terminal-mac stop default --force  # immediate power-off; unsaved guest work can be lost

Новую ВМ можно настроить флагами: --cpus 4 --memory 4 --disk 64 --width 1280 --height 800. Флаг --offline убирает у гостя сетевое устройство — канал управления через общую папку продолжает работать.

Данные ВМ живут в ~/Library/Application Support/terminal-mac/machines/NAME/. Переменная TERMINAL_MAC_HOME меняет корень данных. У каждой ВМ есть эксклюзивная файловая блокировка, динамически растущий диск, аппаратная идентичность, файл machine.json, приватный почтовый ящик управления и журнал runtime.log. Загрузка ВМ идёт отдельным фоновым процессом, поэтому команды жизненного цикла должны использовать тот же TERMINAL_MAC_HOME, что и запустивший её процесс.

Прерванная установка оставляет каталог с меткой installed: false и никогда не перезаписывается молча. Деструктивной команды удаления ВМ пока намеренно нет.

Модель изоляции

Безопасность здесь продумана на уровне транспорта:

  • Действия агента не используют API ввода и экрана хоста. Хелпер отказывается работать, если модель устройства (hw.model) не начинается с VirtualMac. Это защита от случайного запуска на основном Mac, а не аппаратная гарантия.
  • Гость видит ровно два общих ресурса: control (чтение и запись: JSON-запросы, ответы, скриншоты) и tools (приложение-хелпер, только чтение). Домашняя папка хоста, проекты, буфер обмена, микрофон и камера не подключены.
  • Сетевого слушателя удалённого управления нет. «Почтовый ящик» на общей папке проверяет пути (отвергает симлинки, жёсткие ссылки и нестандартные файлы), ограничивает размер сообщений, сверяет идентификаторы запросов и снимает просроченные действия. Хост никогда не исполняет контент, присланный гостем.
  • Сеть по умолчанию работает через NAT: у гостя есть интернет, и он может достучаться до сервисов хоста и локальной сети. Это не среда, изолированная по сети, и не песочница для враждебного кода. Флаг --offline убирает этот канал.
  • Разрешения TCC выдаются вручную внутри гостя. Разлогиненный или заблокированный гость, отсутствие хелпера или отказ в разрешениях блокируют управление.

В планах у автора: клонирование ВМ, контрольные точки для отката, accessibility-снимки, полностью безлюдная установка гостя, сплиты терминала и транспорт через tmux.

Сборка из исходников и проверки

bash scripts/build.sh
./dist/terminal-mac doctor

Сборка создаёт dist/TerminalMac.app вместе с гостевым приложением и лаунчером dist/terminal-mac. Виртуализации нужен entitlement com.apple.security.virtualization, поэтому используйте собранный лаунчер, а не сырой бинарник Swift. Стабильная самоподписанная личность подписи («Govijr Code Signing») сохраняет разрешения хелпера между пересборками; ad-hoc подпись требует выдавать их заново. Детали подписи и публикации описаны в RELEASING.md.

Автотесты покрывают обмен сообщениями почтового ящика, истечение и очистку, защиту границ файлов, валидацию имён и опций, фрагментированный UTF-8 и терминальные последовательности ввода. Записанные результаты и живой чек-лист — в docs/VALIDATION.md.

Среди источников, на которые ссылается автор: проект terminal-browser, пример Apple по виртуализации macOS, документация VZVirtualMachineView и ScreenCaptureKit.

Источник: https://github.com/govijr/terminal-mac