Technical Guide

13. Cron:定时任务怎么保存、触发和投递

从 cron/jobs.py 和 scheduler 看 Hermes 如何管理每日提醒、日报、备份和自动化任务。

这篇解决什么问题

Hermes 不只能被动等你发消息。

Cron 让它可以按时间自动运行:日报、提醒、备份、监控、定时总结,都属于这一类。

这一篇看 Cron 的源码设计。

关键文件

先看:

cron/jobs.py
cron/scheduler.py
cron/scheduler_provider.py
hermes_cli/cron.py
tools/cronjob_tool.py

其中 cron/jobs.py 文件注释写得很清楚:

Jobs are stored in ~/.hermes/cron/jobs.json
Output is saved to ~/.hermes/cron/output/{job_id}/{timestamp}.md

这两个路径是理解 Cron 的入口。

一个 job 里有什么

一个 Hermes cron job 通常包含:

job_id
name
schedule
prompt
skills
deliver
enabled / paused state
next_run_at
last_run_at
last_status

高级一点还可以有:

script
no_agent
workdir
context_from
enabled_toolsets
model override

这意味着 Cron 不是简单 crontab。它可以带 Skill、指定工作目录、限制工具、接上游任务输出。

schedule 支持什么

Hermes 支持多种写法:

30m
every 2h
0 9 * * *
2026-07-01T09:00:00

实际解析和 next_run 计算在 cron 相关代码里处理。

为什么 jobs.json 需要锁

cron/jobs.py 里有文件锁和进程内锁。

原因是:Gateway 里的 scheduler、CLI 手动 pause/resume/run、并发 tick 都可能同时修改 jobs.json

如果没有锁,一个任务刚被暂停,另一个进程又把旧状态写回去,就会出现“看起来暂停了但还在跑”。

所以 Cron 存储层要比普通 JSON 文件读写谨慎得多。

Cron 执行链路

简化流程:

scheduler tick
→ 读取 jobs.json
→ 找到 due jobs
→ 标记运行状态
→ 创建独立 agent session
→ 注入 prompt / skills / workdir / tools
→ 执行任务
→ 保存 output
→ 投递到 deliver 目标
→ 更新 next_run_at 和 last_status

如果 no_agent=True,脚本输出就是最终消息,不再调用 LLM。

deliver 为什么重要

Cron 任务没人在线等结果。

所以必须知道结果投递到哪里:

origin  当前会话来源
local   只保存本地
all     所有 home channel
具体平台 chat id

你之前的早中晚目标提醒,就是典型 Cron:不需要联网、不需要工具,只需要按时把固定提醒发回当前飞书聊天。

如果 Cron 失败怎么查

先看:

hermes cron list
hermes cron status

再看:

~/.hermes/cron/output/<job_id>/
~/.hermes/logs/

如果是模型 401,通常不是 Cron 本身坏,而是 provider/API key 不可用。

下一篇看什么

下一篇看 Gateway。

Cron 是时间入口,Gateway 是平台入口。它们最终都会把任务送进 Agent。