架构图 · 调用链 · 回调通知逻辑 · 反馈环风险 | 2026-06-25
运行模式
launchd 守护进程,当前 PID 监听 127.0.0.1:8787。核心模块
封装 claude CLI 进程。调用 claude -p … --output-format stream-json,把 stdout 转成 AgentEvent 流。
内存注册表。每个 task 有独立事件缓冲(最多 5000 条)和 waiters 队列,供 claude_wait 长轮询。
持久化 Claude 会话 ID。Task 完成时落盘到 sessions.json,重启后可用 session_id 续传。
任务完成/失败时 fire-and-forget 调用 lark-cli,把结果卡片发到飞书。身份由 notify_target 决定。
完整调用链 (Hermes → CC → 飞书)
mcp_cc_claude_runprompt、cwd、model、session_id(续传用)、notify_target(回调配置)cwd-root 约束 → 生成 task_id (UUID) → 调用 TaskRegistry.start()ClaudeAdapter.run() spawn 子进程claude -p <prompt> --output-format stream-jsontask_idclaude_status / claude_wait 轮询text_delta 累加 → tool_use 更新 currentTool → agent_end 触发完成
→ 状态变 done/error → 通知 Notifier → 释放所有 waiters
anchor_msg_id → +messages-replyreply_in_thread → 加 --reply-in-thread(进话题)+messages-send --chat-id(主流)as_identity 默认 "user"lark_home 决定用哪套 lark-cli 凭据~/.hermes → 爸爸账号发 | ~/.pi → Pi 账号发LARK_BIN 环境变量可覆盖 lark-cli 路径
回传身份决策规则
lark_home: "~/.hermes" + as_identity: "user"lark_home: "~/.pi" + as_identity: "user"as_identity: "bot"(任意 lark_home)lark_home,as_identity 走默认 "user"as_identity: "user" + 监听群 + 主流消息路由规则(notifier.ts 实现顺序)
| 条件 | lark-cli 命令 | 效果 |
|---|---|---|
有 anchor_msg_id + reply_in_thread: true |
+messages-reply --message-id <om_xxx> --reply-in-thread |
进入飞书话题(thread),爸爸在话题内看到 |
有 anchor_msg_id,没有 reply_in_thread |
+messages-reply --message-id <om_xxx> |
Reply 那条消息,进主聊流 |
无 anchor_msg_id,有 chat_id |
+messages-send --chat-id <oc_xxx> |
直接发群主聊流 |
| anchor 和 chat_id 都没有 | — | 静默丢弃,只打 warn log |
🔴 反馈环(自激)风险
reply_in_thread: true — 通知进话题,gateway 不监听 thread 子消息
as_identity: "bot" — gateway 识别为自家 bot 消息,直接 ignore
reply_in_thread=false 时必须配 as_identity="bot",禁止两个都走 user+主聊
MCP 工具接口 (6 个)
| 工具名 | 功能 | 关键参数 |
|---|---|---|
claude_run | 启动异步任务,立即返回 | prompt, cwd, model, session_id, notify_target |
claude_status | 获取任务快照(文本/状态/计数器) | task_id |
claude_wait | 长轮询新事件(chunk-by-chunk) | task_id, from_seq, timeout_ms |
claude_cancel | SIGTERM → SIGKILL 终止任务 | task_id |
claude_list | 列出所有任务(运行中+已结束) | — |
claude_forget | 从内存删除已结束任务 | task_id |
claude_sessions | 列出持久化 session,可用 session_id 续传 | — |