Documentação oficial desta página · v0.20.6
Tarefas agendadas (cron)
Agende tarefas para rodar sozinhas, em linguagem natural ou em expressões cron. O Hermes expõe o
gerenciamento por uma ferramenta única, a cronjob, com operações por ação, em vez de ferramentas
separadas para agendar, listar e remover.
O que o cron faz hoje
Tarefas de cron conseguem:
- agendar execuções únicas ou recorrentes
- pausar, retomar, editar, disparar e remover tarefas
- anexar nenhuma, uma ou várias skills a uma tarefa
- entregar o resultado na conversa de origem, em arquivos locais, ou nos destinos configurados
- rodar em sessões novas de agente, com a lista normal de ferramentas
- rodar em modo sem agente — um script no horário marcado, com a saída entregue literal, sem modelo nenhum (veja modo sem agente)
Tudo isso está disponível ao próprio Hermes pela ferramenta cronjob, então você cria, pausa, edita
e remove tarefas pedindo em português — sem CLI.
Em qual modelo uma tarefa de cron roda? A resolução na hora do disparo é: modelo fixado na
tarefa → cron.model no config.yaml → o padrão global do hermes model.
- Fixado na tarefa — definido por você, pelo painel, por
hermes cron create/edit --model … --provider …, ou editando o~/.hermes/cron/jobs.json. Uma vez definido, fica. A ferramentacronjobdo agente não define nem muda o modelo por tarefa — isso é decisão do usuário. cron.model/cron.model_provider— um padrão para toda a frota de cron: toda tarefa sem modelo fixado roda nele, independentemente do seu modelo de conversa. Defina uma vez (hermes config set cron.model <nome>) e trocar o modelo de conversa comhermes modelou/modelnunca mexe na sua frota.- Padrão global — só quando nenhum dos dois está definido é que a tarefa segue o
hermes model. Nesse caso o Hermes tira um retrato do provedor e do modelo na criação, e se o padrão global mudar depois, a tarefa falha fechada: ela pula a execução, não faz chamada de inferência, e avisa você uma vez — e continua pulada (e silenciosa) nos disparos seguintes, até você agir ou a configuração voltar. Em tarefas recorrentes, fixe o provedor e o modelo explicitamente (hermes cron edit <id> --provider <provedor> --model <modelo>) para seguir. Isso impede que uma tarefa sem supervisão herde em silêncio uma troca para um provedor ou modelo pago. Definir ocron.model(ou fixar por tarefa) é o jeito deliberado de rotear o gasto de cron, e a proteção não age no eixo já coberto por ele. Quem prefere que as tarefas sem fixação sigam o padrão global pode desligar a proteção.
O hermes setup --portal é a opção de menor atrito para execuções sem supervisão, porque a renovação
do OAuth é automática.
Esforço de raciocínio por tarefa. Uma tarefa pode fixar o próprio nível de pensamento,
independentemente do modelo: none, minimal, low, medium, high, xhigh, max ou ultra.
Definido, ele vence tanto o agent.reasoning_effort global quanto o
agent.reasoning_overrides por modelo, naquelas execuções (none desliga o pensamento). Defina com
hermes cron create/edit --reasoning-effort high; passe uma string vazia na edição para limpar e
voltar a seguir a configuração. (De propósito, isso não é exposto na ferramenta cronjob do agente —
configuração de modelo é decisão do usuário.) Níveis que o modelo não suporta são limitados ou
omitidos pelo provedor na hora — fixar xhigh num modelo que vai até high roda em high. A
fixação não tem efeito em tarefas no_agent (não há chamada de modelo a ajustar). Use para rodar
análises pesadas em high, enquanto tarefas recorrentes baratas rodam em minimal, sem tocar no seu
padrão global.
Sessões de cron não podem criar mais tarefas de cron recursivamente. O Hermes desliga as ferramentas de gerenciamento dentro das execuções, para evitar laços de agendamento sem controle.
Criar tarefas
Na conversa, com /cron
/cron add 30m "Me lembre de conferir a compilação"
/cron add "every 2h" "Confira a situação do servidor"
/cron add "every 1h" "Resuma os itens novos do feed" --skill blogwatcher
/cron add "every 1h" "Use as duas skills e combine o resultado" --skill blogwatcher --skill maps
Pela linha de comando
hermes cron create "every 2h" "Confira a situação do servidor"
hermes cron create "every 1h" "Resuma os itens novos do feed" --skill blogwatcher
hermes cron create "every 1h" "Use as duas skills e combine o resultado" \
--skill blogwatcher \
--skill maps \
--name "Combo de skills"
Conversando
Peça normalmente:
Toda manhã às 9h, veja as notícias de IA no Hacker News e me mande um resumo no Telegram.
O Hermes usa a ferramenta cronjob por dentro.
Validação antes do disparo
Antes de montar qualquer coisa para uma execução agendada, o agendador confere se a configuração da tarefa consegue mesmo produzir uma execução bem-sucedida:
- se a chave de API do provedor resolve (pulado quando há uma cadeia de
fallback_providersconfigurada, já que a reserva pode salvar uma chave principal ausente), - se as skills anexadas estão prontas (sem variáveis de ambiente, comandos ou arquivos de credencial faltando),
- se os destinos de entrega são conhecidos e têm credencial de gateway configurada (destinos
localeoriginnunca são conferidos).
Quando a validação falha, o last_status da tarefa vira blocked_config, UM alerta é entregue (não
se repete a cada disparo) e nenhuma chamada de modelo é feita — uma tarefa mal configurada nunca
gasta token. A próxima execução saudável limpa o estado bloqueado, então uma quebra futura volta a
alertar.
Para desligar a validação e voltar ao comportamento antigo (a execução segue e falha no meio):
cron:
preflight: false
Ou: hermes config set cron.preflight false.
Deixar tarefas sem fixação seguirem o padrão global
A proteção contra deriva de modelo e provedor vem ligada. Se as suas tarefas sem fixação devem mesmo
seguir toda troca global, desligue no config.yaml:
cron:
model_drift_guard: false
Ou pelo comando de configuração:
hermes config set cron.model_drift_guard false
Isso desliga tanto o bloqueio em execução quanto o aviso mostrado quando a configuração global muda.
Os retratos existentes continuam gravados, então voltar a opção para true religa a proteção sem
recriar tarefa nenhuma.
Com a proteção desligada, tarefas sem supervisão herdam a mudança de padrão global na hora. Uma troca para um provedor ou modelo pago passa a gastar dinheiro em toda execução agendada.
Tarefas com skills
Uma tarefa de cron pode carregar uma ou mais skills antes de rodar o prompt.
Uma skill
cronjob(
action="create",
skill="blogwatcher",
prompt="Check the configured feeds and summarize anything new.",
schedule="0 9 * * *",
name="Morning feeds",
)
Várias skills
As skills são carregadas na ordem. O prompt vira a instrução da tarefa, em cima delas.
cronjob(
action="create",
skills=["blogwatcher", "maps"],
prompt="Look for new local events and interesting nearby places, then combine them into one short brief.",
schedule="every 6h",
name="Local brief",
)
Útil quando você quer um agente agendado herdando fluxos reaproveitáveis, sem enfiar o texto inteiro da skill no prompt do cron.
Rodar uma tarefa dentro de um projeto
Por padrão, tarefas de cron rodam soltas de qualquer repositório — nenhum AGENTS.md, CLAUDE.md
ou .cursorrules é carregado, e as ferramentas de terminal, arquivo e execução de código rodam a
partir de onde o gateway subiu. Passe --workdir (na CLI) ou workdir= (na chamada de ferramenta)
para mudar:
# Pela CLI (o agendamento e o prompt são posicionais)
hermes cron create "every 1d at 09:00" \
"Audite os PRs abertos, resuma a saúde do CI e poste em #eng" \
--workdir /home/eu/projetos/acme
# Da conversa, pela ferramenta cronjob
cronjob(
action="create",
schedule="every 1d at 09:00",
workdir="/home/eu/projetos/acme",
prompt="Audite os PRs abertos, resuma a saúde do CI e poste em #eng",
)
Com o workdir definido:
- o
AGENTS.md, oCLAUDE.mde o.cursorrulesdaquele diretório entram no prompt de sistema (na mesma ordem de descoberta da CLI interativa) - o
terminal, oread_file, owrite_file, opatch, osearch_filese oexecute_codeusam aquele diretório - o caminho precisa ser um diretório absoluto que exista — caminhos relativos e diretórios inexistentes são recusados na criação e na atualização
- passe
--workdir ""(ouworkdir=""pela ferramenta) na edição para limpar e voltar ao comportamento antigo
Tarefas com workdir rodam em sequência no disparo do agendador, e não no grupo paralelo. É de
propósito: o trabalhador de cron aplica o diretório da tarefa por estado global do processo, então
duas tarefas com workdir ao mesmo tempo corromperiam o diretório uma da outra. Tarefas sem
workdir continuam em paralelo.
Editar tarefas
Não é preciso apagar e recriar uma tarefa só para mudá-la.
O <job_id> abaixo também aceita o nome da tarefa (sem diferenciar maiúsculas) — útil quando você
lembra do morning-digest, mas não do identificador hexadecimal. Um identificador exato tem
precedência; se a referência não é um identificador e mais de uma tarefa tem aquele nome, o comando
recusa e imprime os candidatos, para você desempatar.
Na conversa
/cron edit <job_id> --schedule "every 4h"
/cron edit <job_id> --prompt "Use a tarefa revisada"
/cron edit <job_id> --skill blogwatcher --skill maps
/cron edit <job_id> --remove-skill blogwatcher
/cron edit <job_id> --clear-skills
Pela linha de comando
hermes cron edit <job_id> --schedule "every 4h"
hermes cron edit <job_id> --prompt "Use a tarefa revisada"
hermes cron edit <job_id> --skill blogwatcher --skill maps
hermes cron edit <job_id> --add-skill maps
hermes cron edit <job_id> --remove-skill blogwatcher
hermes cron edit <job_id> --clear-skills
Observações:
--skillrepetido substitui a lista de skills anexadas--add-skillacrescenta, sem substituir--remove-skilltira skills específicas--clear-skillsremove todas
Ciclo de vida
Na conversa
/cron list
/cron pause <job_id>
/cron resume <job_id>
/cron run <job_id>
/cron remove <job_id>
Pela linha de comando
hermes cron list
hermes cron pause <id_ou_nome>
hermes cron resume <id_ou_nome>
hermes cron run <id_ou_nome>
hermes cron remove <id_ou_nome>
hermes cron edit <id_ou_nome> [...opções]
hermes cron status
hermes cron tick
O que cada um faz:
pause— mantém a tarefa, mas para de agendá-laresume— reabilita e calcula a próxima execução futurarun— dispara no próximo tique do agendadorremove— apaga de vezedit— muda agendamento, prompt, entrega e o resto
Busca por nome. Os cinco verbos que mudam algo (pause, resume, run, remove, edit) e a
ferramenta cronjob do agente aceitam o nome da tarefa (sem diferenciar maiúsculas) no lugar do
identificador. Tanto o agente quanto a CLI preferem um identificador exato, se existir; nomes
ambíguos (mais de uma tarefa com o mesmo nome) são recusados, com a lista completa de candidatos.
Nomes não são únicos, então essa proteção carrega peso — ela evita mexer em silêncio na tarefa errada.
Tarefas de cron que gerenciam tarefas de cron
Por padrão, agentes abertos pelo agendador não usam a ferramenta cronjob — uma tarefa agendada
não cria, edita nem remove outras. Para permitir, no config.yaml:
cron:
allow_agent_scheduling: true # padrão: false
Habilitado, um agente agendado gerencia a tabela de cron como qualquer sessão de conversa: agenda tarefas únicas de continuação a partir do trabalho agendado, ajusta a própria cadência, ou roda uma tarefa "bibliotecária", que reconcilia a tabela inteira (lista, e então atualiza, remove ou cria). Duas propriedades mantêm isso sob controle:
- Uma tabela única, do usuário. Tarefas criadas de dentro de uma execução caem no mesmo
jobs.jsonde todas as outras, sem posse especial — você lista, edita ou remove exatamente como se tivesse criado. - Sem entrega órfã. Uma execução de cron é efêmera, então o
deliver: originde dentro de uma é resolvido na criação para o destino concreto da tarefa que criou (plataforma:id_da_conversa[:id_do_tópico], oulocalse ela não entrega em lugar nenhum). Uma tarefa criada por um agente agendado nunca aponta a saída para uma sessão que não existe mais. Destinos explícitos (local,all,telegram:<id>) são respeitados literalmente.
Prefira prompts que atualizam tarefas existentes (listar primeiro, depois atualizar pelo identificador) a prompts que criam tarefas novas a cada execução.
Como funciona
A execução do cron é responsabilidade do daemon do gateway. O gateway tica o agendador a cada 60 segundos, rodando as tarefas devidas em sessões isoladas.
hermes gateway install # instala como serviço de usuário
sudo hermes gateway install --system # Linux: serviço de sistema, no boot, para servidores
hermes gateway # ou roda em primeiro plano
hermes cron list
hermes cron status
Comportamento do agendador
A cada tique, o Hermes:
- carrega as tarefas de
~/.hermes/cron/jobs.json - compara o
next_run_atcom a hora atual - abre uma sessão de
AIAgentnova para cada tarefa devida - injeta as skills anexadas naquela sessão, se houver
- roda o prompt até o fim
- entrega a resposta final
- atualiza os metadados e o próximo horário
Uma trava de arquivo em ~/.hermes/cron/.tick.lock impede que tiques sobrepostos rodem o mesmo lote
duas vezes.
Histórico de execução
O Hermes registra cada tentativa reivindicada no banco local do perfil,
~/.hermes/cron/executions.db, antes de despachar. As tentativas passam por claimed e running, e
terminam num estado imutável: completed, failed ou unknown. Depois de um reinício, o Hermes só
marca uma tentativa abandonada como unknown quando o PID original e a impressão digital de início
do processo provam que o dono sumiu. Tentativas desconhecidas são registro de auditoria, e nunca são
repetidas sozinhas.
Veja as tentativas recentes com hermes cron runs [id] --limit 20 (apelido: history). O histórico
terminal é limitado; tentativas ativas nunca são podadas. O registro entra nos backups rápidos.
Aviso de falhas repetidas
Cada tarefa acompanha um failure_streak — execuções falhadas em sequência (falha de entrega não
conta). Uma execução que falha antes mesmo de chegar ao agente — um import quebrado depois de uma
atualização pela metade, um cliente de provedor que não consegue ser construído — conta e alerta
igual. Quando a sequência de uma tarefa recorrente atinge o limiar, a mensagem de falha entregue na
conversa ganha um aviso, dizendo que a tarefa falhou N vezes seguidas e sugerindo corrigir, pausar
(hermes cron pause <tarefa>) ou remover. Qualquer execução bem-sucedida zera a sequência, e o
hermes cron list mostra a contagem ao lado da última execução da tarefa. Tarefas de execução única
nunca avisam.
cron:
failure_nudge_threshold: 3 # padrão; 0 desliga o aviso
Incidentes de falha: reconhecer uma falha conhecida
Uma tarefa recorrente que falha sempre com o mesmo erro cutuca você a cada execução. Cada falha também é registrada como um incidente durável, indexado pela tarefa mais uma assinatura normalizada do texto do erro, no mesmo banco de registro do histórico.
hermes cron incidents # lista (a atividade mais recente primeiro)
hermes cron incidents --state alerted # filtra: detected | alerted | closed
hermes cron incidents ack <id> # reconhece — para de avisar
Reconhecer um incidente silencia o aviso por execução só daquela assinatura exata. Nada mais muda: o histórico ainda registra toda falha, a sequência continua contando, e no instante em que a tarefa começar a falhar com um erro diferente, um incidente novo é criado e os alertas voltam. Uma execução bem-sucedida não mexe nos incidentes — eles são por assinatura, não por tarefa.
Ciclo de vida do incidente: detected (falha registrada) → alerted (pelo menos um aviso chegou à
entrega) → closed (reconhecido; terminal para aquela assinatura). O texto do erro guardado é
higienizado de segredos e cortado antes de ser escrito.
O registro está sempre ligado e não custa nada ignorar — nenhum aviso é suprimido até você fazer o
ack explicitamente.
Opções de entrega
Ao agendar, você diz para onde a saída vai:
| Opção | Descrição | Exemplo |
|---|---|---|
"origin" | De volta para onde a tarefa foi criada | Padrão nas plataformas de mensagem |
"local" | Só em arquivos locais (~/.hermes/cron/output/) | Padrão na CLI |
"telegram" | Canal principal do Telegram | Usa o TELEGRAM_HOME_CHANNEL |
"telegram:123456" | Conversa específica, pelo identificador | Entrega direta |
"telegram:-100123:17585" | Tópico específico | Formato id_da_conversa:id_do_tópico |
"discord" | Canal principal do Discord | Usa o DISCORD_HOME_CHANNEL |
"discord:#engenharia" | Canal específico | Pelo nome |
"slack" | Canal principal do Slack | |
"whatsapp" | ||
"signal" | Signal | |
"matrix" | Sala principal do Matrix | |
"mattermost" | Canal principal do Mattermost | |
"email" | ||
"sms" | SMS pela Twilio | |
"homeassistant" | Home Assistant | |
"dingtalk" | DingTalk | |
"feishu" | Feishu/Lark | |
"wecom" | WeCom | |
"weixin" | Weixin (WeChat) | |
"bluebubbles" | BlueBubbles (iMessage) | |
"qqbot" | QQ Bot | |
"bot-chat" | A conversa canônica de bot deste perfil — o bot lê a saída e responde | Só na máquina local |
"bot-chat:research" | A conversa de bot de outro perfil local | Validado na criação |
"all" | Espalha por todos os canais principais conectados | Resolvido na hora do disparo |
"telegram,discord" | Espalha por um conjunto específico | Lista separada por vírgula |
"origin,all" | Entrega na origem e em todos os outros canais conectados | Combine os que quiser |
A resposta final do agente é entregue automaticamente ao destino em deliver: — o agente não manda
mensagem sozinho, então não há nada a chamar dentro do prompt.
Entrega em conversa de bot (bot-chat)
O bot-chat entrega a saída dentro da sessão canônica de "conversa de bot" de um perfil, como
mensagem de verdade. Diferente de todos os outros destinos — em que quem recebe é uma pessoa lendo
um canal — aqui quem recebe é o próprio bot: ele recebe a saída como mensagem que chega, age no que
precisa de ação, e responde na conversa dele. Use quando a saída agendada deve ser processada, e
não só publicada.
bot-chatsozinho aponta para o próprio perfil da tarefa.bot-chat:<perfil>aponta para outro perfil na mesma máquina. Os nomes são validados contra ohermes profile listna criação; perfis em outros gateways ou máquinas nunca podem ser alvo, então perfis de mesmo nome em máquinas diferentes não são ambíguos.- Cada entrega custa um turno completo de agente ao bot de destino — cuidado com a frequência.
- Combina com outros destinos (
bot-chat,telegram), mas nunca entra noall.
Intenção de roteamento (all)
O all manda uma tarefa para todo canal de mensagem que você configurou, sem precisar enumerar. Ele
é resolvido na hora do disparo, então uma tarefa criada antes de você ligar o Telegram passa a
incluí-lo no tique seguinte à definição do TELEGRAM_HOME_CHANNEL.
Semântica: o all se expande para toda plataforma com canal principal configurado. Zero é aceitável;
a tarefa simplesmente não produz destino e é registrada como falha de entrega.
O all se combina com destinos explícitos. O origin,all entrega na conversa de origem mais todos
os outros canais principais conectados, sem duplicar por (plataforma, conversa, tópico).
Tópico de cron no Telegram (TELEGRAM_CRON_THREAD_ID)
Com o modo de tópicos do Telegram ligado, a conversa raiz é reservada como um saguão de sistema —
respostas mandadas ali são recusadas com um lembrete, e o reply_to_message_id é descartado, então
não dá para responder a uma mensagem de cron que caiu na conversa principal.
Aponte o cron para um tópico dedicado:
- No Telegram, abra a conversa com o bot e crie um tópico chamado
Cron, por exemplo. Segure o cabeçalho do tópico → Copiar link; o número no fim é omessage_thread_id. - Defina
TELEGRAM_CRON_THREAD_ID=<esse número>no seu.env.
Isso vale só para entregas de cron. O TELEGRAM_HOME_CHANNEL_THREAD_ID (usado em outros lugares,
como avisos de reinício) não muda. Destinos explícitos, como
deliver="telegram:id_conversa:id_tópico", continuam vencendo a variável. As respostas às mensagens
de cron agora chegam na sessão do tópico, então dá para agir direto nelas.
Embrulho da resposta
Por padrão, a saída entregue vem com cabeçalho e rodapé, para quem recebe saber que veio de uma tarefa agendada:
Cronjob Response: Morning feeds
-------------
<saída do agente aqui>
Note: The agent cannot see this message, and therefore cannot respond to it.
Para entregar a saída crua, sem embrulho, coloque cron.wrap_response em false:
# ~/.hermes/config.yaml
cron:
wrap_response: false
Tarefas continuáveis (responder a uma entrega de cron)
Por padrão, uma entrega de cron é do tipo dispare e esqueça: a mensagem é enviada, mas não vive no histórico da conversa, então, se você responder, o agente não tem registro do que disse. Marque uma tarefa como continuável e o resumo entregue vira uma conversa em que dá para responder — o agente tem o resumo no contexto, em vez de perguntar "que Tarefa #2?".
É opcional, e vem desligado. Habilite globalmente na configuração, ou por tarefa, pelo
attach_to_session da ferramenta cronjob (que sobrescreve o global naquela tarefa):
# ~/.hermes/config.yaml
cron:
mirror_delivery: false # true torna as entregas continuáveis
O comportamento prefere tópicos, no escopo da própria conversa da tarefa:
- Plataformas com tópico (tópicos do Telegram, threads do Discord e do Slack): cada entrega abre o próprio tópico, e o resumo é semeado naquela sessão, então uma resposta ali continua com contexto completo. Uma tarefa recorrente (um resumo diário, por exemplo) abre um tópico novo por execução, mantendo cada discussão isolada.
- Plataformas só de mensagem direta (WhatsApp, Signal, SMS): não existem tópicos, então o resumo é espelhado na sessão da conversa de origem — a própria conversa é a superfície de continuação.
Só a conversa da própria tarefa é tocada:
- a conversa de origem em que ela foi criada;
- o canal principal como reserva, quando o
deliver: originnão capturou origem nenhuma (tarefas criadas por script ou pela API, e não numa conversa viva de gateway) — a conversa principal da pessoa fazendo as vezes da origem; - um destino explícito único de
plataforma:conversa, mas só quando a própria tarefa opta comattach_to_session: true— quem escreveu a tarefa declara aquele destino uma conversa. Omirror_deliveryglobal sozinho nunca torna continuável uma conversa endereçada explicitamente.
Destinos de difusão (all, canais principais sem endereço) nunca viram continuáveis. O espelho é
escrito como um turno de usuário rotulado ([Cron delivery: <nome da tarefa>]), o que mantém a
alternância do histórico segura em todos os provedores de modelo.
Continuação plana, no canal (Slack)
O comportamento acima cria um tópico a cada entrega. Se você prefere que uma tarefa continuável caia
plana na linha do tempo do canal, sem tópico, defina a superfície de continuação do Slack como
in_channel:
# ~/.hermes/config.yaml
slack:
cron_continuable_surface: in_channel # padrão: thread
reply_in_thread: false # emparelhamento obrigatório (veja abaixo)
require_mention: false # para uma resposta simples continuar a tarefa
No modo in_channel, o resumo é entregue como mensagem comum de topo (sem abrir tópico), e a sua
resposta continua a tarefa pela sessão compartilhada do canal. Três opções trabalham juntas:
cron_continuable_surface: in_channel— pula a criação de tópico na entrega.reply_in_thread: false(obrigatória) — faz o bot responder plano no canal, na mesma sessão do canal inteiro em que o resumo foi semeado. Sem ela, a continuação ainda funciona, mas chega num tópico (ela recua com segurança para a continuação em tópico, nunca perde a resposta — e o gateway registra um aviso na inicialização, para você notar a incoerência).require_mention: false(ou acrescente o canal afree_response_channels) — para você responder com uma mensagem comum; senão o bot só acorda quando é mencionado a cada resposta.
Como a continuação é a sessão do canal inteiro, ela é compartilhada: outras conversas no canal —
e uma segunda tarefa continuável no mesmo modo — entram na mesma conversa rolante. Isso é inerente ao
"plano num canal", e é o mesmo custo que quem usa reply_in_thread: false já aceita; use a
superfície padrão, thread, quando quiser cada continuação isolada.
Hoje é uma capacidade do Slack. As outras plataformas aceitam a chave, mas recuam para thread (as
primitivas de continuação delas são diferentes); a escolha é por plataforma, na configuração de cada
uma. É uma opção do lado do gateway — um /restart já pega; não é preciso reinstalar o aplicativo no
Slack.
O cron_continuable_surface é uma configuração de canal — uma conversa individual não tem
divisão entre tópico e linha do tempo (ela já é plana), então a chave não tem efeito ali. Quem manda
numa conversa individual é a opção separada slack.dm_top_level_threads_as_sessions:
false— todas as mensagens de topo dividem uma sessão rolante, então o resumo continuável e a sua resposta caem na mesma sessão, e a tarefa continua com contexto. É o que você quer para cron continuável em conversa individual.true(padrão) — cada mensagem de topo é uma sessão própria, então responder a um resumo entregue começa uma sessão nova, sem registro dele. A continuação não funciona nesse modo (nem para cron, nem para qualquer outra entrega plana).
Então, para uma tarefa continuável entregue numa conversa individual, defina
slack.dm_top_level_threads_as_sessions: false. O cron_continuable_surface não é necessário (e é
ignorado) em conversas individuais.
Supressão silenciosa
Se a resposta final do agente contém [SILENT], a entrega é suprimida por completo. A saída ainda é
salva localmente para auditoria (em ~/.hermes/cron/output/), mas nenhuma mensagem é enviada.
Serve para tarefas de monitoramento, que só devem falar quando algo está errado:
Veja se o nginx está rodando. Se estiver tudo bem, responda só [SILENT].
Se não, relate o problema.
Tarefas que falharam sempre entregam, independentemente do [SILENT] — só execuções bem-sucedidas
podem ser silenciadas.
Tempo limite de script
Scripts de pré-execução (anexados pelo parâmetro script) têm tempo limite padrão de 3600 segundos
(1 hora). Isso limita só o script — tarefas com skill ou com modelo rodam num orçamento de
inatividade separado, e não são limitadas por esse valor. Para mudar:
# ~/.hermes/config.yaml
cron:
script_timeout_seconds: 1800 # 30 minutos
Ou defina a variável HERMES_CRON_SCRIPT_TIMEOUT. A ordem de resolução é: variável de ambiente →
config.yaml → 3600 segundos.
O cron também limita a limpeza de sessão e de recursos depois da execução. Isso acontece depois de a chamada do modelo retornar, então é separado do tempo de inatividade. O padrão é 10 segundos por operação de limpeza. Se um finalizador de armazenamento ou de cliente parar de responder, o agendador registra um erro, libera a trava da tarefa e permite que execuções futuras aconteçam, em vez de pular aquela tarefa para sempre.
# ~/.hermes/config.yaml
cron:
cleanup_timeout_seconds: 10
Coloque cleanup_timeout_seconds: 0 só para voltar ao comportamento antigo, sem limite.
Tempo limite de envio de mídia
Quando uma entrega inclui anexos (um PDF gerado, um áudio, um relatório exportado) enviados por um adaptador de gateway vivo, cada envio é limitado por um tempo — 300 segundos, por padrão. Arquivos grandes em conexões lentas podem precisar de mais:
# ~/.hermes/config.yaml
cron:
media_send_timeout_seconds: 600 # 10 minutos por anexo
Ou defina a variável HERMES_CRON_MEDIA_SEND_TIMEOUT. Um anexo que estourou o tempo é registrado no
estado da execução como falha parcial de entrega (o texto ainda chega).
Tempo limite da entrega em conversa de bot
Uma entrega bot-chat roda um turno completo de agente na conversa do bot de destino, então o limite
é de minutos, não de segundos — 600 por padrão:
# ~/.hermes/config.yaml
cron:
bot_chat_delivery_timeout_seconds: 900
Uma entrega que estoura o tempo é registrada em last_delivery_error; o turno do bot pode terminar
sozinho mesmo assim.
Modo sem agente (tarefas só de script)
Para tarefas recorrentes que não precisam de raciocínio — vigias clássicos, alertas de disco e
memória, batimentos, avisos de CI — passe no_agent=True na criação. O agendador roda o seu script
no horário e entrega a saída padrão dele diretamente, pulando o agente:
hermes cron create "every 5m" \
--no-agent \
--script memory-watchdog.sh \
--deliver telegram \
--name "memory-watchdog"
Semântica:
- Saída padrão do script (aparada) → entregue literal, como a mensagem.
- Saída vazia → tique silencioso, sem entrega. É o padrão do vigia: "só fale quando algo estiver errado".
- Saída diferente de zero, ou tempo esgotado → um alerta de erro é entregue, para um vigia quebrado não falhar em silêncio.
{"wakeAgent": false}na última linha → tique silencioso (a mesma trava das tarefas com modelo).- Sem token, sem modelo, sem reserva de provedor — a tarefa nunca toca a camada de inferência.
Arquivos .sh e .bash rodam sob o bash do PATH, quando existe, ou sob /bin/bash (importante
no Git Bash do Windows). O resto roda sob o interpretador Python atual (sys.executable). Os scripts
precisam resolver dentro de $HERMES_HOME/scripts/ — nomes relativos, caminhos absolutos e caminhos
com ~ são aceitos quando o alvo resolvido continua nesse diretório; caminhos que escapam são
recusados. O ambiente do subprocesso é higienizado: credenciais de provedor e outros segredos
gerenciados pelo Hermes não são herdados por scripts de cron.
O agente monta isso para você
O esquema da ferramenta cronjob expõe o no_agent ao Hermes diretamente, então você descreve um
vigia na conversa e deixa o agente montar:
Me avise no Telegram se a RAM passar de 85%, a cada 5 minutos.
O Hermes escreve o script em ~/.hermes/scripts/ com o write_file e então chama:
cronjob(action="create", schedule="every 5m",
script="memory-watchdog.sh", no_agent=True,
deliver="telegram", name="memory-watchdog")
Ele escolhe no_agent=True sozinho quando o conteúdo da mensagem é totalmente determinado pelo
script (vigias, alertas de limiar, batimentos). A mesma ferramenta também deixa o agente pausar,
retomar, editar e remover — então o ciclo inteiro é conduzido pela conversa, sem ninguém tocar a CLI.
Veja o guia de cron só com script para exemplos completos.
Encadear tarefas com context_from
Tarefas de cron rodam em sessões isoladas, sem memória das execuções anteriores. Mas às vezes a saída
de uma é exatamente o que a próxima precisa. O parâmetro context_from faz essa ligação sozinho — o
prompt da tarefa B recebe a saída mais recente da tarefa A como contexto, em tempo de execução.
# Tarefa 1: coleta os dados crus
cronjob(
action="create",
prompt="Fetch the top 10 AI/ML stories from Hacker News. Save them to ~/.hermes/data/briefs/raw.md in markdown format with title, URL, and score.",
schedule="0 7 * * *",
name="AI News Collector",
)
# Tarefa 2: tria — recebe a saída da tarefa 1 como contexto
# Pegue o identificador da tarefa 1 com: cronjob(action="list")
cronjob(
action="create",
prompt="Read ~/.hermes/data/briefs/raw.md. Score each story 1–10 for engagement potential and novelty. Output the top 5 to ~/.hermes/data/briefs/ranked.md.",
schedule="30 7 * * *",
context_from="<id_da_tarefa1>",
name="AI News Triage",
)
# Tarefa 3: entrega — recebe a saída da tarefa 2 como contexto
cronjob(
action="create",
prompt="Read ~/.hermes/data/briefs/ranked.md. Write 3 tweet drafts (hook + body + hashtags). Deliver to telegram:7976161601.",
schedule="0 8 * * *",
context_from="<id_da_tarefa2>",
name="AI News Brief",
)
Como funciona:
- Quando a tarefa 2 dispara, o Hermes lê a saída mais recente da tarefa 1, em
~/.hermes/cron/output/{id_tarefa1}/*.md - Essa saída é colocada antes do prompt da tarefa 2, automaticamente
- A tarefa 2 não precisa dizer "leia este arquivo" — ela recebe o conteúdo como contexto
- A corrente pode ter qualquer tamanho: tarefa 1 → tarefa 2 → tarefa 3 → …
O que o context_from aceita:
| Formato | Exemplo |
|---|---|
| Um identificador (texto) | context_from="a1b2c3d4" |
| Vários identificadores (lista) | context_from=["job_a", "job_b"] |
As saídas são concatenadas na ordem da lista.
Continuidade: carregar a saída da execução anterior
Coloque continuity=true e a tarefa injeta a própria saída mais recente em cada execução. Tarefas
recorrentes normalmente começam com amnésia — um vigia de notícias repete as mesmas histórias, um
monitor realerta a mesma condição. Com continuidade, a tarefa acorda vendo o que relatou da última
vez, e consegue não repetir e seguir de onde parou:
cronjob(
action="create",
prompt="Scan HN and arXiv for new agent-tooling papers. Report only items NOT already covered in your previous run's output.",
schedule="every 6h",
continuity=True,
name="Agent Tooling Scout",
)
A primeira execução não tem saída anterior, então o prompt roda como está. Nas seguintes, a saída
anterior entra antes, com um enquadramento de continuidade ("evite repetir o que já foi relatado").
Combina livremente com tarefas anteriores (context_from=["<id_de_outra>"] mais continuity=true),
e continuity=false na atualização desliga, preservando as outras entradas de context_from. Por
dentro, o campo é gravado como a entrada reservada self, dentro de context_from.
Pela CLI: hermes cron create "every 6h" "Procure novidades" --continuity, e
hermes cron edit <id> --continuity ou --no-continuity para ligar e desligar numa tarefa
existente. O mesmo botão aparece no editor de cron do painel e no diálogo de rotinas do Bot Mode, no
desktop.
Quando usar:
- Pipelines de várias etapas (coletar → filtrar → formatar → entregar)
- Tarefas dependentes, em que o passo N depende da saída do passo N−1
- Padrões de espalhar e juntar, em que uma tarefa agrega o resultado de várias
- Vigias e monitores recorrentes, que devem evitar repetir o próprio relatório anterior
(
continuity=true)
Recuperação de provedor
Tarefas de cron herdam os seus provedores de reserva e a rotação de pool de credenciais. Se a chave principal atinge o limite de requisições, ou o provedor devolve erro, o agente de cron consegue:
- cair num provedor alternativo, se você tem
fallback_providers(ou o antigofallback_model) configurado - girar para a credencial seguinte do seu pool, no mesmo provedor
Isso deixa tarefas de alta frequência, ou que rodam no horário de pico, mais resistentes — uma chave sozinha, limitada, não derruba a execução inteira.
Disparos agendados perdidos (last_fire_error)
Em instalações hospedadas (com cron gerenciado), um disparo agendado viaja do agendador da plataforma
até o painel, e daí ao servidor de API interno do gateway. Se esse último salto falha — o processo do
gateway caiu, ou o servidor de API dele nunca subiu — a execução nem começa, então não há registro
nem last_status para inspecionar. O sinal característico: a tarefa funciona toda vez que você
dispara na mão, mas nunca dispara sozinha.
Essas perdas ficam carimbadas no registro da tarefa como last_fire_error (com carimbo de tempo e
motivo), e aparecem:
- na ferramenta
cronjob, na açãolist— no campolast_fire_error - no
hermes cron list— numa linha vermelha,⚠ Missed scheduled fire:, sob a tarefa - na visão de tarefa do painel
O carimbo sempre reflete a saúde atual do disparo automático: ele é sobrescrito por perdas mais
novas e limpo sozinho pela próxima execução bem-sucedida. Se você o vê, a tarefa e o agendamento
estão bem — é o lado do gateway que precisa de atenção (mais comum: reinicie o gateway pelo
supervisor, para ele carregar o ambiente completo do perfil, com hermes gateway restart).
Recuperação de disparo perdido
Quando um agendador externo está ativo (cron gerenciado em instalações hospedadas), o gateway também roda uma varredura de recuperação: uma tarefa cujo horário passou sem disparo — e cuja janela de tolerância já acabou — é reivindicada e rodada localmente, então uma queda no caminho do disparo custa minutos, e não o dia inteiro. A varredura não duplica com as tentativas atrasadas do agendador, por usar a mesma reivindicação de armazenamento dos disparos normais.
cron:
misfire_grace_minutes: 10 # espera este tempo pelas tentativas do próprio agendador
# antes de recuperar localmente; 0 desliga
Instalações locais, com o tique embutido, não precisam disso — o tique já pega as tarefas atrasadas no próximo ciclo.
Formatos de agendamento
Atrasos relativos (execução única)
30m → roda uma vez, em 30 minutos
2h → roda uma vez, em 2 horas
1d → roda uma vez, em 1 dia
Intervalos (recorrente)
every 30m → a cada 30 minutos
every 2h → a cada 2 horas
every 1d → todo dia
Expressões cron
0 9 * * * → todo dia às 9h
0 9 * * 1-5 → dias úteis às 9h
0 */6 * * * → a cada 6 horas
30 8 1 * * → todo dia 1º, às 8h30
0 0 * * 0 → todo domingo, à meia-noite
Carimbos ISO
2026-03-15T09:00:00 → uma vez, em 15 de março de 2026, às 9h
Repetição
| Tipo de agendamento | Repetição padrão | Comportamento |
|---|---|---|
Única (30m, carimbo) | 1 | Roda uma vez |
Intervalo (every 2h) | para sempre | Roda até ser removida |
| Expressão cron | para sempre | Roda até ser removida |
Dá para sobrescrever:
cronjob(
action="create",
prompt="...",
schedule="every 2h",
repeat=5,
)
Gerenciar por programa
A API que o agente vê é uma ferramenta só:
cronjob(action="create", ...)
cronjob(action="list")
cronjob(action="update", job_id="...")
cronjob(action="pause", job_id="...")
cronjob(action="resume", job_id="...")
cronjob(action="run", job_id="...")
cronjob(action="remove", job_id="...")
No update, passe skills=[] para remover todas as skills anexadas.
Execuções manuais são assíncronas
O cronjob(action="run") dispara a tarefa na hora, em segundo plano (como o delegate_task): a
chamada volta na mesma hora, com um identificador, e o desfecho — sucesso ou falha, destino de
entrega, próxima execução agendada e um trecho da saída — reentra na conversa como mensagem nova
quando a execução termina. O agente (e você) segue trabalhando enquanto isso, e uma tarefa que já
está no meio de uma execução é recusada com "already running", em vez de disparar duas vezes.
Também dá para passar um prompt junto do action="run", para injetar contexto naquela execução:
cronjob(action="run", job_id="...", prompt="CONTEXT: focus on the EU region today")
O contexto é acrescentado ao prompt gravado, sob um cabeçalho ## Run Context, só naquele disparo —
ele nunca é gravado na definição da tarefa, e passa pela mesma varredura de injeção de prompt.
Ambientes que não recebem resultados desanexados (o hermes -z de uma vez só, o hermes cron run da
CLI, sessões filhas de cron, trabalhadores do kanban) caem em execução síncrona automaticamente.
Ferramentas disponíveis às tarefas de cron
O cron roda cada tarefa numa sessão nova, sem plataforma de conversa. Por padrão, o agente de cron
recebe o conjunto de ferramentas que você configurou para a plataforma cron, em hermes tools —
não o padrão da CLI, nem tudo que existe.
hermes tools
# → escolha a plataforma "cron" na interface
# → ligue e desligue conjuntos, como faria para Telegram, Discord e o resto
Há controle mais fino por tarefa, no campo enabled_toolsets do cronjob.create (ou do
cronjob.update, numa tarefa existente):
cronjob(action="create", name="weekly-news-summary",
schedule="every sunday 9am",
enabled_toolsets=["web", "file"], # só web e arquivo, sem terminal, navegador etc.
prompt="Summarize this week's AI news: ...")
Quando o enabled_toolsets está definido numa tarefa, ele vence; senão vale a configuração da
plataforma cron do hermes tools; senão, os padrões embutidos. Isso importa para controlar custo:
carregar browser e delegation em toda tarefinha de "buscar notícias" incha o esquema de
ferramentas em cada chamada de modelo.
Pular o agente por completo: wakeAgent
Se a sua tarefa anexa um script de pré-checagem (por script=), ele decide em tempo de execução se o
Hermes deve sequer chamar o agente. Emita uma última linha na saída padrão assim:
{"wakeAgent": false}
…e o cron pula a execução do agente naquele tique. Útil em consultas frequentes (a cada 1 a 5 minutos), que só precisam acordar o modelo quando o estado mudou de verdade — senão você paga por turnos vazios, repetidamente.
# script de pré-checagem
import json, sys
latest = fetch_latest_issue_count()
prev = read_state("issue_count")
if latest == prev:
print(json.dumps({"wakeAgent": False})) # pula este tique
sys.exit(0)
write_state("issue_count", latest)
print(json.dumps({"wakeAgent": True, "context": {"new_issues": latest - prev}}))
Sem o wakeAgent, o padrão é true (acordar o agente).
Receitas: travas baratas antes de rodar
A trava de wakeAgent dá um jeito de custo zero de decidir se uma tarefa agendada deve gastar
qualquer token. Três padrões cobrem quase tudo.
Trava por mudança de arquivo — só roda quando um arquivo observado tem conteúdo novo desde o
último tique bem-sucedido. O agendador registra o last_run_at de cada tarefa; compare com a data de
modificação do arquivo.
#!/bin/bash
# ~/.hermes/scripts/feed-changed.sh
FEED="$HOME/data/feed.json"
STATE="$HOME/.hermes/scripts/.feed-changed.last"
test -f "$FEED" || { echo '{"wakeAgent": false}'; exit 0; }
mtime=$(stat -c %Y "$FEED")
last=$(cat "$STATE" 2>/dev/null || echo 0)
if [ "$mtime" -le "$last" ]; then
echo '{"wakeAgent": false}'
else
echo "$mtime" > "$STATE"
echo '{"wakeAgent": true}'
fi
cronjob(action="create", name="process-feed",
schedule="every 30m",
script="feed-changed.sh",
prompt="A new ~/data/feed.json has landed. Summarize what changed.")
Trava por sinalizador externo — só roda quando outro processo sinalizou que está pronto (um gancho de publicação deixa um arquivo, uma tarefa de CI grava um valor).
#!/bin/bash
# ~/.hermes/scripts/flag-ready.sh
if test -f /tmp/new-data-ready; then
rm -f /tmp/new-data-ready
echo '{"wakeAgent": true}'
else
echo '{"wakeAgent": false}'
fi
cronjob(action="create", name="nightly-analysis",
schedule="0 9 * * *",
script="flag-ready.sh",
prompt="Run the nightly analysis over today's batch.")
Trava por contagem em SQL — só roda quando há linhas novas a processar no seu banco. O script
também passa a contagem ao agente, pelo context, então ele sabe o volume sem consultar de novo.
#!/usr/bin/env python
# ~/.hermes/scripts/new-rows.py
import json, sqlite3
conn = sqlite3.connect("/home/eu/dados/app.db")
n = conn.execute(
"SELECT COUNT(*) FROM messages WHERE ts > strftime('%s','now','-2 hours')"
).fetchone()[0]
if n < 1:
print(json.dumps({"wakeAgent": False}))
else:
print(json.dumps({"wakeAgent": True, "context": {"new_rows": n}}))
cronjob(action="create", name="summarize-new-msgs",
schedule="every 2h",
script="new-rows.py",
prompt="Summarize the new messages from the last 2 hours.")
O mesmo padrão vale para qualquer fonte de dados que você consulte de um script — Postgres, uma API HTTP, o seu próprio armazenamento de estado — sem embutir um avaliador de SQL no subsistema de cron.
O ~/.hermes/state.db do próprio Hermes é um esquema interno, que muda entre versões. Não consulte
ele numa trava de pré-execução — aponte para o seu próprio banco ou feed.
Crédito: este conjunto de receitas nasceu da exploração de @iankar8 no
#2654, que propunha acrescentar gatilhos de
SQL, arquivo e comando como mecanismo paralelo. A trava de script mais wakeAgent já cobre os três
casos a custo zero, então o trabalho virou documentação.
Encadear tarefas: context_from
Uma tarefa de cron consome a saída bem-sucedida mais recente de uma ou mais outras, listando os
nomes (ou identificadores) delas em context_from:
cronjob(action="create", name="daily-digest",
schedule="every day 7am",
context_from=["ai-news-fetch", "github-prs-fetch"],
prompt="Write the daily digest using the outputs above.")
As saídas concluídas mais recentes das tarefas citadas entram acima do prompt, como contexto daquela
execução. Cada entrada precisa ser um identificador ou nome válido (veja cronjob action="list").
Atenção: o encadeamento lê a saída concluída mais recente — ele não espera tarefas anteriores que
estejam rodando no mesmo tique.
Onde as tarefas ficam
As tarefas ficam em ~/.hermes/cron/jobs.json. A saída das execuções vai para
~/.hermes/cron/output/{id_da_tarefa}/{carimbo}.md.
As definições são JSON puro no disco: elas sobrevivem ao hermes update, a reinícios do gateway e a
reinícios da máquina. Uma tarefa que estava no meio de uma execução durante um reinício é marcada
como unknown no registro — ela não é repetida sozinha, mas o próximo tique agendado dispara
normalmente. Veja histórico de execução.
Peça ao agente para gerenciar as tarefas pela ferramenta cronjob, pelo hermes cron edit ou pelo
/cron — e não editando o jobs.json direto. Edições diretas podem falhar em silêncio quando a
proteção de escrita bloqueia o caminho
(quando o HERMES_WRITE_SAFE_ROOT está definido, por exemplo), e o rodapé do verificador de mudanças
é o sinal autoritativo de que nada foi salvo.
As tarefas podem guardar model e provider como null. Quando esses campos estão ausentes, o
Hermes os resolve na hora da execução, pela configuração global. Eles só aparecem no registro quando
há uma sobrescrita por tarefa.
O armazenamento usa escrita atômica de arquivo, então uma escrita interrompida não deixa um arquivo de tarefa pela metade.
Prompts autossuficientes continuam importando
Tarefas de cron rodam numa sessão de agente completamente nova. O prompt precisa conter tudo de que o agente precisa e que não venha das skills anexadas.
RUIM: "Confira aquele problema do servidor"
BOM: "Conecte por SSH no servidor 192.168.1.100 como usuário 'deploy', veja se o nginx está rodando com 'systemctl status nginx', e confirme que https://exemplo.com devolve HTTP 200."
Segurança
Os prompts das tarefas agendadas são varridos atrás de padrões de injeção de prompt e de exfiltração de credencial, na criação e na atualização. Prompts com truques de Unicode invisível, tentativas de backdoor em SSH, ou cargas óbvias de vazamento de segredo são bloqueados.