12 KiB
Hermes на Eagle (Mac M4 Max) — Настройка и подводные камни
Hermes работает нативно (не в Docker) на Mac через hermes gateway.
Транспорт — Zulip (запущен в Docker). Провайдер модели — openclaw-claude-proxy
(см. ниже).
Компоненты
| Компонент | Расположение | Запуск |
|---|---|---|
| Hermes config | ~/.hermes/config.yaml |
— |
| claude-proxy (Claude proxy) | /opt/homebrew/bin/claude-proxy |
launchd ai.claude-proxy |
| Zulip stack | ~/Developer/zulip/docker-compose.yml |
docker compose up -d |
| Obsidian MCP | mcpvault | встроен в Hermes toolset |
Claude CLI прокси — обход rate limit Claude API
Актуальный прокси (июнь 2026): Python
claude-code-openai-wrapperна порту 8090. Детальная документация: claude-python-cli-proxy.
Проблема
provider: claude-code в Hermes использует OAuth-токен напрямую через
API Anthropic — и упирается в rate limit подписки. Лимиты сбрасываются
раз в час. API-ключа нет (политика организации).
Почему не cmappy
cmappy (claude-max-proxy-py) молча выбрасывает поле tools из запроса —
передаёт только текст в claude --print. Результат: Hermes не может
использовать ни один инструмент (скиллы, MCP, терминал). Только голый
чат.
Решение: openclaw-claude-proxy
mehdic/claude-proxy (npm:
openclaw-claude-proxy) — Node.js сервер, запускает claude --print как
subprocess и предоставляет OpenAI-совместимый /v1/chat/completions на
порту 3456. Поддерживает tool_use — инжектирует схемы инструментов в
системный промпт, парсит JSON tool_call из ответа, возвращает стандартный
OpenAI tool_calls. Caller (Hermes) сам выполняет инструменты.
Важно: CLAUDE_PROXY_TOOLS_TRANSLATION=1 НЕ включать — этот режим
выполняет MCP инструменты внутри CLI и Hermes ничего не получает.
Установка
npm install -g openclaw-claude-proxy
Wrapper-скрипт (обязателен для launchd)
~/.local/bin/claude-proxy-start.sh:
#!/bin/zsh
# launchd не наследует среду login-сессии — токен нужно загружать явно
set -a
source /Users/admin/.hermes/.env 2>/dev/null
set +a
export PATH="/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:$PATH"
exec /opt/homebrew/bin/claude-proxy 3456
Pitfall: без явного source ~/.hermes/.env claude-proxy не видит
CLAUDE_CODE_OAUTH_TOKEN и прогревочные процессы падают с "Not logged in".
Pitfall: без явного PATH Claude CLI не найден (/opt/homebrew/bin/claude
не в launchd PATH).
launchd сервис
~/Library/LaunchAgents/ai.claude-proxy.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key><string>ai.claude-proxy</string>
<key>ProgramArguments</key>
<array>
<string>/Users/admin/.local/bin/claude-proxy-start.sh</string>
</array>
<key>EnvironmentVariables</key>
<dict>
<key>HOME</key><string>/Users/admin</string>
</dict>
<key>RunAtLoad</key><true/>
<key>KeepAlive</key><true/>
<key>StandardOutPath</key>
<string>/Users/admin/.hermes/logs/claude-proxy.log</string>
<key>StandardErrorPath</key>
<string>/Users/admin/.hermes/logs/claude-proxy.log</string>
</dict>
</plist>
launchctl load ~/Library/LaunchAgents/ai.claude-proxy.plist
Pitfall при перезагрузке: если старый процесс ещё держит порт 3456:
lsof -ti :3456 | xargs kill -9
launchctl unload ~/Library/LaunchAgents/ai.claude-proxy.plist
launchctl load ~/Library/LaunchAgents/ai.claude-proxy.plist
Конфигурация Hermes
~/.hermes/config.yaml (секция model):
model:
default: claude-sonnet-4-6
# provider: claude-code # отключён — упирается в rate limit OAuth API
provider: custom
base_url: 'http://localhost:3456/v1'
Pitfall: provider: openai не существует в Hermes — нужно custom.
Pitfall: base_url должен включать /v1 (Hermes дописывает
/chat/completions). Без /v1 → 404.
Zulip Docker — подводные камни
RabbitMQ: пользователи сбрасываются после перезапуска
Симптом: Zulip отдаёт 500 на /api/v1/register. В логах RabbitMQ —
паника Khepri (Raft WAL). Пользователи в RabbitMQ исчезают.
Причина: RabbitMQ 4.x использует Khepri вместо Mnesia. При переполнении
диска WAL не может записаться → Khepri сбрасывает состояние → пользователи
исчезают. RABBITMQ_DEFAULT_USER/PASS применяются только при первом
старте с пустым volume — повторный запуск их не восстанавливает.
Решение:
docker system prune— освободить место на диске (Docker VM sparse disk не освобождает место автоматически).- Добавить
RABBITMQ_ERLANG_COOKIEв env rabbitmq (стабилизирует cookie через перезапуски). - При повреждённом volume — стереть и пересоздать:
docker compose down docker volume rm zulip_zulip-rabbitmq docker compose up -d
Log rotation (обязательно!)
Без ротации логи заполняют Docker VM (~6 ГБ за несколько месяцев).
docker-compose.yml — добавить к каждому сервису:
# zulip:
logging:
driver: json-file
options:
max-size: "50m"
max-file: "5"
# rabbitmq, memcached, redis:
logging:
driver: json-file
options:
max-size: "20m"
max-file: "3"
Docker VM sparse disk
Mac Docker Desktop использует sparse virtual disk. Место, освобождённое
внутри VM, не возвращается хосту автоматически. docker system prune
запускает compaction.
Obsidian MCP
Везде используется mcpvault (не obsidian-mcp).
| Конфиг | Путь |
|---|---|
| Claude Code CLI | ~/.claude/.mcp.json |
| Claude Desktop App | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Hermes | встроен через toolset |
Пример конфига (одинаковый для обоих):
{
"mcpServers": {
"obsidian": {
"command": "mcpvault",
"args": ["/Users/admin/obsidian"]
}
}
}
Pitfall: obsidian-mcp (npm) был удалён — если остался в конфиге,
Claude падает с "Failed to spawn process". Проверить логи:
~/Library/Logs/Claude/mcp-server-obsidian.log.
Схема маршрутизации сообщений
Zulip Events API
↓ poll (credentials Eagle)
[zulip-router] (Go, Docker)
│
├── @Валера → trigger=owner → POST balda-agent:8091
├── @Клавдий → trigger=owner → POST claudio-agent:8092
├── @Орёл → trigger=owner → POST host.docker.internal:8645/webhooks/eagle
├── @Кит → trigger=owner → POST host.docker.internal:8646/webhooks/whale
└── ответы от ботов → в Zulip (боты пишут сами через API)
Кто что получает
| Компонент | Получает сообщения через | Шлёт ответы через |
|---|---|---|
| Eagle (Hermes gateway) | zulip-router → POST /webhooks/eagle |
Zulip API напрямую (бот eagle-bot) |
| Кит (Hermes gateway) | zulip-router → POST /webhooks/whale |
Zulip API напрямую (бот whale-bot) |
| Валера (balda-agent) | zulip-router → POST /zulip/webhook |
Zulip API напрямую (бот valera-bot) |
| Клавдий (claudio-agent) | zulip-router → POST /zulip/webhook |
Zulip API напрямую (бот claudio-bot) |
Важно: @**Орёл** и @**Кит** НЕ регистрируют свои event queue в Zulip.
Все сообщения приходят только через zulip-router. Роутер использует
credentials Eagle для поллинга Zulip Events API, но Eagle сам в Zulip
не поллит.
Что не так
Роутер после установки ownership шлёт ВСЕ сообщения из треда владельцу, даже если @mention адресован другому боту.
Должно быть: если @mention другого бота — ownership обновляется, НО НЕ форвардить. Бот получит сообщение через свой outgoing webhook (от Zulip напрямую).
Eagle: переключение на zulip-router (2026-06-17)
Задача
Eagle должен получать сообщения только через zulip-router (вебхуки),
без прямого Zulip polling. Кастомный код «роутера» в Hermes (eagle-thread-guard)
не должен мешаться.
План
- Отключить Zulip polling у Eagle (если включён)
- Настроить Eagle на приём вебхуков от zulip-router:
- webhook route
/webhooks/eagleна порту 8645 - роутер шлёт на
host.docker.internal:8645/webhooks/eagle
- webhook route
- Проверить:
- curl POST
/webhooks/eagle→ 202 @**Орёл**в Zulip → Eagle отвечает- ответы только на @mention Орла (не на чужие)
- curl POST
Конфиг Eagle
~/.hermes/config.yaml — секция platforms:
platforms:
webhook:
enabled: true
extra:
host: 127.0.0.1
port: 8645
routes:
eagle:
secret: INSECURE_NO_AUTH
prompt: '{{message.content}}'
deliver: zulip
Zulip platform (platforms.zulip) — отсутствует, polling отключён.
Что сделано
- Конфиг Eagle: порт 8645, webhook с route
eagle - Eagle перезапущен, порт 8645 слушается
- curl POST
/webhooks/eagle→ 202 Accepted - Роутер должен слать на
:8645, но шлёт на:8644— не настроено
Статус
- Порт 8645 занят — сейчас на нём сидит Кит (Whale), Eagle на 8644
- Роутер шлёт на
:8644— надо поправить на:8645 @**Орёл**— не отвечает
Связанные страницы
- claude-python-cli-proxy — Python Claude CLI proxy (claude-code-openai-wrapper, порт 8090)
- tech/hermes-docker-kraken — Hermes на Кракене (Docker)
- tech/kraken-network — сетевая топология
- concepts/hermes-deployment-patterns — сравнение трёх моделей деплоя Hermes