Pular para o conteúdo principal

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

Gateway de mensagens

Converse com o Hermes pelo Telegram, Discord, Slack, WhatsApp, Signal, SMS, e-mail, Home Assistant, Mattermost, Matrix, DingTalk, Feishu/Lark, WeCom, Weixin, BlueBubbles (iMessage), QQ, Yuanbao, Microsoft Teams, LINE, ntfy ou pelo navegador. O gateway é um único processo em segundo plano que se conecta a todas as plataformas que você configurou, cuida das sessões, roda as tarefas de cron e entrega as mensagens de voz.

Para o conjunto completo de recursos de voz — incluindo o modo microfone na CLI, respostas faladas nas mensagens e conversas em canal de voz do Discord — veja Modo de voz e Usar o modo de voz com o Hermes.

dica

Os bots precisam de um provedor de modelo e de provedores de ferramenta (TTS, web). Uma assinatura do Nous Portal reúne todos eles.

Comparação entre plataformas​

PlataformaVozImagensArquivosThreadsReaçõesDigitandoStreaming
Telegram✅✅✅✅—✅✅
Discord✅✅✅✅✅✅✅
Slack✅✅✅✅✅✅✅
Google Chat—✅✅✅—✅—
WhatsApp—✅✅——✅✅
WhatsApp Cloud API✅✅✅——✅—
Signal—✅✅——✅—
SMS———————
E-mail—✅✅✅———
Home Assistant———————
Mattermost✅✅✅✅—✅✅
Matrix✅✅✅✅✅✅✅
DingTalk—✅✅—✅—✅
Feishu/Lark✅✅✅✅✅✅✅
WeCom✅✅✅————
WeCom Callback———————
Weixin✅✅✅——✅—
BlueBubbles—✅✅—✅✅—
Photon (iMessage)✅✅✅—✅✅—
QQ✅✅✅——✅—
Yuanbao✅✅✅——✅✅
Microsoft Teams—✅—✅—✅—
LINE—✅✅——✅—
ntfy———————
Raft———————
IRC———————
Buzz—✅—✅———
SimpleX✅✅✅——✅—

Voz = respostas em áudio por TTS e/ou transcrição de mensagem de voz. Imagens = enviar/receber imagens. Arquivos = enviar/receber anexos. Threads = conversas em thread. Reações = reações com emoji nas mensagens. Digitando = indicador de digitação durante o processamento. Streaming = atualização progressiva da mensagem por edição.

Hermes Relay

O Hermes Relay (experimental) não é uma plataforma de chat em si — é um sistema de conectores que serve de fachada para plataformas como Discord, Telegram, Slack e WhatsApp, por meio de um conector externo que é dono das credenciais da plataforma. As capacidades (mídia, prompts nativos de aprovação/esclarecimento, reações, threads, digitação, streaming) são negociadas por conector no handshake, em vez de ficarem fixas na tabela acima.

Arquitetura​

flowchart TB
subgraph Gateway["Hermes Gateway"]
subgraph Adapters["Adaptadores de plataforma"]
tg[Telegram]
dc[Discord]
wa[WhatsApp]
sl[Slack]
gc[Google Chat]
sig[Signal]
sms[SMS]
em[E-mail]
ha[Home Assistant]
mm[Mattermost]
mx[Matrix]
dt[DingTalk]
fs[Feishu/Lark]
wc[WeCom]
wcb[WeCom Callback]
wx[Weixin]
bb[BlueBubbles]
qq[QQ]
yb[Yuanbao]
ms[Microsoft Teams]
api["Servidor de API<br/>(compatível com OpenAI)"]
wh[Webhooks]
end

store["Armazenamento de sessões<br/>por chat"]
agent["AIAgent<br/>run_agent.py"]
cron["Agendador de cron<br/>tique a cada 60s"]
end

tg --> store
dc --> store
wa --> store
sl --> store
gc --> store
sig --> store
sms --> store
em --> store
ha --> store
mm --> store
mx --> store
dt --> store
fs --> store
wc --> store
wcb --> store
wx --> store
bb --> store
qq --> store
yb --> store
ms --> store
api --> store
wh --> store
store --> agent
cron --> store

Cada adaptador de plataforma recebe as mensagens, roteia por um armazenamento de sessões por chat e as despacha para o AIAgent processar. O gateway também roda o agendador de cron, com um tique a cada 60 segundos para executar as tarefas que estiverem vencidas.

Tokens de silêncio intencional​

Para conversas em grupo, hooks e fluxos de automação, o Hermes aceita tokens explícitos de silêncio. Se a resposta final do agente for exatamente um token aceito, o gateway suprime a entrega e não manda nada para o chat.

Tokens aceitos:

  • [SILENT]
  • SILENT
  • NO_REPLY
  • NO REPLY

Espaços em branco e maiúsculas/minúsculas são normalizados, mas a resposta final inteira precisa ser o token. Uma frase como "Use [SILENT] quando nada mudou" é entregue normalmente.

O silêncio é só uma decisão de entrega. O Hermes guarda o turno de silêncio do assistente na transcrição da sessão, então a conversa continua alternando normalmente:

user: conversa paralela
assistant: [SILENT] # guardado, não entregue
user: próxima mensagem

Turnos que falharam continuam aparecendo como erro; o Hermes não esconde falhas só porque o texto se parece com um token de silêncio.

Configuração rápida​

O jeito mais fácil de configurar as plataformas de mensagens é o assistente interativo:

hermes gateway setup # Configuração interativa de todas as plataformas de mensagens

Ele leva você pela configuração de cada plataforma com seleção por setas, mostra quais plataformas já estão configuradas e se oferece para iniciar/reiniciar o gateway no final.

Comandos do gateway​

hermes gateway # Roda em primeiro plano
hermes gateway setup # Configura as plataformas de mensagens de forma interativa
hermes gateway install # Instala como serviço de usuário (Linux) / serviço launchd (macOS)
sudo hermes gateway install --system # Só no Linux: instala um serviço de sistema que sobe no boot
hermes gateway start # Inicia o serviço padrão
hermes gateway stop # Para o serviço padrão
hermes gateway status # Confere o status do serviço padrão
hermes gateway status --system # Só no Linux: inspeciona explicitamente o serviço de sistema

Watchdog opcional do laço de eventos no Linux​

Um gateway administrado pelo systemd pode aderir à recuperação de processo quando o laço de eventos do asyncio do Python para de receber tempo de agendamento. Isso cobre travas do processo inteiro, que também impedem as tarefas de liveness específicas de plataforma de rodar:

~/.hermes/config.yaml
gateway:
systemd_watchdog_seconds: 120

Regere a unidade de serviço depois de mudar essa opção:

hermes gateway install --force

Um valor positivo faz a unidade gerada usar Type=notify, NotifyAccess=main e o WatchdogSec correspondente. O Hermes manda batimentos só enquanto o laço de eventos está progredindo no tempo certo; o systemd reinicia o processo quando eles param. O padrão 0 mantém o comportamento atual de Type=simple. Essa opção é exclusiva de Linux/systemd e não trata uma desconexão comum de rede da plataforma como falha do laço de eventos.

Comandos de chat (dentro das mensagens)​

ComandoDescrição
/new ou /resetComeça uma conversa nova
/model [provider:model]Mostra ou troca o modelo (aceita a sintaxe provider:model)
/personality [name]Define uma personalidade (none para limpar)
/retryRepete a última mensagem
/undoRemove a última troca
/statusMostra as informações da sessão
/whoamiMostra o seu acesso a comandos de barra neste escopo (admin / usuário / sem restrição)
/stopPara o agente em execução
/approveAprova um comando perigoso pendente
/denyRecusa um comando perigoso pendente
/sethomeDefine este chat como canal principal
/compressComprime o contexto da conversa manualmente
/title [name]Define ou mostra o título da sessão
/resume [name]Retoma uma sessão nomeada antes
/sessions [all] [search <query>]Lista as sessões anteriores; search <query> filtra por título ou id
/usageMostra o uso de tokens desta sessão (/usage reset [--force] resgata um reset de limite do Codex guardado)
/insights [days]Mostra análises e insights de uso
/reasoning [level|show|hide]Muda o esforço de raciocínio ou liga/desliga a exibição do raciocínio
/voice [on|off|tts|join|leave|status]Controla as respostas por voz nas mensagens e o comportamento em canal de voz do Discord
/rollback [number]Lista ou restaura checkpoints do sistema de arquivos
/background <prompt>Roda um prompt numa sessão separada, em segundo plano
/reload-mcpRecarrega os servidores MCP a partir da configuração
/updateAtualiza o Hermes Agent para a última versão
/helpMostra os comandos disponíveis
/<skill-name>Invoca qualquer skill instalada

Gerenciamento de sessões​

Persistência de sessão​

As sessões duram entre mensagens até serem reiniciadas. O agente lembra o contexto da sua conversa.

Achar sessões antigas (/sessions)​

O /sessions lista as suas sessões anteriores no chat atual, e /sessions <name> retoma uma delas (atalho para o /resume). Quando a lista fica longa, /sessions search <query> (com o apelido find) filtra por título ou por id de sessão, ordenando pelas mais ativas recentemente. A listagem entre origens, com /sessions all, é só para admin — usuários comuns só veem as sessões da própria origem de chat.

Sobrescritas persistentes de /model​

Uma troca por /model num chat de gateway vale para aquela sessão e agora sobrevive a reinícios do gateway: a escolha de modelo/provedor é gravada no armazenamento de sessões e reidratada no primeiro uso depois do reinício (as credenciais são resolvidas de novo no carregamento e nunca são escritas em disco). O /new (ou /reset) limpa a sobrescrita, e /model <name> --global grava a escolha no config.yaml. O /model <name> --once vale por um único turno.

Confiabilidade da entrega​

As respostas finais do agente são registradas num livro-razão de entrega durável (state.db) em volta de cada envio para a plataforma. Se o gateway quebrar ou reiniciar entre produzir uma resposta e a plataforma confirmar o recebimento, o próximo boot reentrega a resposta guardada em vez de perdê-la — ou de reexecutar o turno inteiro.

A semântica é honestamente "pelo menos uma vez":

  • Uma resposta cujo envio nunca começou é reentregue como está.
  • Uma resposta que estava no meio do envio quando o gateway morreu (a plataforma pode ter recebido ou não) é reentregue com um prefixo visível "♻️ Recovered reply — … may be a duplicate". A ambiguidade é rotulada, nunca reenviada em silêncio.
  • A reentrega tem limite: 3 tentativas, 24 horas de validade, e depois a linha é abandonada. As linhas entregues são podadas depois de 7 dias.

Desligue com gateway.delivery_ledger: false no config.yaml (isso volta ao comportamento antigo: as respostas em trânsito se perdem numa queda).

Políticas de reinício​

Por padrão, as sessões nunca são reiniciadas automaticamente — o contexto vive até você dar /reset na mão ou até a compressão de contexto entrar em ação. Se você quiser reinícios automáticos, adira pela seção session_reset do ~/.hermes/config.yaml:

session_reset:
mode: idle # "idle", "daily", "both" ou "none" (padrão)
idle_minutes: 1440 # para idle/both: minutos de inatividade antes do reinício
at_hour: 4 # para daily/both: hora do dia (0-23, horário local)
ModoDescrição
noneNunca reinicia sozinho (padrão)
dailyReinicia numa hora específica todo dia
idleReinicia depois de N minutos de inatividade
bothO que disparar primeiro

Um processo vivo em segundo plano (iniciado com terminal(background=true)) normalmente protege a sessão dele de reiniciar, para a saída não se perder. Para impedir que um processo esquecido — um servidor de preview, digamos — prenda uma sessão aberta para sempre, um processo em segundo plano mais velho que bg_process_max_age_hours (padrão de 24) deixa de bloquear o reinício. O processo não é morto, só ignorado pela guarda de reinício. Coloque 0 para desligar esse corte (qualquer processo vivo bloqueia o reinício, o comportamento antigo), ou aumente o valor se você roda tarefas legítimas de vários dias cuja atividade deve manter a conversa aberta.

Configure sobrescritas por plataforma no ~/.hermes/gateway.json:

{
"reset_by_platform": {
"telegram": { "mode": "idle", "idle_minutes": 240 },
"discord": { "mode": "idle", "idle_minutes": 60 }
}
}

Sobrescrita de modelo e de prompt de sistema por canal​

Canais diferentes podem rodar modelos e personas diferentes a partir de um único gateway — por exemplo, um modelo barato e rápido no #daily e um modelo de ponta com um prompt especialista no #dev. Configure o channel_overrides sob a plataforma, no ~/.hermes/gateway-config.yaml:

platforms:
discord:
enabled: true
channel_overrides:
"123456789012345678": # id do canal/thread
model: anthropic/claude-sonnet-4.6
provider: anthropic
system_prompt: "Você é o especialista em revisão de código do canal #dev."
"987654321098765432":
model: openai/gpt-5-mini

Detalhes:

  • As três chaves são opcionais — defina só model, só system_prompt, ou qualquer combinação. Os campos que ficarem sem valor recaem nos padrões globais.
  • A ordem de busca é primeiro o id exato do canal/thread e depois o id do canal/fórum pai — então as threads do Discord herdam a sobrescrita do canal pai automaticamente.
  • A prioridade de resolução do modelo é: sobrescrita de sessão por /model → channel_overrides → configuração global. Um usuário que roda /model num chat ainda vence o padrão do canal.
  • A sobrescrita de system_prompt substitui o prompt global do gateway naquele canal (ela é efêmera — injetada a cada turno, não guardada no histórico).

Segurança​

Por padrão, o gateway nega todos os usuários que não estejam numa lista de permissão ou pareados por DM. Esse é o padrão seguro para um bot com acesso ao terminal.

# Restringir a usuários específicos (recomendado):
TELEGRAM_ALLOWED_USERS=123456789,987654321
DISCORD_ALLOWED_USERS=123456789012345678
SIGNAL_ALLOWED_USERS=+155****4567,+155****6543
SMS_ALLOWED_USERS=+155****4567,+155****6543
EMAIL_ALLOWED_USERS=confiavel@exemplo.com,colega@trabalho.com
MATTERMOST_ALLOWED_USERS=3uo8dkh1p7g1mfk49ear5fzs5c
MATRIX_ALLOWED_USERS=@alice:matrix.org
DINGTALK_ALLOWED_USERS=user-id-1
FEISHU_ALLOWED_USERS=ou_xxxxxxxx,ou_yyyyyyyy
WECOM_ALLOWED_USERS=user-id-1,user-id-2
WECOM_CALLBACK_ALLOWED_USERS=user-id-1,user-id-2
TEAMS_ALLOWED_USERS=aad-object-id-1,aad-object-id-2

# Ou liberar
GATEWAY_ALLOWED_USERS=123456789,987654321

# Ou liberar explicitamente todos os usuários (NÃO recomendado para bots com acesso ao terminal):
GATEWAY_ALLOW_ALL_USERS=true

Pareamento por DM (alternativa às listas de permissão)​

Em vez de configurar IDs de usuário na mão, usuários desconhecidos recebem um código de pareamento de uso único quando mandam DM para o bot. O e-mail é a exceção: remetentes de e-mail desconhecidos são ignorados, a menos que o pareamento por e-mail seja ligado explicitamente.

# O usuário vê: "Pairing code: XKGH5N7P"
# Você aprova com:
hermes pairing approve telegram XKGH5N7P

# Outros comandos de pareamento:
hermes pairing list # Vê os usuários pendentes + aprovados
hermes pairing revoke telegram 123456789 # Remove o acesso

Os códigos de pareamento expiram em 1 hora, têm limite de taxa e usam aleatoriedade criptográfica.

Admins e usuários comuns​

As listas de permissão respondem "esta pessoa consegue alcançar o bot?" A divisão admin / usuário responde "agora que ela entrou, o que ela pode fazer?"

Todo usuário permitido cai em um de dois níveis por escopo (DM ou grupo/canal):

  • Admin — acesso total. Pode rodar todo comando de barra registrado (embutido + de plugin) e usar toda capacidade controlada.
  • Usuário comum — acesso restrito. Pode conversar com o agente normalmente, mas só pode rodar os comandos de barra que você liberar explicitamente. O piso sempre permitido é /help e /whoami.

Os níveis são configurados por plataforma e por escopo. Ser admin em DM não implica ser admin em grupo/canal — cada escopo tem a própria lista de admins.

O que os níveis controlam hoje: os comandos de barra. A divisão passa pelo registro vivo de comandos, então cobre os embutidos e os registrados por plugin sem fiação por recurso. O chat comum não é afetado — quem não é admin continua podendo falar com o agente.

O que pode vir a ser controlado: mais superfícies de capacidade (acesso a ferramentas, troca de modelo, operações caras) vão se pendurar na mesma distinção admin / usuário conforme forem sendo acrescentadas. Configurar a divisão agora significa que essas restrições futuras entram sem atrito, sem você ter que remodelar quem é admin.

Configuração​

gateway:
platforms:
discord:
extra:
allow_from: ["111", "222", "333"]
allow_admin_from: ["111"] # admins → todos os comandos de barra
user_allowed_commands: [status, model] # o que quem não é admin pode rodar
# Opcional: escopo separado de grupo/canal
group_allow_admin_from: ["111"]
group_user_allowed_commands: [status]

Compatibilidade retroativa: se o allow_admin_from não estiver definido para um escopo, a divisão em níveis fica desligada naquele escopo e todo usuário permitido tem acesso total. As instalações existentes continuam funcionando sem mudança nenhuma — adira quando quiser a distinção.

Inspecionar o seu acesso​

Use /whoami em qualquer plataforma para ver o escopo ativo, o seu nível (admin / usuário / sem restrição) e quais comandos de barra você pode rodar. Veja as páginas do Telegram e do Discord para exemplos específicos de cada plataforma.

Redirecionar o agente​

Mande uma mensagem enquanto o agente está trabalhando para corrigir o turno ativo:

  • A geração do modelo recomeça com contexto — o raciocínio já mostrado e o texto parcial visível são mantidos como um checkpoint comum de assistente
  • O trabalho já concluído continua disponível — as chamadas de ferramenta e os resultados anteriores continuam no turno
  • As ferramentas em execução terminam com segurança — a correção é aplicada na próxima fronteira de resultado de ferramenta, em vez de matar a ferramenta
  • O /stop continua sendo uma parada dura — use-o para cancelar o turno ativo e o trabalho em primeiro plano

Fila, interrupção ou condução (modo de entrada ocupada)​

Por padrão, mandar mensagem para um agente ocupado redireciona o turno ativo. Existem outros dois modos:

  • queue — as mensagens seguintes esperam e viram o próximo turno depois que a tarefa atual terminar.
  • steer — as mensagens seguintes são injetadas na execução atual por /steer, chegando ao agente depois da próxima chamada de ferramenta. Sem interrupção, sem turno novo. Recai no comportamento de queue se o agente ainda não tiver começado.
display:
busy_input_mode: steer # ou queue, ou interrupt (padrão)
busy_ack_enabled: true # coloque false para suprimir por completo a resposta ⚡/⏳/⏩ no chat

Na primeira vez que você manda mensagem para um agente ocupado em qualquer plataforma, o Hermes acrescenta um lembrete de uma linha ao aviso de ocupado, explicando o botão ("💡 First-time tip — …"). O lembrete dispara uma vez por instalação — uma flag em onboarding.seen.busy_input_prompt trava isso. Apague essa chave para ver a dica de novo.

Se você achar o aviso de ocupado barulhento, coloque display.busy_ack_enabled: false. O tratamento da entrada continua igual; só a mensagem de confirmação some.

Perguntas de esclarecimento (múltipla escolha)​

Quando o agente usa a ferramenta clarify para fazer uma pergunta, o gateway mostra as opções como uma lista numerada (ou como botões nativos nas plataformas que aceitam). O clarify também aceita perguntas de múltipla escolha — o agente pode deixar você escolher várias opções de uma vez:

  • Plataformas de mensagens — a pergunta diz "Multiple selections allowed"; responda com os números separados por vírgula ou espaço (por exemplo, 1, 3), com o texto da opção, ou com a sua própria resposta livre.
  • CLI clássica / TUI — a múltipla escolha aparece como caixas de seleção: Espaço alterna uma opção, Enter envia a seleção.

As perguntas de escolha única funcionam como antes: escolha uma opção pelo número, pelo botão ou pelo texto, ou digite a sua própria resposta pelo caminho "Other".

Notificações de progresso das ferramentas​

Controle quanta atividade de ferramenta aparece pelo ~/.hermes/config.yaml:

display:
tool_progress: all # off | new | all | verbose | log
tool_progress_command: false # coloque true para habilitar o /verbose nas mensagens
# Como o progresso é agrupado nas plataformas que aceitam edição de mensagem:
# accumulate (padrão) — edita um balão no lugar conforme as ferramentas rodam
# separate — manda uma mensagem por ferramenta (estilo pré-v0.9; mais barulhento)
# Só vale onde o tool_progress já está ligado.
tool_progress_grouping: accumulate # accumulate | separate

Modo log — arquivo de auditoria em vez de mensagens no chat​

Colocar display.tool_progress: log faz o Hermes não mandar balões de progresso para o chat. Em vez disso, cada chamada de ferramenta é acrescentada como uma linha em ~/.hermes/logs/tool_calls.log — um arquivo de auditoria rotativo (5 MB × 3 backups), passado pelo mesmo formatador que oculta segredos dos logs comuns, então as credenciais nunca chegam ao disco. Use isso quando quiser um rastro completo das chamadas de ferramenta sem barulho nenhum no chat.

Frases de status configuráveis​

As linhas de status de execução longa do gateway (os batimentos no estilo "ainda trabalhando…") vêm de um catálogo de frases. Os padrões embutidos ficam em gateway/assets/status_phrases.yaml; você pode acrescentar as suas com arquivos portáveis entre perfis, sob o HERMES_HOME:

  • ~/.hermes/status_phrases.yaml ou qualquer *.yaml em ~/.hermes/status_phrases/ (caminhos convencionais, carregados automaticamente), ou
  • aponte a configuração para um caminho relativo:
display:
status_phrases:
path: status_phrases/whatsapp.yaml # relativo a HERMES_HOME
mode: append # append (padrão) ou replace

Os arquivos de frase mapeiam uma superfície (status, generic) para uma lista de strings (no máximo 80 frases por superfície, de 160 caracteres cada). Caminhos absolutos e escapes com .. são ignorados, para a configuração continuar portável entre perfis. Só as strings de frase que você configurou são usadas — argumentos brutos de ferramenta, comandos e texto de raciocínio nunca são interpolados numa frase de status.

Carimbo de hora das mensagens no contexto do modelo​

Desligado por padrão. Quando você liga, o Hermes coloca um carimbo de hora legível (por exemplo, [Tue 2026-04-28 13:40:53 CEST]) na frente de cada mensagem de usuário no contexto do modelo, para o agente saber quando as mensagens foram mandadas — útil para raciocínio temporal ("você perguntou de manhã…", perceber um intervalo grande). Ele não é acrescentado às mensagens do assistente nem ao prompt de sistema.

gateway:
message_timestamps:
enabled: false # coloque true para mostrar os horários de envio ao modelo

As transcrições gravadas ficam sempre limpas — o carimbo é guardado como metadado da mensagem independentemente desse botão, então ligá-lo depois também revela os horários de envio das mensagens antigas, e o replay nunca acumula prefixos duplicados.

Quando ligado, o bot manda mensagens de status conforme trabalha:

💻 `ls -la`...
🔍 web_search...
📄 web_extract...
🐍 execute_code...

Sessões em segundo plano​

Rode um prompt numa sessão separada, em segundo plano, para o agente trabalhar nele de forma independente enquanto o seu chat principal continua respondendo:

/background Verifique todos os servidores do cluster e relate os que estiverem fora do ar

O Hermes confirma na hora:

🔄 Background task started: "Verifique todos os servidores do cluster..."
Task ID: bg_143022_a1b2c3

Como funciona​

Cada prompt de /background abre uma instância separada do agente, que roda de forma assíncrona:

  • Sessão isolada — o agente em segundo plano tem a própria sessão, com o próprio histórico de conversa. Ele não sabe nada do contexto do seu chat atual e recebe só o prompt que você deu.
  • Mesma configuração — herda o seu modelo, provedor, conjuntos de ferramentas, opções de raciocínio e roteamento de provedor da configuração atual do gateway.
  • Não bloqueia — o seu chat principal continua totalmente interativo. Mande mensagens, rode outros comandos ou comece mais tarefas em segundo plano enquanto ele trabalha.
  • Entrega do resultado — quando a tarefa termina, o resultado é mandado de volta para o mesmo chat ou canal onde você deu o comando, com o prefixo "✅ Background task complete". Se falhar, você vê "❌ Background task failed" com o erro.

Notificações de processo em segundo plano​

Quando o agente que roda uma sessão em segundo plano usa terminal(background=true) para iniciar processos de longa duração (servidores, builds etc.), o gateway pode empurrar atualizações de status para o seu chat. Controle isso com o display.background_process_notifications no ~/.hermes/config.yaml:

display:
background_process_notifications: concise # concise | all | result | error | off
ModoO que você recebe
conciseMensagem de status de uma linha na conclusão; as falhas acrescentam um pedaço curto da saída (padrão)
allAtualizações da saída em andamento e a mensagem final com a saída bruta
resultSó a mensagem final de conclusão, com a saída bruta (qualquer que seja o código de saída)
errorSó a mensagem final com a saída bruta, quando o código de saída for diferente de zero
offNenhuma mensagem do observador de processos

Você também pode definir isso por variável de ambiente:

HERMES_BACKGROUND_NOTIFICATIONS=result

Casos de uso​

  • Monitorar servidores — "/background Verifique a saúde de todos os serviços e me avise se algum estiver fora do ar"
  • Builds longos — "/background Faça o build e o deploy do ambiente de staging" enquanto você continua conversando
  • Tarefas de pesquisa — "/background Pesquise o preço dos concorrentes e resuma numa tabela"
  • Operações com arquivos — "/background Organize as fotos em ~/Downloads por data, em pastas"
dica

Tarefas em segundo plano nas plataformas de mensagens são do tipo dispare e esqueça — você não precisa esperar nem ficar conferindo. Os resultados chegam sozinhos no mesmo chat quando a tarefa termina.

Gerenciamento do serviço​

Linux (systemd)​

hermes gateway install # Instala como serviço de usuário
hermes gateway start # Inicia o serviço
hermes gateway stop # Para o serviço
hermes gateway status # Confere o status
journalctl --user -u hermes-gateway -f # Vê os logs

# Habilita o lingering (mantém rodando depois do logout)
sudo loginctl enable-linger $USER

# Ou instale um serviço de sistema que sobe no boot mas ainda roda como o seu usuário
sudo hermes gateway install --system
sudo hermes gateway start --system
sudo hermes gateway status --system
journalctl -u hermes-gateway -f

Use o serviço de usuário em notebooks e máquinas de desenvolvimento. Use o serviço de sistema em VPS ou hosts sem interface, que devem voltar no boot sem depender do linger do systemd.

Não acrescente um drop-in de kill com ExecStopPost

A unidade que o Hermes instala já desliga o gateway de forma limpa, com KillMode=mixed + KillSignal=SIGTERM, e usa Restart=always com RestartForceExitStatus para que atualizações e o /restart subam de novo direito. Não acrescente um drop-in do systemd como ExecStopPost=/bin/kill -9 $MAINPID — o ExecStopPost dispara em toda parada, inclusive nos reinícios limpos, então ele manda SIGKILL na instância recém-criada antes de ela estabilizar, e o Restart=always a recria na hora. O resultado é um laço infinito de reinício (e, no Telegram, uma enxurrada de mensagens de reinício). Se você acrescentou um drop-in desses, tire: systemctl --user edit hermes-gateway (ou sudo systemctl edit hermes-gateway, para um serviço de sistema), apague a linha do ExecStopPost e depois rode systemctl --user daemon-reload.

VMs sem interface: serviço de usuário + linger evita pedidos de root

Um serviço de sistema precisa de root a cada reinício — inclusive no reinício automático do gateway no fim do hermes update. Quando o hermes update roda como um usuário sem root, ele tenta um sudo systemctl sem senha; se isso não estiver disponível, ele pula o reinício e imprime o comando manual sudo systemctl restart hermes-gateway (ele nunca trava num pedido interativo de senha).

Numa VM sem interface, na qual você nunca faz login, um serviço de usuário com o lingering ligado dá o mesmo comportamento de subir no boot, com zero envolvimento de root:

hermes gateway install # serviço de usuário
sudo loginctl enable-linger $USER # uma vez só: sobe no boot, sobrevive ao logout

Depois disso, o hermes update consegue reiniciar o gateway sem privilégio nenhum. Se você preferir manter o serviço de sistema, ou rode as atualizações com sudo hermes update, ou dê sudo sem senha para o systemctl à conta de serviço, por exemplo em sudo visudo -f /etc/sudoers.d/hermes-gateway:

hermes ALL=(root) NOPASSWD: /usr/bin/systemctl --no-ask-password reset-failed hermes-gateway*, /usr/bin/systemctl --no-ask-password start hermes-gateway*, /usr/bin/systemctl --no-ask-password restart hermes-gateway*

Evite manter a unidade de gateway de usuário e a de sistema instaladas ao mesmo tempo, a menos que seja mesmo essa a intenção. O Hermes avisa se detectar as duas, porque o comportamento de start/stop/status fica ambíguo.

Várias instalações

Se você roda várias instalações do Hermes na mesma máquina (com diretórios HERMES_HOME diferentes), cada uma ganha o próprio nome de serviço no systemd. O padrão ~/.hermes usa hermes-gateway; as outras instalações usam hermes-gateway-<hash>. Os comandos hermes gateway miram automaticamente o serviço certo para o seu HERMES_HOME atual.

macOS (launchd)​

hermes gateway install # Instala como agente launchd
hermes gateway start # Inicia o serviço
hermes gateway stop # Para o serviço
hermes gateway status # Confere o status
tail -f ~/.hermes/logs/gateway.log # Vê os logs

O plist gerado fica em ~/Library/LaunchAgents/ai.hermes.gateway.plist. Ele inclui três variáveis de ambiente:

  • PATH — o seu PATH completo de shell no momento da instalação, com o bin/ do venv e o node_modules/.bin na frente. Isso garante que as ferramentas instaladas pelo usuário (Node.js, ffmpeg etc.) fiquem disponíveis para os subprocessos do gateway, como a ponte do WhatsApp.
  • VIRTUAL_ENV — aponta para o virtualenv do Python, para as ferramentas resolverem os pacotes direito.
  • HERMES_HOME — dá escopo ao gateway na sua instalação do Hermes.
Mudanças de PATH depois da instalação

Os plists do launchd são estáticos — se você instalar ferramentas novas (por exemplo, uma nova versão do Node.js pelo nvm, ou o ffmpeg pelo Homebrew) depois de montar o gateway, rode hermes gateway install de novo para capturar o PATH atualizado. O gateway detecta o plist velho e recarrega sozinho.

Várias instalações

Assim como no serviço systemd do Linux, cada diretório HERMES_HOME ganha o próprio rótulo no launchd. O padrão ~/.hermes usa ai.hermes.gateway; as outras instalações usam ai.hermes.gateway-<suffix>.

Conjuntos de ferramentas por plataforma​

Cada plataforma tem o próprio conjunto de ferramentas:

PlataformaConjuntoCapacidades
CLIhermes-cliAcesso total
Telegramhermes-telegramFerramentas completas, incluindo terminal
Discordhermes-discordFerramentas completas, incluindo terminal
WhatsApphermes-whatsappFerramentas completas, incluindo terminal
WhatsApp Cloud APIhermes-whatsappFerramentas completas, incluindo terminal (compartilha o conjunto com a ponte Baileys)
Slackhermes-slackFerramentas completas, incluindo terminal
Google Chathermes-google_chatFerramentas completas, incluindo terminal
Signalhermes-signalFerramentas completas, incluindo terminal
SMShermes-smsFerramentas completas, incluindo terminal
E-mailhermes-emailFerramentas completas, incluindo terminal
Home Assistanthermes-homeassistantFerramentas completas + controle de dispositivos do HA (ha_list_entities, ha_get_state, ha_call_service, ha_list_services)
Mattermosthermes-mattermostFerramentas completas, incluindo terminal
Matrixhermes-matrixFerramentas completas, incluindo terminal
DingTalkhermes-dingtalkFerramentas completas, incluindo terminal
Feishu/Larkhermes-feishuFerramentas completas, incluindo terminal
WeComhermes-wecomFerramentas completas, incluindo terminal
WeCom Callbackhermes-wecom-callbackFerramentas completas, incluindo terminal
Weixinhermes-weixinFerramentas completas, incluindo terminal
BlueBubbleshermes-bluebubblesFerramentas completas, incluindo terminal
QQBothermes-qqbotFerramentas completas, incluindo terminal
Yuanbaohermes-yuanbaoFerramentas completas, incluindo terminal
Microsoft Teamshermes-teamsFerramentas completas, incluindo terminal
Servidor de APIhermes-api-serverFerramentas completas (sem clarify e text_to_speech — o acesso programático não tem um usuário interativo)
Webhookshermes-webhookFerramentas completas, incluindo terminal
Rafthermes-raftCanal só de acordar; o agente usa a CLI do Raft para a entrada e saída de mensagens

Operar um gateway com várias plataformas​

Um gateway normalmente roda vários adaptadores ao mesmo tempo (Telegram + Discord + Slack etc.). As seções abaixo tratam da operação do dia a dia, que atravessa todas as plataformas.

Comando /platform​

Com o gateway rodando, use o comando de barra /platform de qualquer sessão de CLI conectada ou de qualquer chat para inspecionar e conduzir adaptadores individuais sem reiniciar o gateway inteiro:

/platform list # mostra todos os adaptadores e o estado de cada um
/platform pause <name> # para de despachar mensagens novas para um adaptador
/platform resume <name> # reativa um adaptador pausado

O /platform list mostra se cada adaptador está running, paused (na mão) ou paused-by-breaker (veja abaixo). Pausar mantém o adaptador carregado e os laços de segundo plano dele vivos — as mensagens que chegam são descartadas, mas a conexão em si continua aberta, então retomar é instantâneo.

Veja também o comando de resumo de status mais amplo, o /platforms.

Disjuntor automático​

Cada adaptador é envolvido por um disjuntor. Falhas repetidas que valeriam nova tentativa (oscilações de rede, respostas de limite de taxa, respostas 5xx do lado de cima, desconexões de websocket) fazem o disjuntor abrir — o adaptador é pausado automaticamente, uma notificação ao operador é mandada para o canal principal de outra plataforma viva, quando houver uma configurada, e uma linha estruturada de log é emitida.

O disjuntor não retoma sozinho — ele fica aberto até você rodar /platform resume <name> na mão. Isso é de propósito: se uma plataforma está numa queda prolongada, você não quer o gateway se debatendo em reconexões.

Onde olhar quando uma plataforma está pausada​

Quando um adaptador está pausado, confira:

  1. O log do gateway (~/.hermes/logs/gateway.log ou o log da unidade do systemd/launchd). Procure pelo nome da plataforma e por circuit breaker, paused ou disabled. O evento de abertura inclui a contagem de falhas e o último erro.
  2. A saída de /platform list — mostra o estado atual e o último motivo.
  3. A página de status do provedor (status da API de bots do Telegram, status do Discord etc.). O disjuntor abriu porque a plataforma estava com problema; não tente retomar antes de ela voltar.

Com o lado de cima saudável, /platform resume <name> limpa o disjuntor e rearma o adaptador.

Notificações de reinício​

Quando o gateway reinicia (ou é desligado com sessões em andamento), ele pode mandar uma mensagem única de "o agente voltou" / "o agente foi interrompido" para o canal principal de cada plataforma. Isso é controlado por plataforma pela flag gateway_restart_notification no gateway-config.yaml, que por padrão é true:

gateway:
platforms:
telegram:
home_chat_id: "123456789"
gateway_restart_notification: false # não avisar nesta plataforma
discord:
home_chat_id: "987654321"
# gateway_restart_notification omitido → padrão true

Desligue nas plataformas barulhentas ou de baixa prioridade e deixe ligado no seu chat principal. A notificação é mandada uma vez por reinício, não importa quantas sessões estavam em andamento.

Indicadores de digitação​

Enquanto o agente processa uma mensagem, o gateway mostra um status de digitação ao vivo nas plataformas que aceitam — um balão de "digitando…" no Telegram/Discord/Signal, ou o status de assistente "is thinking…" no Slack. Isso é controlado por plataforma pela flag typing_indicator no gateway-config.yaml, que por padrão é true:

gateway:
platforms:
slack:
typing_indicator: false # não mostrar "is thinking…" no Slack
telegram:
# typing_indicator omitido → padrão true

Coloque typing_indicator: false em qualquer plataforma onde o indicador atrapalhe. Algumas pessoas acham o status "is thinking…" do Slack barulhento (ele também desabilita rapidinho a caixa de escrita enquanto aparece, já que usa a Assistant API do Slack). Desligar só suprime o indicador — a entrega das mensagens e todo o resto ficam iguais. A flag é genérica, então a mesma chave funciona para toda plataforma.

Retomada de sessão entre reinícios do gateway​

Quando o gateway desliga com uma chamada de ferramenta ou uma geração em andamento, as sessões afetadas são marcadas como restart_interrupted. Na próxima inicialização, o gateway agenda uma retomada automática para cada uma — o usuário recebe um aviso curto no chat ("Send any message after restart and I'll try to resume where you left off.") e a sessão continua do último turno confirmado quando ele responder.

Esse comportamento vem ligado e aparece no log na inicialização do gateway:

Scheduled auto-resume for N restart-interrupted session(s)

Não é preciso configurar nada. Se você não quer o aviso, coloque gateway_restart_notification: false na plataforma.

Padrões de progresso pensados para o celular​

O Telegram costuma ser uma caixa de entrada de celular, então os padrões são calibrados para essa superfície:

  • O tool_progress vem como off — sem um fluxo de migalhas por ferramenta enchendo o chat.
  • O busy_ack_detail vem como off — os avisos de estado ocupado e os batimentos de execução longa ficam secos (sem o detalhe de depuração iteration 21/60).
  • O interim_assistant_messages fica ligado — o comentário real do assistente no meio do turno (o modelo literalmente contando o que vai fazer) é sinal, não ruído.
  • O long_running_notifications fica ligado — um único balão "⏳ Working — N min", editado no lugar, se atualiza a cada poucos minutos, para você ter um batimento em vez de encarar typing… por meia hora.

Desligue qualquer um dos padrões que ficam ligados, ou volte a ligar o progresso detalhado, por plataforma:

display:
platforms:
telegram:
# Religa o fluxo de progresso das ferramentas
tool_progress: new
# Mostra "iteration N/M, running: tool" nos batimentos e nos avisos de ocupado
busy_ack_detail: true
# Ou silencia de vez
interim_assistant_messages: false
long_running_notifications: false

Limpeza dos balões de progresso (opt-in)​

As mensagens de progresso das ferramentas, o batimento de "ainda trabalhando…" e os balões de callback de status também podem ser apagados automaticamente depois que a resposta final chega. Habilite por plataforma com display.platforms.<platform>.cleanup_progress:

display:
platforms:
telegram:
cleanup_progress: true
discord:
cleanup_progress: true

O padrão é false. Só as plataformas cujo adaptador implementa o delete_message respeitam a opção (hoje, Telegram e Discord). Execuções que falharam pulam a limpeza, para os balões ficarem como migalhas.

Próximos passos​