跳到主要内容

定时任务(Cron)

使用自然语言或 cron 表达式安排自动运行的任务。Hermes 通过单一的 cronjob 工具公开 cron 管理功能,使用操作式调用而非独立的调度/列表/删除工具。

Cron 当前能做的事

Cron 任务可以:

  • 安排一次性或循环任务
  • 暂停、恢复、编辑、触发和删除任务
  • 附加零个、一个或多个技能到任务
  • 将结果传递回原始聊天、本地文件或配置的平台目标
  • 在具有正常静态工具列表的全新 Agent 会话中运行
  • 无 Agent 模式运行——按计划运行脚本,将 stdout 直接传递,零 LLM 参与(参见下方无 Agent 模式

所有这些功能都通过 cronjob 工具对 Hermes 自身开放,因此你可以用自然语言创建、暂停、编辑和删除任务——无需 CLI。

注意

Cron 运行的会话不能递归创建更多 cron 任务。Hermes 在 cron 执行中禁用了 cron 管理工具,以防止失控的调度循环。

创建定时任务

在聊天中使用 /cron

/cron add 30m "Remind me to check the build"
/cron add "every 2h" "Check server status"
/cron add "every 1h" "Summarize new feed items" --skill blogwatcher
/cron add "every 1h" "Use both skills and combine the result" --skill blogwatcher --skill maps

从独立 CLI

hermes cron create "every 2h" "Check server status"
hermes cron create "every 1h" "Summarize new feed items" --skill blogwatcher
hermes cron create "every 1h" "Use both skills and combine the result" \
--skill blogwatcher \
--skill maps \
--name "Skill combo"

通过自然对话

直接向 Hermes 说:

Every morning at 9am, check Hacker News for AI news and send me a summary on Telegram.

Hermes 将在内部使用统一的 cronjob 工具。

技能支持的定时任务

定时任务可以在运行提示前加载一个或多个技能。

单个技能

cronjob(
action="create",
skill="blogwatcher",
prompt="Check the configured feeds and summarize anything new.",
schedule="0 9 * * *",
name="Morning feeds",
)

多个技能

技能按顺序加载。提示成为叠加在这些技能之上的任务指令。

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",
)

当你希望定时 Agent 继承可复用的工作流而无需将完整技能文本填入 cron 提示本身时,这很有用。

在项目目录中运行任务

Cron 任务默认与任何仓库分离运行——不加载 AGENTS.mdCLAUDE.md.cursorrules,终端/文件/代码执行工具从网关启动时的工作目录运行。使用 --workdir(CLI)或 workdir=(工具调用)来改变这一点:

# Standalone CLI (schedule and prompt are positional)
hermes cron create "every 1d at 09:00" \
"Audit open PRs, summarize CI health, and post to #eng" \
--workdir /home/me/projects/acme
# From a chat, via the cronjob tool
cronjob(
action="create",
schedule="every 1d at 09:00",
workdir="/home/me/projects/acme",
prompt="Audit open PRs, summarize CI health, and post to #eng",
)

当设置了 workdir 时:

  • 来自该目录的 AGENTS.mdCLAUDE.md.cursorrules 被注入系统提示(与交互式 CLI 相同的发现顺序)
  • terminalread_filewrite_filepatchsearch_filesexecute_code 都使用该目录作为其工作目录(通过 TERMINAL_CWD
  • 路径必须是存在的绝对目录——相对路径和不存在的目录在创建/更新时被拒绝
  • 在编辑时传入 --workdir ""(或工具中的 workdir="")以清除它并恢复旧行为
序列化

workdir 的任务在调度器触发时顺序运行,而不是在并行池中运行。这是有意为之——TERMINAL_CWD 是进程全局的,因此两个同时运行的 workdir 任务会相互破坏 cwd。无 workdir 的任务仍然并行运行,如之前一样。

编辑任务

你不需要删除并重新创建任务来更改它们。

聊天

/cron edit <job_id> --schedule "every 4h"
/cron edit <job_id> --prompt "Use the revised task"
/cron edit <job_id> --skill blogwatcher --skill maps
/cron edit <job_id> --remove-skill blogwatcher
/cron edit <job_id> --clear-skills

独立 CLI

hermes cron edit <job_id> --schedule "every 4h"
hermes cron edit <job_id> --prompt "Use the revised task"
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

说明:

  • 重复使用 --skill 会替换任务附加的技能列表
  • --add-skill 追加到现有列表而不替换
  • --remove-skill 删除特定的附加技能
  • --clear-skills 删除所有附加技能

生命周期操作

Cron 任务现在有比创建/删除更完整的生命周期。

聊天

/cron list
/cron pause <job_id>
/cron resume <job_id>
/cron run <job_id>
/cron remove <job_id>

独立 CLI

hermes cron list
hermes cron pause <job_id>
hermes cron resume <job_id>
hermes cron run <job_id>
hermes cron remove <job_id>
hermes cron status
hermes cron tick

各命令的作用:

  • pause — 保留任务但停止调度
  • resume — 重新启用任务并计算下一次未来运行时间
  • run — 在下一次调度器触发时触发任务
  • remove — 完全删除任务

工作原理

Cron 执行由网关守护进程处理。 网关每 60 秒触发一次调度器,在隔离的 Agent 会话中运行所有到期任务。

hermes gateway install # Install as a user service
sudo hermes gateway install --system # Linux: boot-time system service for servers
hermes gateway # Or run in foreground

hermes cron list
hermes cron status

网关调度器行为

每次触发时,Hermes 会:

  1. ~/.hermes/cron/jobs.json 加载任务
  2. next_run_at 与当前时间对比
  3. 为每个到期任务启动全新的 AIAgent 会话
  4. 可选地将一个或多个附加技能注入该全新会话
  5. 运行提示直到完成
  6. 传递最终响应
  7. 更新运行元数据和下一次计划时间

~/.hermes/cron/.tick.lock 处的文件锁可防止重叠的调度器触发重复运行同一批任务。

传递选项

调度任务时,你指定输出的去向:

选项描述示例
"origin"回到任务创建的地方消息平台上的默认值
"local"仅保存到本地文件(~/.hermes/cron/output/CLI 上的默认值
"telegram"Telegram 主频道使用 TELEGRAM_HOME_CHANNEL
"telegram:123456"按 ID 指定特定 Telegram 聊天直接传递
"telegram:-100123:17585"特定 Telegram 话题chat_id:thread_id 格式
"discord"Discord 主频道使用 DISCORD_HOME_CHANNEL
"discord:#engineering"按名称指定特定 Discord 频道按频道名
"slack"Slack 主频道
"whatsapp"WhatsApp 主
"signal"Signal
"matrix"Matrix 主房间
"mattermost"Mattermost 主频道
"email"电子邮件
"sms"通过 Twilio 发送短信
"homeassistant"Home Assistant
"dingtalk"钉钉
"feishu"飞书/Lark
"wecom"企业微信
"weixin"微信
"bluebubbles"BlueBubbles(iMessage)
"qqbot"QQ 机器人(腾讯 QQ)

Agent 的最终响应会自动传递。你不需要在 cron 提示中调用 send_message

响应包装

默认情况下,传递的 cron 输出会用头部和尾部包裹,以便接收者知道它来自定时任务:

Cronjob Response: Morning feeds
-------------

<agent output here>

Note: The agent cannot see this message, and therefore cannot respond to it.

要不带包装地传递原始 Agent 输出,将 cron.wrap_response 设置为 false

# ~/.hermes/config.yaml
cron:
wrap_response: false

静默抑制

如果 Agent 的最终响应以 [SILENT] 开头,则完全抑制传递。输出仍会保存到本地以供审计(在 ~/.hermes/cron/output/ 中),但不会向传递目标发送任何消息。

这对于仅在出现问题时才应报告的监控任务很有用:

Check if nginx is running. If everything is healthy, respond with only [SILENT].
Otherwise, report the issue.

失败的任务始终传递,忽略 [SILENT] 标记——只有成功的运行可以被静默。

脚本超时

预运行脚本(通过 script 参数附加)默认超时为 120 秒。如果你的脚本需要更长时间——例如,包含用于避免机器人式定时模式的随机延迟——你可以增加此值:

# ~/.hermes/config.yaml
cron:
script_timeout_seconds: 300 # 5 minutes

或设置 HERMES_CRON_SCRIPT_TIMEOUT 环境变量。解析顺序为:环境变量 → config.yaml → 默认 120 秒。

无 Agent 模式(纯脚本任务)

对于不需要 LLM 推理的循环任务——经典看门狗、磁盘/内存告警、心跳、CI 检查——在创建时传入 no_agent=True。调度器按计划运行你的脚本,并直接传递其 stdout,完全跳过 Agent:

hermes cron create "every 5m" \
--no-agent \
--script memory-watchdog.sh \
--deliver telegram \
--name "memory-watchdog"

语义:

  • 脚本 stdout(去除空白)→ 作为消息逐字传递。
  • 空 stdout → 静默触发,不传递。这是看门狗模式:"只在出现问题时才说话"。
  • 非零退出或超时 → 传递错误告警,因此损坏的看门狗不会静默失败。
  • 最后一行 {"wakeAgent": false} → 静默触发(与 LLM 任务使用的相同门)。
  • 无 token,无模型,无提供商回退——任务从不触碰推理层。

.sh / .bash 文件在 /bin/bash 下运行;其他所有文件在当前 Python 解释器(sys.executable)下运行。脚本必须位于 ~/.hermes/scripts/(与预运行脚本门相同的沙箱规则)。

Agent 为你设置这些

cronjob 工具的模式直接向 Hermes 公开 no_agent,因此你可以在聊天中描述一个看门狗,让 Agent 来配置它:

Ping me on Telegram if RAM is over 85%, every 5 minutes.

Hermes 会通过 write_file 将检查脚本写入 ~/.hermes/scripts/,然后调用:

cronjob(action="create", schedule="every 5m",
script="memory-watchdog.sh", no_agent=True,
deliver="telegram", name="memory-watchdog")

当消息内容完全由脚本决定时(看门狗、阈值告警、心跳),Agent 会自动选择 no_agent=True。同一工具也允许 Agent 暂停、恢复、编辑和删除任务——整个生命周期都由聊天驱动,无需任何人触碰 CLI。

参见纯脚本 Cron 任务指南获取工作示例。

使用 context_from 链接任务

Cron 任务在隔离会话中运行,不保留之前运行的记忆。但有时一个任务的输出正是下一个任务所需要的。context_from 参数会在运行时自动建立这种连接——任务 B 的提示在运行时会将任务 A 的最新输出作为上下文前置。

# Job 1: Collect raw data
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",
)

# Job 2: Triage — receives Job 1's output as context
# Get Job 1's ID from: 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="<job1_id>",
name="AI News Triage",
)

# Job 3: Ship — receives Job 2's output as context
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="<job2_id>",
name="AI News Brief",
)

工作原理:

  • 当任务 2 触发时,Hermes 从 ~/.hermes/cron/output/{job1_id}/*.md 读取任务 1 的最近输出
  • 该输出会自动前置到任务 2 的提示
  • 任务 2 不需要硬编码"读取这个文件"——它接收内容作为上下文
  • 链可以是任意长度:任务 1 → 任务 2 → 任务 3 → ...

context_from 接受什么:

格式示例
单个任务 ID(字符串)context_from="a1b2c3d4"
多个任务 ID(列表)context_from=["job_a", "job_b"]

输出按列出的顺序连接。

何时使用:

  • 多阶段流水线(收集 → 过滤 → 格式化 → 传递)
  • 依赖任务,其中第 N 步的工作依赖于第 N-1 步的输出
  • 扇出/扇入模式,一个任务聚合多个任务的结果

提供商恢复

Cron 任务继承你配置的回退提供商和凭证池轮换。如果主 API 密钥受到速率限制或提供商返回错误,cron Agent 可以:

  • 回退到备用提供商,如果你在 config.yaml 中配置了 fallback_providers(或旧版的 fallback_model
  • 为同一提供商轮换到凭证池中的下一个凭证

这意味着在高频率或高峰时段运行的 cron 任务更具弹性——单个受速率限制的密钥不会导致整个运行失败。

调度格式

Agent 的最终响应会自动传递——对于同一目标,你不需要在 cron 提示中包含 send_message。如果 cron 运行调用 send_message 到调度器已经要传递的完全相同的目标,Hermes 会跳过那次重复发送,并告知模型将面向用户的内容放入最终响应中。send_message 仅用于额外或不同的目标。

相对延迟(一次性)

30m → Run once in 30 minutes
2h → Run once in 2 hours
1d → Run once in 1 day

间隔(循环)

every 30m → Every 30 minutes
every 2h → Every 2 hours
every 1d → Every day

Cron 表达式

0 9 * * * → Daily at 9:00 AM
0 9 * * 1-5 → Weekdays at 9:00 AM
0 */6 * * * → Every 6 hours
30 8 1 * * → First of every month at 8:30 AM
0 0 * * 0 → Every Sunday at midnight

ISO 时间戳

2026-03-15T09:00:00 → One-time at March 15, 2026 9:00 AM

重复行为

调度类型默认重复次数行为
一次性(30m、时间戳)1运行一次
间隔(every 2h永久运行直到删除
Cron 表达式永久运行直到删除

你可以覆盖它:

cronjob(
action="create",
prompt="...",
schedule="every 2h",
repeat=5,
)

以编程方式管理任务

面向 Agent 的 API 是单一工具:

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="...")

对于 update,传入 skills=[] 以删除所有附加技能。

Cron 任务可用的工具集

Cron 在没有聊天平台附加的全新 Agent 会话中运行每个任务。默认情况下,cron Agent 获得你在 hermes tools 中为 cron 平台配置的工具集——不是 CLI 默认值,不是所有工具。

hermes tools
# → pick the "cron" platform in the curses UI
# → toggle toolsets on/off just like you would for Telegram/Discord/etc.

通过 cronjob.create 上的 enabled_toolsets 字段(或通过 cronjob.update 在现有任务上)可以进行更细粒度的每任务控制:

cronjob(action="create", name="weekly-news-summary",
schedule="every sunday 9am",
enabled_toolsets=["web", "file"], # just web + file, no terminal/browser/etc.
prompt="Summarize this week's AI news: ...")

当在任务上设置了 enabled_toolsets 时,它优先;否则 hermes tools 中的 cron 平台配置优先;否则 Hermes 回退到内置默认值。这对于成本控制很重要:将 moabrowserdelegation 带入每个小小的"获取新闻"任务会在每次 LLM 调用时膨胀工具模式提示。

完全跳过 Agent:wakeAgent

如果你的 cron 任务附加了预检脚本(通过 script=),脚本可以在运行时决定 Hermes 是否应该调用 Agent。在 stdout 的最后一行输出以下形式:

{"wakeAgent": false}

……cron 就会完全跳过本次触发的 Agent 运行。适用于频繁轮询(每 1-5 分钟),仅在状态实际发生变化时才需要唤醒 LLM——否则你为空内容的 Agent 轮次一遍又一遍地付费。

# pre-check script
import json, sys
latest = fetch_latest_issue_count()
prev = read_state("issue_count")
if latest == prev:
print(json.dumps({"wakeAgent": False})) # skip this tick
sys.exit(0)
write_state("issue_count", latest)
print(json.dumps({"wakeAgent": True, "context": {"new_issues": latest - prev}}))

当省略 wakeAgent 时,默认为 true(照常唤醒 Agent)。

链接任务:context_from

Cron 任务可以通过在 context_from 中列出名称(或 ID)来消费一个或多个其他任务的最新成功输出:

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.")

被引用任务的最近已完成输出会作为上下文注入此次运行的提示之上。每个上游条目必须是有效的任务 ID 或名称(参见 cronjob action="list")。注意:链接读取最近已完成的输出——它不等待在同一触发中运行的上游任务。

任务存储

任务存储在 ~/.hermes/cron/jobs.json。任务运行的输出保存到 ~/.hermes/cron/output/{job_id}/{timestamp}.md

任务可能将 modelprovider 存储为 null。当这些字段被省略时,Hermes 在执行时从全局配置解析它们。它们仅在设置了每任务覆盖时才出现在任务记录中。

存储使用原子文件写入,因此中断的写入不会留下部分写入的任务文件。

自包含的提示仍然重要

重要

Cron 任务在完全全新的 Agent 会话中运行。提示必须包含 Agent 所需的、不由附加技能提供的一切信息。

错误: "Check on that server issue"

正确: "SSH into server 192.168.1.100 as user 'deploy', check if nginx is running with 'systemctl status nginx', and verify https://example.com returns HTTP 200."

安全性

定时任务提示在创建和更新时会扫描提示注入和凭证泄露模式。包含不可见 Unicode 技巧、SSH 后门尝试或明显密钥泄露负载的提示将被阻止。