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 aAPI_SERVER_KEYde~/.hermes/profiles/coder/.env; a chave do listener padrão é rejeitada. - Uma rota de webhook destinada ao
coderprecisa declararprofile: coderao lado dosecretespecífico daquela rota, noconfig.yamldo 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
profilecontinuam 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`
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:
| Plataforma | Caminho |
|---|---|
| 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ção | Efeito |
|---|---|
-d | bloqueia o sono da tela |
-i | bloqueia o sono por ociosidade (padrão) |
-m | bloqueia o sono do disco |
-s | bloqueia o sono do sistema (só Macs na tomada) |
-u | simula atividade do usuário (evita travar a tela) |
-t N | sai sozinho depois de N segundos |
-w P | sai quando o PID P sair |
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