Hermes \+ Claude Code 协作实战: 双 agent 节拍同步 \+ 状态共享设计
一、为什么写这篇
前 3 篇我们搭建好了: 5 张业务表 (Supabase PG)、L2 跨 tick state (Upstash Redis)、免费的 Image/OCR/Job 全家桶 (Upstash 6 件套), 一个真实在跑的个人数据基础设施。
但只跑通基础设施不算"搞定", 你还得让这些基础设施能跨 agent 协作。在我们场景里: Hermes 是 24×7 cron 跑手 (业务数据), Claude Code 是按需短跑分析师 (代码/调试/写报告)。两个 agent 各跑各的, 必须靠一个第三方存储做"通讯介质 + 真实 source of truth"。
这篇文章就是讲我们怎么设计这层 — 用的就是前 3 篇搭的 Supabase PG + Upstash Redis + 飞书 docx。
这是《Hermes 全栈实战系列》的最终篇。第 1 篇的 Supabase + Redis + Upstash 三件套都是 “零件”, 这篇是把零件"组装"成跨 agent 同步的实际工作流。
二、先说结论
我跑通了一个真实运行 1 个月的双 agent 协作协议 v1.0:
-
角色分工: Hermes = cron 24×7 跑手 (负责跑数据); Claude Code = 按需短跑分析师 (负责出报告)
-
通讯介质: Supabase
cron_state表 (单一 source of truth, 不是IM/邮件/webhook) -
原语:
status字段状态机 (todo_for_claude/todo_for_hermes/done/failed) -
命名约定: Hermes 用飞书 doc_token 28 字符, Claude 用前缀
cc_*或fix_* -
协议已知路径: 每天早 7:30 自动跑 Hermes 日报; 老板发"分析一下这段" → Claude 进; 状态写到表里
整个协议的关键不是"agent 多厉害", 是 “双方都遵守一个极简公约” — 这个公约只规定 3 件事: 唯一通讯介质 / 状态机字段 / 命名约定。其它都自由发挥。
三、为什么必须双 agent (而不是单 agent 全包)
我对"独立开发者基础设施" 的真实判断: 7×24 cron 任务跟代码分析任务是两个截然不同的工作节拍:
| 维度 | Hermes (cron 跑手) | Claude Code (分析) |
|---|---|---|
| 触发方式 | schedule 时间触发 | 用户消息触发 |
| 运行时长 | 数秒 - 几分钟 | 数分钟 - 半小时 |
| 工具偏好 | 永 agent 大循环 | 短 session, 多种工具 |
| Token 模式 | 0 token 机械任务首选 | LLM 高单价 |
| 错误模式 | 弱网/限流/服务宕机 | 代码 bug / 找不到资料 |
| 输出 | 写表/推送/生成报告 | 写 docx / 修复 bug |
如果强行把两个塞到同一个 agent, 每次 cron 跑都要付 LLM 钱, 而且 cron 跟用户消息会互相抢占调度。
我最终决定使用: 双 agent + 共享 DB + 状态机。
四、我设计的协议 v1.0 (3 件最简公约)
4.1 单一通讯介质 — cron_state 表
所有 Hermes ↔ Claude 的"消息"都进 Supabase cron_state, 不是 IM 不是邮件不是 webhook。理由:
-
可追溯: 一年后还能跑 SQL 看历史
-
幂等: 同一条 status 写多遍不影响
-
跨 agent 抢跑: 双方都用 SQL UPSERT, 谁先到谁赢
-
状态共享: 不需要"我读你的 inbox" 那种轮询
4.2 状态机字段
status TEXT CHECK (status IN ('todo_for_hermes', 'todo_for_claude', 'done', 'failed'))
4 个状态, 互相转移:
-
todo_for_claude— Hermes 写, 等 Claude 处理 -
todo_for_hermes— Claude 写, 等 Hermes cron 处理 -
done— 谁执行完谁写 -
failed— 失败兜底 (避免静默丢失)
4.3 命名约定
-
Hermes 任务
cron_type ∈ {hermes, manual, test},job_id= 飞书 doc_token 28 字符 -
Claude 任务
cron_type='claude_code',job_id LIKE 'cc\_%'或fix_*
这样 SELECT 出来就知道谁负责, 不用看 status 字段反推。
五、3 个真实场景演示 (我们 7/1 跑过的)
5.1 场景 1: §5.1 bug 修复
症状: 89/91 行 boss_documents.last_modified = 1970-01-21
根因: sync_boss_documents.py:167 老代码 datetime.fromtimestamp(int(v)/1000) 无脑除 1000, Feishu API 实际返回秒级 epoch 时被切成毫秒级 → 1970
修复: 3 格式智能识别 (10 位秒 / 13 位毫秒 / ISO 8601), 解析失败打 [WARN] 不静默
Hermes 写:
INSERT INTO cron_state (job_id, status, output_snippet)
VALUES ('fix_hermes_last_modified_bug', 'todo_for_claude', '89 行 1970-01-21, sync_boss_documents.py:167');
Claude 修完, 写回执:
UPDATE cron_state SET status='done', output_snippet='95/95 行 2025-2026, 0 行 1970' WHERE job_id='fix_hermes_last_modified_bug';
真实跑通, 端到端验证 —— 这是协议最经典的用法。
5.2 场景 2: 协议文档写错章节
症状: Claude 写作的"协作手册 §5.2" 说错了一段: “你每 30 秒一次批量心跳写”
根因 (Hermes 实测): 产线没有 30 秒 heartbeat, hermes_pg_sync_memory.py 每小時 (0 * * * *, cron 35fdd4ab6cc4) 跑一次
Hermes 立即转交, 不争辩:
UPDATE cron_state SET status='todo_for_claude',
output_snippet='§5.2 错误: 30秒 heartbeat 不存在, 实测每小時 cron 35fdd4ab6cc4 跑 PG memory_entries.sync'
WHERE job_id='todo_20260629_revise_collaboration_manual_section_5_2';
Claude 修订完, 写回执: status='done', output=‘已修订 v1.1 §5.2’。
5.3 场景 3: 用户发"分析这段"
我在 Hermes 飞书对话发: “请分析 CSDN 调研报告 boss 偏好”. Hermes 自己不擅长长篇报告, 转交 Claude:
INSERT INTO cron_state (job_id, status, output_snippet)
VALUES ('cc_20260704_boss_blog_preference', 'todo_for_claude',
'fix 报告 boss_preferences 共 26 条, 分类 career/tools/comms/preferences/security/hermes, 老板偏实战系列+软文混合');
Claude 跑完 report, 写: status='done', output_snippet='已完成 v1.0, 输出 6 项偏好 + 7 个待办'.
六、3 个协议外坑 (我踩过的)
6.1 文档占位限制: 2KB
cron_state.output_snippet 限 2KB (手册 §12.4), 超长分析写 markdown 路径。所以协议不能用来"送大文件", 只能"投递 todo 信封"。
6.2 沉默 except = 老板看不见根因
Hermes 跑 Postgres 写失败时, try/except 静默, 后果: 老板问"我没看到日报"才被发现。修法: except Exception as e: print(f"[WARN] {e}", file=sys.stderr), 让 cron output 目录里有失败痕迹。
写入 hermes_mistakes 表 (Supabase, 强约束), 永远: any “失败静默” 都先写 mistakes 表 (severity=low 也记), 这是老板拍板的成长机制。
6.3 同名抢跑
双 agent 都想写 status='done', 后到盖前到。正解: 用 SQL ON CONFLICT (job_id) DO UPDATE + 检查原 status 是不是 todo_for_xxx 才允许升级 done; 防止一边写着 done, 另一边还在处理。
七、双 agent 跟单 agent 优劣对比 (我们的真实数据)
| 维度 | 双 agent (我们) | 单 agent 全包 |
|---|---|---|
| 产线 7×24 cron | ✅ 0 token 机械 | ❌ 每次都要付 LLM |
| 长篇分析 | ✅ 短 session, 多种工具 | 跑长会挤占 cron 调度 |
| Token 成本 | 1.6 元/天 (实测 6/29) | 10-20 元/天 |
| 协作抢跑 | ✅ SQL UPSERT 解决 | ❌ 串行阻塞 |
| 失败兜底 | 各自 status 字段 | 状态机混在一块 |
| 复杂度 | 多一层协议 | 看起来简单实际很坑 |
唯一代价: 多一个协议文档要写。但 一旦跑通, 可永久复用。
八、给"准备搭双 agent"读者的 5 件实跑
8.1 建表 (Hermes 抄这个)
CREATE TABLE cron_state (
job_id TEXT PRIMARY KEY,
status TEXT CHECK (status IN ('todo_for_hermes','todo_for_claude','done','failed')),
output_snippet TEXT,
cron_type TEXT, -- hermes | claude_code | manual | test
updated_at TIMESTAMPTZ DEFAULT NOW()
);
8.2 装 pydantic-settings (跟 Upstash 篇铁律一致)
pip install pydantic-settings==2.14.2
8.3 Hermes 端: 写 job 后等回执
# cron_state 写 todo_for_claude
job_id = f"cc_{date.today():%Y%m%d}_{slug}"
status = upsert_cron_state(job_id, "todo_for_claude", snippet)
# 轮询 status 直到 done / failed
8.4 Claude 端: 扫 cron_state 拿 todo_for_claude
SELECT job_id FROM cron_state
WHERE status='todo_for_claude'
AND cron_type='claude_code'
ORDER BY updated_at;
九、给"只用单 agent"的读者的提示
如果你一个人用单 agent 跑 cron, 不必拆双 agent。协议是"必须多人协作"才划算: 比如:
-
我白天用户消息 (Claude Code)
-
半夜无人, 业务要跑 (Hermes cron)
这种"昼夜分工" 场景, 双 agent 价值最大。
如果你只是日常 Coding + 偶尔跑几行脚本, 用单 agent 就够, 别折腾。
十、给"准备上 Claude Code CLI "的提示
如果你想自己也跑 Claude Code CLI (跟作者一样, 让它跟 Hermes 协作), 我们 7/29 写了个老板专用接入指南 (飞书 docx ):
| 章节 | 内容 | 适用 |
|---|---|---|
| 方案 A | HTTP 远程 MCP + OAuth | Claude Code 在远端 PC |
| 方案 B | stdio 本地 npx + access token | Claude Code 在本地 |
| 鉴权 | pydantic-settings 2.14.2 三重持久化 | 跟 Supabase / Upstash 完全相同 |
警告: 没做凭证持久化的 agent 接入, 80% 都会在第一步翻车 (没 access token 就断了)。
十一、协议 v1.1 我们接下来要加什么
Agent正在跟我拍板 v1.1, 候选改进:
-
优先级字段:
priority INT (1-9), 让 Claude 跑 critical 的 todo 优先 -
死信队列:
failed状态超 30 天自动转dead_letter -
通知通道: Claude 完成时老板飞书主动推一条消息 (取代今天"23:30 统一扫 cron")
-
冲突解决: 同 job_id 同时
todo时, 谁抢到谁 (last-write-wins)
任何 v1.1 变更都先在 cron_state 写 status todo_for_xxx 走协议流程, 不直接动协议文档。
十二、最后
双 agent 协作的精髓, 不是 “agent 多强大”, 是 “双方都遵守同一个极简公约”:
-
一张表 (
cron_state) -
一个状态机 (
todo/done/failed) -
一个命名约定 (
cc_*vs 飞书 doc_token)
更多推荐




所有评论(0)