一、为什么写这篇前 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 按需短跑分析师 (负责出报告)通讯介质: Supabasecron_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 的消息都进 Supabasecron_state,不是IM 不是邮件不是 webhook。理由:可追溯: 一年后还能跑 SQL 看历史幂等: 同一条 status 写多遍不影响跨 agent 抢跑: 双方都用 SQL UPSERT, 谁先到谁赢状态共享: 不需要我读你的 inbox 那种轮询4.2 状态机字段statusTEXTCHECK(statusIN(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_typeclaude_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 写:INSERTINTOcron_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 修完, 写回执:UPDATEcron_stateSETstatusdone,output_snippet95/95 行 2025-2026, 0 行 1970WHEREjob_idfix_hermes_last_modified_bug;真实跑通, 端到端验证—— 这是协议最经典的用法。5.2 场景 2: 协议文档写错章节症状: Claude 写作的协作手册 §5.2 说错了一段: “你每 30 秒一次批量心跳写”根因(Hermes 实测): 产线没有30 秒 heartbeat,hermes_pg_sync_memory.py每小時 (0 * * * *, cron35fdd4ab6cc4) 跑一次Hermes 立即转交, 不争辩:UPDATEcron_stateSETstatustodo_for_claude,output_snippet§5.2 错误: 30秒 heartbeat 不存在, 实测每小時 cron 35fdd4ab6cc4 跑 PG memory_entries.syncWHEREjob_idtodo_20260629_revise_collaboration_manual_section_5_2;Claude 修订完, 写回执:statusdone, output‘已修订 v1.1 §5.2’。5.3 场景 3: 用户发分析这段我在 Hermes 飞书对话发: “请分析 CSDN 调研报告 boss 偏好”. Hermes 自己不擅长长篇报告, 转交 Claude:INSERTINTOcron_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, 写:statusdone, output_snippet已完成 v1.0, 输出 6 项偏好 7 个待办.六、3 个协议外坑 (我踩过的)6.1 文档占位限制: 2KBcron_state.output_snippet限 2KB (手册 §12.4), 超长分析写 markdown 路径。所以协议不能用来送大文件, 只能投递 todo 信封。6.2 沉默 except 老板看不见根因Hermes 跑 Postgres 写失败时, try/except 静默, 后果: 老板问我没看到日报才被发现。修法:except Exception as e: print(f[WARN] {e}, filesys.stderr), 让 cron output 目录里有失败痕迹。写入hermes_mistakes表 (Supabase, 强约束),永远: any “失败静默” 都先写 mistakes 表 (severitylow 也记), 这是老板拍板的成长机制。6.3 同名抢跑双 agent 都想写statusdone, 后到盖前到。正解: 用 SQLON 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 抄这个)CREATETABLEcron_state(job_idTEXTPRIMARYKEY,statusTEXTCHECK(statusIN(todo_for_hermes,todo_for_claude,done,failed)),output_snippetTEXT,cron_typeTEXT,-- hermes | claude_code | manual | testupdated_at TIMESTAMPTZDEFAULTNOW());8.2 装 pydantic-settings (跟 Upstash 篇铁律一致)pipinstallpydantic-settings2.14.28.3 Hermes 端: 写 job 后等回执# cron_state 写 todo_for_claudejob_idfcc_{date.today():%Y%m%d}_{slug}statusupsert_cron_state(job_id,todo_for_claude,snippet)# 轮询 status 直到 done / failed8.4 Claude 端: 扫 cron_state 拿 todo_for_claudeSELECT job_id FROM cron_state WHERE statustodo_for_claudeAND cron_typeclaude_codeORDER BY updated_at;九、给只用单 agent的读者的提示如果你一个人用单 agent 跑 cron, 不必拆双 agent。协议是必须多人协作才划算: 比如:我白天用户消息 (Claude Code)半夜无人, 业务要跑 (Hermes cron)这种昼夜分工 场景, 双 agent 价值最大。如果你只是日常 Coding 偶尔跑几行脚本, 用单 agent 就够, 别折腾。十、给准备上 Claude Code CLI 的提示如果你想自己也跑 Claude Code CLI (跟作者一样, 让它跟 Hermes 协作), 我们 7/29 写了个老板专用接入指南 (飞书 docx ):章节内容适用方案 AHTTP 远程 MCP OAuthClaude Code 在远端 PC方案 Bstdio 本地 npx access tokenClaude 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写 statustodo_for_xxx走协议流程,不直接动协议文档。十二、最后双 agent 协作的精髓, 不是 “agent 多强大”, 是 “双方都遵守同一个极简公约”:一张表 (cron_state)一个状态机 (todo/done/failed)一个命名约定 (cc_*vs 飞书 doc_token)