ИИ / автоматизация 27 апреля 2026

2026: PATH OpenClaw, префиксы Homebrew и сбой запуска серверов MCP под launchd на Mac mini в ProxyMac

Инженерная команда ProxyMac 27 апреля 2026 ~12 мин чтения

Команды, которые ведут OpenClaw на арендованных Mac mini M4 в Гонконге, Японии, Корее, Сингапуре и США, регулярно присылают логи, где дочерние серверы MCP печатают env: node: No such file or directory или uvx: command not found, хотя в Терминале тот же вызов срабатывает. Этот материал — контракт по переменной PATH между интерактивной login-shell и launchd: почему brew --prefix на Apple Silicon и Intel расходятся, как читать LaunchAgent-файл без магии, и пятишаговая лестница проверок, согласованная с настройкой серверов MCP, устранением сбоев при выкатке и гайдом по установке и развёртыванию. Внутри — широкая таблица симптомов, готовый фрагмент EnvironmentVariables в XML, который в прод вносят только после ревью, и кнопки на справку плюс страницу хаба OpenClaw без «маркетинговой пены». Если вы уже ввели SRE-процесс для brew upgrade Node, но ночной перезапуск агента снова ломает execve, чаще всего виноват не сетевой слой, а таблица путей, которую ssh-сессия видела, а launchd — нет. Зафиксируйте гипотезу в тикете: до правки plist путь which npx и путь, который видит launchctl print для Job-объекта, должны совпасти побитно.

Дополнительный контекст: при совместимости с GitOps для конфига каждое изменение brew или asdf должно порождать отдельный pull request с обновлённой строкой PATH, иначе ревьюер не поймёт, почему в логах ENOENT всплыло через две недели, когда коллега обновил только клиент. На выделенном mini путь /opt/homebrew живёт на NVMe рядом с рабочим каталогом; не предполагайте, что CI на GitHub, где brew стоит в ~/actions-runner, дублирует ту же схему. Документированный PATH — единственный способ согласовать SRE, безопасность и владельца продукта, когда HK / JP / KR / SG / US смотрят в один runbook, но в каждом ЦОДе свои образы с разными минорными версиями Node.

Терминал и launchd: две разные вселенные

Интерактивные оболочки в macOS исполняют /etc/zprofile, ~/.zprofile и ~/.zshrc, часто с eval "$(/opt/homebrew/bin/brew shellenv)" в этих rc-файлах. Агенты launchd по умолчанию наследуют консервативную среду: PATH схлопывается в /usr/bin:/bin:/usr/sbin:/sbin, пока plist явно не расширяет. Шлюзы OpenClaw, поднимающие MCP, видят урезанный набор, где npx и pnpm в виде shims исчезают, хотя which npx в Терминале пишет /opt/homebrew/bin/npx. Сбой не в том, что OpenClaw «потерял MCP» — это ENOENT в execve, потому что ядро не находит бинарник-интерпретатор, указанный в shebang.

Когда в логе виден env: python3: No such file or directory, сначала проверьте, не ссылается ли wrapper на путь, который существует только в профиле пользователя-разработчика, а супервайзор запущен в другом UID. На ProxyMac-инстансах агент обычно крутится в GUI-домене той учётки, под которой подписан ssh, но LaunchAgent всё равно не читает ~/.zshrc — только явные EnvironmentVariables плюс наследуемый минимум. Снимите printenv PATH в однократной сессии ssh mini 'launchctl print gui/$(id -u)/…' и сравните с интерактивной zsh -l, чтобы цифры попали в инцидент, а не в переписку.

  • Доказать раскол: сравнить printenv PATH в однократном ssh с выводом launchctl print gui/… для вашего Label.
  • Наружный бинарник MCP пока указывайте по абсолютному пути, пока PATH для вспомогательных инструментов не стабилизирован.
  • Дрейф версий ведите в Git по образцу версионирования конфига, чтобы brew upgrade не вращал корень путей незаметно.
Не путайте PATH из окон VNC с автоматикой. Сессия «Общий экран» может подмешивать иные таблицы окружения, чем headless LaunchAgent. Отладка через VNC — человеческий сценарий, не единый источник правды для cron-подобных джобов. Для GUI-сценариев ориентируйтесь на VNC и справку ProxyMac, но в plist прописывайте то, что повторяется на сервере без дисплея.

Матрица префиксов Homebrew: Apple Silicon и Intel (три колонки, иная логика, чем в статье про Wi-Fi)

Смешивайте Intel x86_64 и arm64 только осознанно: Rosetta вводит в заблуждение при чтении file бинарника, тогда как обёртки npx, собранные на ноутбуке M3, смотрят в arm64, а node в /usr/local остаётся x86. Каждую бинарь в конфиге MCP сопровождайте шестнадцатеричной подписью и выводом file — иначе тикет в ЦОД скажет «у меня всё падает», а ваша локаль так и останется зелёной. Это снимает вопрос, почему мини пингует иначе, чем 14-дюймовый ноутбук, с которого вы копировали JSON.

Поколение железаТиповой префикс brewТиповой симптом при отсутствии в PATH
Mac mini M4 на Apple Silicon/opt/homebrewnode не найден, при этом /opt/homebrew/bin/node -v печатает v22.x
Mac mini на Intel (наследие)/usr/localВ JSON всё ещё /opt/homebrew/bin/uvx, перенесённый с портативного Mac
Гетерогенный паркОба префикса на дискеАгенты берут неверный порядок, если /usr/local/bin стоит раньше /opt/homebrew/bin

Если в одной Plist-строке PATH перечислены сразу …/usr/local/bin и …/opt/homebrew/bin, согласуйте порядок с политикой пакетного менеджера: brew doctor на целевом хосте — обязателен перед мёрджем. На fleet из mini в разных дата-центрах нельзя полагаться на «дефолт, который везде Apple Silicon» — запасной Intel для CI всё ещё встречается, и grep репозитория на строку /opt/homebrew в шаблонах — полезный предохранитель в CI.

Шаблон EnvironmentVariables в plist, переживающий перезагрузки

К LaunchAgent, которому принадлежит OpenClaw или супервайзор MCP, добавьте словарь EnvironmentVariables. Сначала — shims Homebrew, потом системные пути, затем каталоги вроде ~/.local/bin для uv и uvx. После правки всегда launchctl bootout gui/$(id -u)/… с последующим kickstart; на macOS 14 и новее доверять одному launchctl unload нельзя. Сопрягите сигнал с руководством по мониторингу, чтобы регресс по PATH поймали в течение трёх минут, иначе бизнес-агенты будут снова писать «всё сломалось ночью», когда brew молча перенёс node на другой путь. Любая правка plist в проде сопровождается ссылкой на тикет, откат к предыдущему plist из openclaw-version-upgrades-rollback-launchctl-mac-mini-2026.html остаётся в скоупе релиз-менеджера.

Пример фрагмента (в прод после проверки)

<key>EnvironmentVariables</key> <dict> <key>PATH</key> <string>/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string> </dict>

Безопасность: расширение PATH остаётся безопаснее, чем отключение SIP или Gatekeeper. Не вставляйте в начало пути world-writable каталоги. При ссылке на пользовательские бинарники прочтите гигиену секретов, чтобы не дать PATH тянуть исполняемый файл из ~/Downloads после вредоносной распаковки.

Если Library/LaunchAgents в Git хранит несколько plists (отдельно для n8n, отдельно для туннеля), согласуйте порядок загрузки: LimitLoadToSessionType и ThrottleInterval влияют на то, в каком порядке PATH окажется в процессе супервайзера OpenClaw. Мелочь, но она всплывает, когда первый субагент смотрит на ещё пустой PATH до bootout второго.

Пять проверок, прежде чем с нуля переписывать конфиги MCP

  1. Хэш бинарника: shasum -a 256 $(which uvx) в Терминале сравнить с путём, который зашьёте в JSON MCP (абсолютный путь, не $(which) в конфиге).
  2. Среда launchd: launchctl print user/$(id -u)/limit плюс домен агента, убедиться, что PATH реально подтянут из plist, а не кэш старой сессии.
  3. Нелогиновая среда: env -i PATH=/usr/bin:/bin /opt/homebrew/bin/npx --version — выживает ли сам npx при минимальном PATH (тест на корректность shebang и вложенных вызовов).
  4. Корреляция с JSONL: grep ENOENT в скользящих логах по диагностике JSONL — сопоставить время brew upgrade и смену inode бинарника.
  5. Документация отката: снять снапшот LaunchAgent до массовой раскатки на флоты HK / JP / KR / SG / US, согласно роллбэку и canary-задачи на регион, а не big-bang в пике.

Node, uv и раскладка шимов: почему менеджеры версий рвутся под launchd

Разработчики подключают fnm, mise и asdf, чтобы на одном хосте держать несколько рантаймов Node, но эти утилиты почти всегда меняют PATH в ~/.zshrc, который процессы launchd не читают. Если в JSON MCP указано npx @scope/server, сначала сам исполняемый файл npx должен быть доступен по абсолютному пути; только затем подключаются каталоги вроде ~/.npm. Типичный перенос конфигурации с ноутбука на новый ProxyMac mini: в интерактивной оболочке после corepack enable утилита pnpm попадает в PATH, а plist по-прежнему отдаёт shebang #!/usr/bin/env node, который упирается в системную заглушку (на части образов v18) вместо цепочки v22 из lockfile. В логах это не обязательно явное «файл не найден» — чаще всплывает ERR_PNPM_UNSUPPORTED_ENGINE глубоко в повторных попытках OpenClaw.

С uv та же схема: uvx после установки через curl-скрипт обычно оказывается в ~/.local/bin или ~/.cargo/bin — в Терминале путь есть, в урезанном PATH у launchd часто нет. Вместо бесконечного наращивания plist разумнее положить компактный обёрточный сценарий в /usr/local/bin/mcp-env.sh (владелец root:wheel, без каталогов с общей записью в начале PATH), один раз экспортировать окружение и exec настоящую точку входа MCP. Аудиторам проще смотреть один согласованный файл, чем два десятка разрозненных правок. Держите скрипт в Git наравне с фрагментами из перезапуска шлюза и восстановления через launchctl, чтобы сравнивать соседние выкладки.

Среда выполненияТипичное место установки (интерактив)Что видит launchd без правок
Node через Homebrew/opt/homebrew/bin/nodeОстаётся разбор через /usr/bin/env; без шима Homebrew → ENOENT
Цепочка uv~/.local/bin/uvxТильда в строке plist сама не раскрывается
pnpm через Corepackшим рядом с nodeСогласованно только если каталог node в PATH стоит раньше /usr/bin
Эксплуатационный совет: заведите контрольный LaunchAgent, который каждые 15 минут запускает /opt/homebrew/bin/node -e "console.log(process.version)" и передаёт строку стандартного вывода в ваш канал JSONL; после brew upgrade номер версии изменится раньше, чем это заметят пользователи MCP.

Когда ssh на мини вручную показывает рабочий uvx, а OpenClaw — нет, убедитесь, что ssh стартует интерактивную оболочку: неисполняемая команда ssh mini env ближе к тому, что увидит агент, чем ssh -t mini bash -l. Это избавит от сценария «команда работает, когда я набираю её руками».

Вопросы и ответы

Обернуть всё в /bin/zsh -lc? Сработает, но скроет настоящие ошибки и ухудшит обработку сигналов. Пока нет критичной зависимости от функций login-shell, оставьте прямой exec и явный PATH.

Рушит ли Rosetta brew MCP? Только если бинарь x86_64, а нативный агент ждёт arm64 — сопоставьте file $(which node) с архитектурой, под которой собрали OpenClaw и его зависимости.

Где ещё бывают залипания stdio? PATH чинит запуск, буферизация — каналы. Если процесс стартует, но дальше тишина, читайте статью про stdio и сравнение построчной буферизации с launchd и npx-обёртками, которые пишут по строкам, пока stdout уже закрыт с другой стороны трубы.

Почему на ProxyMac Mac mini удобно «законсервировать» контракт по PATH

Выделенный Mac mini M4 на арендной стойке — это железо на одного арендатора: валидированный /opt/homebrew остаётся на NVMe рядом с рабочим пространством OpenClaw, и никакой сосед по Jenkins не сделает brew uninstall критичного рантайма. Нативные бинарники arm64 уменьшают сюрпризы Rosetta, unified memory снимает борьбу за NUMA у параллельных воркеров MCP, пять регионов дают репликацию рядом с требованием к данным, при этом git-traced plist остаётся идентичным. Когда PATH снова «скучный» и в логах нет ENOENT неделями, масштабируйте конкурентность по гайду по параллельным агентам, бронируйте ёмкость на странице тарифов и ведите людей в центр справки, если GUI-диалоги невозможны без VNC к сессии на мини. Это завершает петлю: PATH зафиксировали, наблюдаемость есть, сценарий доступа согласован с безопасностью.

Долгий хвост инцидентов по ENOENT исчезает, если коммит plists относите к тому же репозиторию, что и JSON определения MCP, а ревьюер смотрит на оба дифа единовременно. Внутренний аудит ProxyMac в духе help и внешние поставщики реже задают вопрос «где ваша схема путей», если таблица соответствия хост ↔ префикс brew публикуется рядом с openclaw-mcp-tool-servers-mac-mini-setup-2026.html. Сохраняйте холодный стенд: одна копия mini с образом до обновлений, чтобы воссоздать execve без плясок с brew switch в пике.

Зафиксировать PATH один раз — везде запускайте OpenClaw

HK / JP / KR / SG / US · Apple Silicon M4