🤖 Hermes Cron 原生治理
设计原则: 不使用任何需要预定义的自定义目录。所有文件位于 Hermes 原生路径内,cron 脚本全部放入 cron 系统的默认搜索目录。
1. 🏗️ 架构
┌──────────────────────────────────────────────┐
│ cronjob: hermes-cron-master │
│ schedule: 0 1 * * * │
│ script: hermes-cron-master.sh (no_agent) │
│ → 脚本名解析自 ~/.hermes/scripts/ │
└──────────────────┬───────────────────────────┘
│
▼
┌──────────────────────────────────────────────┐
│ ~/.hermes/scripts/hermes-cron-master.sh │
│ Master Orchestrator (bash, 自包含) │
│ ● 内置任务定义(order/timeout/deps) │
│ ● 串行运行各任务脚本 │
│ ● timeout 超时强杀 │
│ ● 捕获 stdout/stderr/退出码/耗时 │
│ ● 生成日报 + stdout 输出摘要 │
└──────┬──────────────────┬────────────────────┘
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ cron-tasks/ │ │ cron-tasks/ │
│ gbrain.sh │ │ sitemap.sh │
└──────────────┘ └──────────────┘
│ │
▼ ▼
┌──────────────────────────────────────────────┐
│ /opt/data/home/.cron-reports/ │
│ cron-YYYY-MM-DD.md(日报存盘) │
│ /opt/data/cron/output/{job_id}/ │
│ (cron 系统原生保留的 stdout 输出) │
└──────────────────────────────────────────────┘
2. 📂 原生目录布局
所有路径在默认 Hermes 安装中已存在或可推导:
| 路径 | 性质 | 说明 |
|---|---|---|
~/.hermes/scripts/hermes-cron-master.sh |
Cron 系统脚本目录 | cron job 的 script 字段以此为查找基 |
~/.hermes/scripts/cron-tasks/ |
任务脚本子目录 | master 脚本内部通过 $(dirname "$0") 推导该位置 |
/opt/data/home/.cron-reports/ |
日报持久化位置 | 位于 home(唯一持久 volume 内),自动创建 |
/opt/data/cron/output/{job_id}/ |
Cron 系统原生输出 | master 脚本的 stdout 自动归档于此 |
/opt/data/cron/jobs.json |
Cron 系统原生定义 | cron job 元数据,Hermes 管理 |
3. ⚙️ Master 编排器设计
3.1 脚本位置约定
Hermes cron 系统的 script 字段解析自 ~/.hermes/scripts/。目录布局:
~/.hermes/scripts/
├── hermes-cron-master.sh # cron job 脚本(入口)
└── cron-tasks/ # 各任务脚本
├── gbrain.sh
└── sitemap.sh
3.2 Master 脚本结构
#!/usr/bin/env bash
set -o pipefail
# ── 路径推导(依赖 cron 系统的可预测执行上下文) ──
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
TASKS_DIR="${SCRIPT_DIR}/cron-tasks"
REPORT_DIR="${HOME}/.cron-reports"
# ── 任务定义(内联,无外部配置文件) ──
TASK_ORDER=(gbrain sitemap)
declare -A TASK_TIMEOUT
TASK_TIMEOUT[gbrain]=600
TASK_TIMEOUT[sitemap]=120
declare -A TASK_DEPS
TASK_DEPS[gbrain]=""
TASK_DEPS[sitemap]=""
# ── 路径推导结束 ──
路径推导为何可靠:
$(dirname "$0")在 cron no_agent 模式下始终解析为~/.hermes/scripts/,因为 cron 系统启动脚本时 CWD 已设定为该目录$HOME在 cron 上下文中有定义,指向/opt/data/homeTASKS_DIR从 master 脚本位置推导,不需硬编码REPORT_DIR使用$HOME(cron 原生值),不需硬编码
3.3 运行时行为
- 按
TASK_ORDER顺序依次运行每个任务脚本(${TASKS_DIR}/${name}.sh) - 每个任务用
timeout包裹,超时退出码 124 - 任务失败后检查
TASK_DEPS,下游依赖任务自动跳过 - 捕获每个任务的 stdout/stderr(各前 2000 字符)、退出码、耗时
- 所有任务结束后,生成统—日报并保存到
$REPORT_DIR/cron-YYYY-MM-DD.md - 输出简短摘要到 stdout → cron 系统自动转发到 Telegram + 归档到
cron/output/
4. ✅ 初始部署
步骤一:编写三个脚本文件
# 创建目录
mkdir -p ~/.hermes/scripts/cron-tasks
# 写入三个文件(略,见后文代码段)
# ~/.hermes/scripts/hermes-cron-master.sh
# ~/.hermes/scripts/cron-tasks/gbrain.sh
# ~/.hermes/scripts/cron-tasks/sitemap.sh
chmod +x ~/.hermes/scripts/hermes-cron-master.sh
chmod +x ~/.hermes/scripts/cron-tasks/*.sh
步骤二:创建 cron job
通过聊天命令创建 cron job:
hermes cron create \
--name hermes-cron-master \
--schedule "0 1 * * *" \
--script hermes-cron-master.sh \
--no-agent \
--deliver origin
或直接请求 Hermes:
[at c] 创建 cron job,每天 1 点运行 hermes-cron-master.sh,no_agent 模式,发回本聊天
步骤三:验证
# 手动触发一次(测试模式,不修改 cron 状态)
bash ~/.hermes/scripts/hermes-cron-master.sh
# 检查日报是否生成
ls -la ~/.cron-reports/
5. ➕ 新增任务
# 1. 创建任务脚本
cat > ~/.hermes/scripts/cron-tasks/your-task.sh <<'SCRIPT'
#!/usr/bin/env bash
set -o pipefail
echo "🚀 你的任务"
# 业务逻辑
SCRIPT
chmod +x ~/.hermes/scripts/cron-tasks/your-task.sh
# 2. 编辑 master 脚本,在任务定义段落追加
# TASK_ORDER+=(your-task)
# TASK_TIMEOUT[your-task]=300
# TASK_DEPS[your-task]=""
# 3. 验证语法
bash -n ~/.hermes/scripts/hermes-cron-master.sh
6. ❌ 移除任务
# 1. 删除任务脚本
rm ~/.hermes/scripts/cron-tasks/your-task.sh
# 2. 从 master 脚本中删除对应的三行数组定义
# 3. 验证
bash -n ~/.hermes/scripts/hermes-cron-master.sh
7. 🔗 依赖关系
# 无依赖
TASK_DEPS[task-a]=""
# 依赖单个任务
TASK_DEPS[task-b]="gbrain"
# 依赖多个任务
TASK_DEPS[task-c]="gbrain,sitemap"
行为: 被依赖的任务失败 → 当前任务自动跳过,日报中标注跳过原因。
8. ⏰ 超时机制
- 每个任务独立配置超时秒数(
TASK_TIMEOUT) - 使用 Linux
timeout命令,超时发送 SIGTERM - 超时退出码 124,标记为 ❌ 失败(超时)
- 不影响后续任务
9. 📊 日报机制
输出路径
| 输出 | 去向 | 说明 |
|---|---|---|
| 简短摘要(stdout) | /opt/data/cron/output/{job_id}/ + Telegram |
cron 系统自动保留 + no_agent 自动转发 |
| 详细日报(Markdown) | /opt/data/home/.cron-reports/cron-YYYY-MM-DD.md |
master 脚本额外写入,用于查阅历史 |
日报格式
🤖 Hermes Cron 日报 — 2026-05-16
═══════════════════════════════════════
📊 总体: 2 任务 | ✅ 1 | ❌ 0 | ⏭️ 1 | ⏱️ 8s
✅ [1] gbrain — 成功 (exit=0, 6s)
⏭️ [2] sitemap — 跳过 (依赖 'gbrain' 未成功)
📄 完整报告: /opt/data/home/.cron-reports/cron-2026-05-16.md
10. 🔧 运维指南
查看 cron job 状态
[at c] 列出目前所有cron
手动触发运行
# 全量
bash ~/.hermes/scripts/hermes-cron-master.sh
# 单任务(利用 master 脚本的 --task 参数)
bash ~/.hermes/scripts/hermes-cron-master.sh --task=sitemap
查看日报
# 最近一份
ls -t ~/.cron-reports/ | head -1 | xargs -I{} cat ~/.cron-reports/{}
# cron 系统输出的原始 stdout
cat /opt/data/cron/output/{job_id}/latest
修改执行时间
[at c] 把 cron 改为每天凌晨 2 点
暂停/恢复 cron
[at c] 暂停 cron hermes-cron-master
[at c] 恢复 cron hermes-cron-master
11. 设计依据
本设计基于对 Hermes 原生行为的以下观察:
| Hermes 原生事实 | 设计推论 |
|---|---|
cron script 解析自 ~/.hermes/scripts/ |
所有 cron 脚本必须在此目录下 |
| cron no_agent 模式运行脚本时 CWD 固定 | $(dirname "$0") 可靠推导脚本位置 |
$HOME 在 cron 上下文始终为 /opt/data/home |
用 $HOME 推导持久化路径,不硬编码 |
无 tasks_home 或 cron_home 原生配置字段 |
用脚本位置推导所有路径,不用 config.yaml 定义 |
cron 系统原生保存 stdout 到 output/{job_id}/ |
摘要输出到 stdout 即可持久化,日报存盘作为补充 |
— 本文档基于 Hermes 原生行为,不依赖于任何自定义目录或预定义配置