Pular para o conteúdo principal

Documentação oficial desta página · v0.20.6

Vários Gateways ao Mesmo Tempo

Opere vários perfis — cada um com seus próprios tokens de bot, sessões e memória — como serviços gerenciados numa única máquina. Esta página cobre a parte operacional: subir todos juntos, ver os logs de todos os perfis, impedir que o computador durma e se recuperar das manias mais comuns do launchd/systemd.

Se você roda um único agente Hermes, não precisa desta página — veja Perfis para o básico. E se as suas instâncias vivem em máquinas diferentes que um mesmo aplicativo desktop deve alcançar ao mesmo tempo, veja Conectar o Desktop a Várias Instâncias do Hermes.

Quando usar isto​

Você quer esta configuração quando tem dois ou mais agentes Hermes que devem ficar online ao mesmo tempo. Motivos comuns:

  • Um assistente pessoal num bot do Telegram e um agente de código em outro
  • Um agente por pessoa da família ou um por espaço de trabalho do Slack
  • Instâncias de sandbox + produção da mesma configuração
  • Um agente de pesquisa + um agente de escrita + um bot movido a cron — cada um com memória e skills isoladas

Todo perfil já ganha o seu próprio LaunchAgent por plataforma (ai.hermes.gateway-<name>.plist) ou serviço de usuário do systemd (hermes-gateway-<name>.service). Este guia acrescenta os padrões para gerenciá-los em conjunto.

Início rápido​

# Crie os perfis (uma vez)
hermes profile create coder
hermes profile create personal-bot
hermes profile create research

# Configure cada um
coder setup
personal-bot setup
research setup

# Instale o gateway de cada um como serviço gerenciado
coder gateway install
personal-bot gateway install
research gateway install

# Suba todos
coder gateway start
personal-bot gateway start
research gateway start

É isso — três agentes independentes, cada um no seu processo, reiniciando automaticamente em caso de queda e no login do usuário.

Alternativa: um gateway para todos os perfis (multiplexação)​

O modelo acima roda um processo por perfil. Esse é o padrão e é a escolha certa para a maioria das instalações. Mas numa máquina com muitos perfis — ou num deploy em contêiner onde um processo por perfil pesa demais na operação — você pode rodar um único gateway multiplexador: o gateway do perfil padrão vira o único processo de entrada e atende mensagens de todos os perfis da máquina.

Isso é opt-in e vem desligado por padrão. Com ele desligado, nada nesta página muda — todo comportamento descrito abaixo fica inerte.

Quando preferir a multiplexação​

  • Um deploy em contêiner/VPS onde N unidades de supervisão, N portas e N arquivos de PID são um peso.
  • Muitos perfis de baixo tráfego que não justificam um processo inteiro cada.
  • Você quer uma coisa só para iniciar, monitorar e reiniciar.

Fique com um processo por perfil quando quiser isolamento duro no nível de processo entre perfis (pegadas de memória separadas, domínios de falha independentes, poder reiniciar um perfil sem encostar nos outros).

Como ativar​

Ligue a chave no perfil padrão (é ele que carrega o multiplexador) e reinicie o gateway dele:

hermes config set gateway.multiplex_profiles true
hermes gateway restart

Ou, de forma equivalente, no ~/.hermes/config.yaml do perfil padrão:

gateway:
multiplex_profiles: true

(A chave também é aceita como um multiplex_profiles: true de nível raiz, por conveniência.) Na próxima inicialização, o gateway padrão enumera todos os perfis, sobe as plataformas habilitadas de cada perfil com as credenciais desse perfil e roteia cada mensagem de entrada para o perfil a que ela pertence. Cada turno resolve a config, as skills, a memória, o SOUL e as chaves de provedor do perfil roteado — credenciais nunca são compartilhadas entre perfis.

Você não roda hermes gateway start para os perfis secundários — o gateway padrão atende por eles. Veja as mudanças de contrato abaixo.

O que muda com a multiplexação ligada​

Ligar a chave muda o comportamento de algumas coisas. Todas voltam ao normal no instante em que a chave é desligada.

1. Perfis secundários não podem subir o próprio gateway​

Com um multiplexador rodando, um hermes gateway start / run com perfil nomeado vira erro duro, apontando você de volta para o multiplexador:

The default gateway is running as a profile multiplexer and already serves
profile 'coder'. ...

O multiplexador é o único processo de entrada; um segundo gateway de perfil faria bind duplo nas plataformas daquele perfil. Passe --force só se você quiser deliberadamente um processo separado para esse perfil (não recomendado enquanto o multiplexador estiver rodando). O script de ciclo de vida entre perfis mostrado adiante nesta página, portanto, não é usado no modo multiplexado — você gerencia apenas o gateway padrão.

2. Plataformas com entrada HTTP são alcançadas por um prefixo /p/<profile>/ na URL​

O tráfego de webhook (e de outras plataformas com entrada HTTP) de um perfil secundário chega no listener padrão sob um prefixo de perfil, e não numa segunda porta:

# perfil padrão
POST http://host:8644/webhooks/<route>
# o perfil "coder", no mesmo listener
POST http://host:8644/p/coder/webhooks/<route>

Um perfil desconhecido ou não configurado no prefixo devolve 404. Como esse listener compartilhado já atende todos os perfis dessa forma, um perfil secundário não pode habilitar uma plataforma que faz bind de porta — fazer isso é um erro de configuração que pula o perfil secundário inteiro, enquanto o padrão e os demais perfis saudáveis seguem funcionando. O aviso nomeia o perfil pulado e cada plataforma em conflito:

Skipping secondary profile 'coder' due to port-binding config error: Profile
'coder' enables port-binding platform(s) webhook, but gateway.multiplex_profiles
is on. ... Remove these platform entries from profile 'coder's config.yaml or
configure them only on the default profile.

Plataformas que fazem bind de porta e caem nessa regra: webhook, api_server, msgraph_webhook, feishu, wecom_callback, bluebubbles, sms, whatsapp_cloud, line. Configure qualquer uma delas apenas no perfil padrão; todo perfil fica alcançável pelo seu prefixo /p/<profile>/.

A autenticação segue o perfil nomeado na URL. Endpoints sem prefixo continuam usando as credenciais já existentes do listener padrão.

  • Requisições de API-server em /p/coder/... precisam usar a API_SERVER_KEY de ~/.hermes/profiles/coder/.env; a chave do listener padrão é rejeitada.
  • Uma rota de webhook destinada ao coder precisa declarar profile: coder ao lado do secret específico daquela rota, no config.yaml do perfil padrão. Esse secret passa então a ser aceito somente em /p/coder/webhooks/<route> e é rejeitado em qualquer outro prefixo de perfil.
  • Rotas de webhook sem profile continuam sendo rotas do perfil padrão e não são alcançáveis por um prefixo de perfil nomeado.

Mantenha as plataformas que fazem bind de porta desligadas nas configs dos perfis secundários. O listener compartilhado e as definições de rota dele ficam no perfil padrão; a vinculação de perfil controla qual perfil cada rota de webhook autenticada pode executar. Requisições nomeadas falham fechando quando o perfil alvo não tem API_SERVER_KEY.

Só esse conflito de listener compartilhado degrada para um perfil pulado. Erros de configuração de segurança continuam fatais: por exemplo, uma plataforma com política própria open sem GATEWAY_ALLOW_ALL_USERS ou sem o opt-in de liberar-todos específico daquela plataforma ainda aborta a inicialização do gateway, em vez de descartar em silêncio o perfil inseguro.

3. Plataformas com credencial por perfil continuam precisando do próprio token​

Plataformas de polling/conexão (Telegram, Discord, Slack, Matrix, Signal, …) funcionam bem multiplexadas, mas cada perfil que habilita uma delas precisa fornecer o seu próprio token de bot — o mesmo token não pode ser consultado por dois perfis ao mesmo tempo. Se dois perfis configurarem o mesmo (platform, token), a inicialização falha na hora nomeando os dois perfis (veja Proteção contra conflito de token — a regra é a mesma, só passa a ser aplicada dentro de um único processo).

4. Chaves de sessão ganham namespace por perfil​

As sessões de cada perfil vivem sob um namespace agent:<profile>:…, para que dois perfis na mesma plataforma/conversa nunca colidam no armazenamento compartilhado de sessões. O perfil padrão mantém o namespace histórico agent:main:… byte a byte, então as sessões existentes do perfil padrão não são afetadas — sem migração, sem histórico órfão.

5. Um PID/lock só e uma superfície de status só​

Existe um único PID e lock em nível de processo (o multiplexador, sob o diretório do perfil padrão). O hermes status reporta o multiplexador e os perfis que ele atende; hermes status -p <name> recorta para um perfil. Cada perfil continua escrevendo o seu próprio runtime_status.json no seu próprio diretório, então quem já lia esses arquivos continua funcionando.

O que não muda​

O isolamento de credenciais por .env de cada perfil é preservado e, se alguma coisa, fica mais rígido: as chaves de um perfil são resolvidas no escopo dele e nunca são unidas num ambiente compartilhado (o que também significa que subprocessos como servidores MCP e workers do Kanban só enxergam os segredos do próprio perfil). Kanban, skills/memória/SOUL com escopo de perfil e roteamento de modelos se comportam por perfil exatamente como se comportariam com gateways separados.

Atender apenas alguns perfis​

Por padrão, gateway.multiplex_profiles: true atende todos os perfis nomeados válidos da máquina. Para manter perfis não relacionados instalados sem subir os adaptadores nem os jobs de cron deles, use gateway.multiplex_profile_allowlist:

gateway:
multiplex_profiles: true
multiplex_profile_allowlist:
- worker
- guest

O perfil padrão é sempre atendido e não precisa ser listado. Uma allowlist não definida preserva o comportamento histórico de atender todos; uma lista vazia atende apenas o perfil padrão. Os nomes são normalizados e deduplicados. Entradas inválidas ou nomes que não estão instalados são pulados com um aviso. Um valor malformado que não seja uma lista falha com segurança para "só o padrão".

O conjunto atendido resultante também controla os prefixos de API e webhook /p/<profile>/, o status de runtime, a elegibilidade de rotas de perfil e quais perfis o agendador de cron em processo faz tiquetaquear. Um perfil nomeado fora da allowlist ainda pode rodar o próprio gateway independente.

Rotear conversas de um bot compartilhado para perfis (profile_routes)​

A multiplexação escolhe um perfil por credencial (o token de bot de cada perfil) ou por prefixo de URL (/p/<profile>/ para plataformas HTTP). Quando várias comunidades compartilham um token de bot — por exemplo, um bot do Discord atendendo muitas guildas — você pode, além disso, rotear guildas/canais/ threads específicos para perfis diferentes com gateway.profile_routes:

gateway:
multiplex_profiles: true
profile_routes:
# Um servidor inteiro do Discord → um perfil
- name: acme-server
platform: discord
guild_id: "1234567890"
profile: acme

# Um canal desse servidor → um perfil diferente
- name: acme-support
platform: discord
guild_id: "1234567890"
chat_id: "9876543210"
profile: acme-support

# Um grupo do Telegram (não existe guilda — só chat_id)
- name: tg-group
platform: telegram
chat_id: "-1001234567890"
profile: tg-profile

As rotas são casadas da mais específica para a menos específica (thread_id > chat_id > guild_id), todos os campos declarados precisam bater (E lógico), e uma rota chaveada por canal também casa com threads/posts de fórum cujo pai é aquele canal. Mensagens que não casam com rota nenhuma ficam no perfil padrão/ativo. O perfil roteado recebe o isolamento por perfil completo descrito acima (config, skills, memória, credenciais, namespace de sessão). O roteamento funciona em todo adaptador de plataforma, não só no Discord.

profile_routes exige gateway.multiplex_profiles: true; com a multiplexação desligada as rotas são ignoradas. Se uma rota explícita casar mas o perfil alvo não estiver instalado ou estiver fora de multiplex_profile_allowlist, o gateway rejeita aquela entrada e registra a rota e o alvo em log. Ele não roda o perfil padrão. O tráfego que não casa com rota nenhuma mantém o comportamento histórico de perfil padrão.

Iniciar, parar ou reiniciar todos os gateways de uma vez​

A CLI vem com comandos de ciclo de vida para um perfil por vez. Para agir sobre todos os perfis, embrulhe-os num laço de shell. Coloque o trecho abaixo em ~/.local/bin/hermes-gateways e rode chmod +x nele:

#!/bin/sh
set -eu

# Acrescente ou remova nomes de perfil aqui conforme você cria / apaga perfis.
profiles="default coder personal-bot research"

usage() {
echo "Usage: hermes-gateways {start|stop|restart|status|list}"
}

run_for_profile() {
profile="$1"
action="$2"
if [ "$profile" = "default" ]; then
hermes gateway "$action"
else
hermes -p "$profile" gateway "$action"
fi
}

action="${1:-}"
case "$action" in
start|stop|restart|status)
for profile in $profiles; do
echo "==> $action $profile"
run_for_profile "$profile" "$action"
done
;;
list)
hermes gateway list
;;
*)
usage
exit 2
;;
esac

Depois:

hermes-gateways start # sobe todos os perfis configurados
hermes-gateways stop # para todos os perfis configurados
hermes-gateways restart # reinicia todos
hermes-gateways status # status de todos
hermes-gateways list # delega para `hermes gateway list`
dica

O perfil default é alvo de hermes gateway <action> (sem -p), e não de hermes -p default gateway <action>. O wrapper acima trata as duas formas.

Gerenciar um perfil​

Os comandos de atalho que todo perfil instala:

coder gateway run # em primeiro plano (Ctrl-C para parar)
coder gateway start # inicia o serviço gerenciado
coder gateway stop # para o serviço gerenciado
coder gateway restart # reinicia
coder gateway status # status
coder gateway install # cria o LaunchAgent / unidade systemd
coder gateway uninstall # remove o arquivo de serviço

Eles equivalem a hermes -p coder gateway <action> — útil se o alias do perfil não estiver no PATH ou se você mirar perfis dinamicamente a partir de um script.

Arquivos de serviço​

Cada perfil instala o próprio serviço com um nome único, então as instalações nunca se atropelam:

PlataformaCaminho
macOS~/Library/LaunchAgents/ai.hermes.gateway-<profile>.plist
Linux~/.config/systemd/user/hermes-gateway-<profile>.service

O perfil padrão mantém os nomes históricos: ai.hermes.gateway.plist / hermes-gateway.service.

Ver os logs​

Cada perfil escreve nos seus próprios arquivos de log:

# Perfil padrão
tail -f ~/.hermes/logs/gateway.log
tail -f ~/.hermes/logs/gateway.error.log

# Perfil nomeado
tail -f ~/.hermes/profiles/<name>/logs/gateway.log
tail -f ~/.hermes/profiles/<name>/logs/gateway.error.log

Acompanhe o log de todos os perfis ao mesmo tempo:

tail -f ~/.hermes/logs/gateway.log ~/.hermes/profiles/*/logs/gateway.log

A CLI também tem um visualizador de log estruturado:

hermes logs -f # acompanha o perfil padrão
hermes -p coder logs -f # acompanha um perfil
hermes logs --help # filtros, níveis, saída em JSON

Descobrir o que está rodando de verdade​

hermes profile list # perfis + modelo + estado do gateway
hermes-gateways status # status completo de todos os perfis
launchctl list | grep hermes # macOS — PIDs e labels
systemctl --user list-units 'hermes-gateway-*' # Linux — unidades

Editar a configuração​

Todo perfil guarda a config dentro do próprio diretório:

~/.hermes/profiles/<name>/
├── .env # chaves de API, tokens de bot (chmod 600)
├── config.yaml # modelo, provedor, toolsets, ajustes de gateway
└── SOUL.md # personalidade / prompt de sistema

O perfil padrão usa o ~/.hermes/ direto, com os mesmos três arquivos.

Edite-os com qualquer editor ou pela CLI:

hermes config set model.model anthropic/claude-sonnet-4 # perfil padrão
coder config set model.model openai/gpt-5 # perfil nomeado

Depois de editar .env ou config.yaml, reinicie o gateway afetado:

coder gateway restart
# ou, para tudo:
hermes-gateways restart

Manter o computador acordado​

O processo do gateway pode rodar o dia inteiro, mas o sistema operacional ainda vai tentar dormir quando ficar ocioso. Dois padrões:

macOS — caffeinate​

O caffeinate já vem no macOS e impede o sono enquanto roda. Nada a instalar.

caffeinate -dis # bloqueia sono de tela, de ociosidade e do sistema
caffeinate -dis -t 28800 # o mesmo, saindo sozinho depois de 8 horas
caffeinate -i -w $(cat ~/.hermes/gateway.pid) & # acordado enquanto o gateway padrão roda

# Persistente: rode em segundo plano e esqueça
nohup caffeinate -dis >/dev/null 2>&1 &
disown

# Inspecionar / parar
pmset -g assertions | grep -iE 'caffeinate|prevent|user is active'
pkill caffeinate
OpçãoEfeito
-dbloqueia o sono da tela
-ibloqueia o sono por ociosidade (padrão)
-mbloqueia o sono do disco
-sbloqueia o sono do sistema (só Macs na tomada)
-usimula atividade do usuário (evita travar a tela)
-t Nsai sozinho depois de N segundos
-w Psai quando o PID P sair
Fechar a tampa ainda faz o Mac dormir

O caffeinate não consegue anular o sono por fechamento de tampa, que é comandado pelo hardware nos MacBooks. Para operar de tampa fechada, mude as preferências de Economia de Energia / Bateria ou use uma ferramenta de terceiros.

Linux — systemd-inhibit ou loginctl​

# Inibe a suspensão enquanto um comando roda
systemd-inhibit --what=idle:sleep --who=hermes --why="gateways running" \
sleep infinity &

# Permite que serviços de usuário sigam rodando depois do logout (recomendado)
sudo loginctl enable-linger "$USER"

Depois de habilitar o lingering, suas unidades de usuário do systemd (incluindo hermes-gateway-<profile>.service) continuam rodando através de desconexões de SSH e de reinicializações.

Proteção contra conflito de token​

Cada perfil precisa usar tokens de bot únicos para cada plataforma. Se dois perfis compartilharem um token de Telegram, Discord, Slack, WhatsApp ou Signal, o segundo gateway se recusa a iniciar com um erro nomeando o perfil em conflito.

Para auditar:

grep -H 'TELEGRAM_BOT_TOKEN\|DISCORD_BOT_TOKEN' \
~/.hermes/.env ~/.hermes/profiles/*/.env

Atualizar o código​

O hermes update puxa o código mais recente uma vez e sincroniza as novas skills empacotadas em todos os perfis:

hermes update
hermes-gateways restart

Skills modificadas pelo usuário nunca são sobrescritas.

Resolução de problemas​

"Could not find service in domain for user gui: 501"​

Você rodou hermes gateway start depois de um hermes gateway stop anterior. O stop da CLI faz um launchctl unload completo, que remove o serviço do registro do launchd. A CLI captura esse erro específico no start e recarrega o plist automaticamente (↻ launchd job was unloaded; reloading service definition). O serviço sobe normalmente. Nada a corrigir.

PID velho depois de uma queda​

Se o gateway de um perfil mostra not running mas um processo continua vivo:

ps -ef | grep "hermes_cli.*-p <profile>"
cat ~/.hermes/profiles/<profile>/gateway.pid
kill -TERM <pid> # gracioso
kill -KILL <pid> # se o anterior não resolver em alguns segundos
<profile> gateway start

Forçar um reset duro de um serviço​

# macOS
launchctl unload ~/Library/LaunchAgents/ai.hermes.gateway-<profile>.plist
launchctl load ~/Library/LaunchAgents/ai.hermes.gateway-<profile>.plist

# Linux
systemctl --user restart hermes-gateway-<profile>.service

Checagem de saúde​

hermes doctor # perfil padrão
hermes -p <profile> doctor # um perfil