ИИ / Автоматизация 21 мая 2026

Запуск шлюза OpenClaw через launchd на Mac mini: абсолютный путь к node, ProcessType и исправление выхода 78 (2026-05-21)

Инженерная команда ProxyMac 21 мая 2026 ~18 мин чтения

После перезагрузки LaunchAgent шлюза OpenClaw на арендованной Mac mini M4 в Гонконге, Японии, Корее, Сингапуре или США может не привязать админ-порт, завершиться с кодом 78 в launchctl list или потратить примерно три минуты, прежде чем WebSocket-клиенты перестанут видеть аномальные закрытия 1006. Этот runbook от 21 мая 2026 нацелен на ошибки plist launchd — «голый» node в ProgramArguments и отсутствие ProcessType со значением Interactive — а не на сиротские деревья MCP. Он дополняет восстановление после перезапуска шлюза, чеклист headless SSH при первой загрузке и согласование runtime Node / nvm.

Выход 78, медленный listen и WebSocket 1006 при холодной загрузке

В сообществах на хостах Apple Silicon описывают две разные формы сбоя launchd. Мгновенный выход 78 означает, что launchd так и не выполнил exec бинарника шлюза — часто потому, что ProgramArguments начинается со строки node, пока окружение launchd имеет пустой или минимальный PATH. Задержанная готовность показывает задание «running» в launchctl list, но lsof не находит listener минутами; дашборды тогда логируют код закрытия WebSocket 1006, пока процесс наконец не получит планировщик. Оба сценария отличаются от циклов падений ThrottleInterval, которые бьют по CPU быстрыми перезапусками.

  • Код выхода 78 сразу после launchctl bootstrap или входа в систему — проверьте ~/Library/LaunchAgents/*.plist на «голый» node.
  • 180+ секунд от загрузки до первой успешной health-пробы на иначе простаивающей mini.
  • 1006 на управляющем WebSocket, пока SSH работает и диск здоров — listener ещё не поднят, а не ошибка TLS.
  • Ручной node gateway.js по SSH работает, а путь LaunchAgent падает — классическое расхождение PATH vs абсолютный бинарник.
Не путайте с дрейфом semver Node: если node -v различается между login-оболочкой и plist, сначала прочитайте статью о расхождении runtime. Выход 78 — «бинарник не найден»; mismatch — «найден, но неверный ABI».

Почему launchd игнорирует PATH оболочки и понижает приоритет фоновых агентов

LaunchAgents наследуют урезанное окружение по сравнению с интерактивными сессиями Terminal.app. Документация и полевые треды подчёркивают, что EnvironmentVariables в plist не помогают разрешить имя интерпретатора внутри ProgramArguments — launchd разрешает исполняемый файл до применения этих ключей. Поэтому копирование plist с ноутбука, где argv[0] — node, падает на headless mini ProxyMac, даже если в том же XML экспортируется PATH.

Отдельно, когда ProcessType опущен, macOS может отнести шлюз к фоновой нагрузке с эвристиками питания и планирования после перезагрузки. Операторы сообщают о сокращении времени listen при холодной загрузке с порядка трёх минут до нескольких секунд после добавления <key>ProcessType</key><string>Interactive</string> рядом с Label. Считайте это гигиеной планировщика, а не лицензией на безнадзорные GUI-сессии — разовую работу с Keychain сочетайте с VNC по чеклисту первой загрузки, затем оставайтесь на SSH.

Матрица оператора (сигнал → первое исправление)

Основной сигналПервый ответ (порядок важен)Доказательства для сбораОткат при ошибкеОтветственный
Последний код выхода 78 на label OpenClawЗаменить argv[0] абсолютным путём $(command -v node); bootout → bootstraplaunchctl print gui/$UID/<label> + XML plistВосстановить прежний plist из gitPlatform SRE
Задание running, нет listener >60 с после rebootДобавить ProcessType Interactive; подтвердить один label plistС меткой времени lsof -nP -iTCP:<port> -sTCP:LISTENУбрать ProcessType, если политика запрещает desktop-сессииAutomation lead
Дублирующие listener на админ-портуСледовать восстановлению single-listenerДва PID в выводе lsofbootout дублирующего labelOn-call
Цикл падений <30 с, высокий CPUНастроить ThrottleInterval / KeepAlive — не эта статьяlog show --predicate 'process == "launchd"' --last 5mОткатить ключи throttleSRE

Исправление plist в 9 шагов (SSH на mini ProxyMac)

  1. Определите label: launchctl list | grep -i openclaw и запишите полное reverse-DNS имя.
  2. Выведите живое состояние: launchctl print gui/$(id -u)/<label> и зафиксируйте последний код выхода.
  3. Разрешите Node: в том же пользовательском контексте выполните command -v node (или which node) и запишите абсолютный путь — обычно под /opt/homebrew или ~/.nvm.
  4. Отредактируйте plist: задайте argv[0] в ProgramArguments этим путём; путь к скрипту шлюза тоже сделайте абсолютным.
  5. Добавьте ProcessType: вставьте Interactive в корневой dict, если задержка холодной загрузки совпадает с полевыми отчётами.
  6. Проверьте XML: plutil -lint ~/Library/LaunchAgents/<file>.plist перед reload.
  7. Перезагрузите: launchctl bootout gui/$(id -u) <label>, затем bootstrap того же пути (или vendor kickstart).
  8. Time-to-listen: опрашивайте lsof каждые 5 секунд в течение 120 секунд; цель <15 с на M4.
  9. Задокументируйте: закоммитьте plist в infra-репозиторий; добавьте ссылку на эту статью в runbook для следующего инженера.
Пример формы ProgramArguments: /opt/homebrew/bin/node + абсолютный путь к entry-скрипту openclaw-gateway + --config + абсолютный JSON конфигурации — никогда не полагайтесь на cd в обёртке, если не задан WorkingDirectory.

Проверка listener, health-эндпоинта и стабильности WebSocket

После bootstrap подтвердите, что ровно один PID слушает настроенный админ-порт (в операторской документации часто фигурирует 18999 — сверьте с вашим config.json). Выполните curl HTTP health-маршрута, если он включён; затем подключите desktop-клиент и убедитесь, что нет 1006 в первые 30 секунд после reboot. Если health проходит, а инструменты MCP падают, переключитесь на гигиену сирот MCP, а не на повторное редактирование plist шлюза.

Раз в квартал делайте reboot-тест на хостах автоматизации: регрессии launchd часто проявляются только после обновлений безопасности macOS, а не при правках plist в тот же день по SSH. Логируйте uname -r рядом с time-to-listen в системе тикетов.

Профилактика: plists как код и staging-labels

  • Храните plists в git с абсолютным путём Node из сборки образа (префикс Homebrew или nvm по умолчанию).
  • Разделяйте labels LaunchAgent для dev/staging/prod на одной mini — см. руководство по восстановлению на коллизии портов.
  • CI smoke: после деплоя утверждайте listener <20 с через SSH-скрипт, прежде чем помечать хост здоровым.
  • Одноразовая lab mini в HK/JP/KR/SG/US для экспериментов с plist — дешевле, чем отладка на production-оркестраторе.

FAQ

Почему LaunchAgent OpenClaw сразу завершается с кодом 78? launchd разрешает ProgramArguments до применения EnvironmentVariables. Строка node без пути не работает, когда PATH пуст под launchd. Замените её абсолютным путём из command -v node, затем выполните bootout и bootstrap plist снова.

Почему шлюзу нужны минуты, чтобы начать слушать порт после перезагрузки? Стандартные plist LaunchAgent могут не содержать ProcessType Interactive, и macOS понижает приоритет фонового запуска на минуты. Добавление ProcessType Interactive в корневой dict часто сокращает time-to-listen с примерно трёх минут до нескольких секунд на mini с Apple Silicon.

Чем это отличается от циклов падений ThrottleInterval? Проблемы ThrottleInterval дают штормы быстрых перезапусков с высокой загрузкой CPU. Выход 78 — одноразовый сбой конфигурации до запуска шлюза. Медленный listen без циклов падений указывает на ProcessType или планировщик ресурсов — а не на KeepAlive, борющийся с битым бинарником.

Почему арендованная Mac mini — правильное место для укрепления launchd OpenClaw

Plist шлюза — это инфраструктура: он должен пережить reboot, обновления ОС и инженеров, знающих только пути Homebrew с ноутбука. Mini на Apple Silicon M4 дают предсказуемое время холодной загрузки, macOS launchd совпадает с документированным потоком LaunchAgent OpenClaw, а размещение в HK / JP / KR / SG / US держит задержку control plane рядом с API, которые вы автоматизируете. ProxyMac позволяет клонировать проверенный plist на staging mini, доказать sub-minute listen по SSH, затем промоутить тот же XML в production — см. цены для выбора региона и справку по паттернам доступа.

Проверьте plist launchd на staging-железе

Арендуйте Mac mini HK / JP / KR / SG / US для укрепления шлюза OpenClaw