Agent Buddy Bridge:将 M5StickC 物理按钮连接到 Hermes Agent 的完整方案

目标
实现用 M5StickC Plus 设备的物理按钮(A/B)对 Hermes Agent 的 Dangerous Command 进行审批:
M5StickC Plus (BLE Peripheral, Claude Desktop Buddy firmware)
↕ BLE NUS
BLECentral (ble_central.py)
↓ JSON over BLE
HTTPServer (:8765) ← POST /buddy/state + X-Session-Key
↑ Hermes BuddyPlatformAdapter.send_exec_approval()
(via platform_class: "agent_buddy_bridge.platform.BuddyPlatformAdapter")
M5StickC 按钮 → BLE → BLECentral._handle_notification
↓
HTTPServer.handle_internal_approve() → Hermes /internal/approve
↓ (PR #11812 合并后) 或 Approval Relay (fallback)
resolve_gateway_approval(session_key, choice)
架构组件
1. M5StickC Plus 设备端
状态:已有完整开源固件,直接复用。
- 源码:https://github.com/anthropics/claude-desktop-buddy
- BLE NUS Service UUID: 6e400001-b5a3-f393-e0a9-e50e24dcca9e
- RX Char (写): 6e400002-b5a3-f393-e0a9-e50e24dcca9e
- TX Char (通知): 6e400003-b5a3-f393-e0a9-e50e24dcca9e
- 设备名称格式:Claude-XXXX
2. BLE NUS JSON 协议
Desktop → Device(心跳,每 10s):
{
"total": 3,
"running": 1,
"waiting": 1,
"msg": "approve: Bash",
"entries": ["10:42 git push", "10:41 yarn test"],
"tokens": 184502,
"tokens_today": 31200,
"prompt": {
"id": "req_abc123",
"tool": "Bash",
"hint": "rm -rf /tmp/foo"
}
}
Device → Desktop(按钮决策):
{"cmd": "permission", "id": "req_abc123", "decision": "once"}
{"cmd": "permission", "id": "req_abc123", "decision": "deny"}
3. Hermes BuddyPlatformAdapter(进程内)
位置:agent_buddy_bridge/platform.py
- 通过 platform_class 配置注入 Hermes Gateway
- 实现 send_exec_approval() 推送状态到 BuddyBridge HTTP Server
- 注册 approval_callback 给 AIAgent(PR #11812 特性)
- 关键类:BuddyPlatformAdapter, BuddyApprovalCallback
# ~/.hermes/config.yaml
platforms:
buddy:
enabled: true
platform_class: "agent_buddy_bridge.platform.BuddyPlatformAdapter"
bridge_url: "http://localhost:8765"
hermes_approve_url: "http://localhost:8642"
4. BuddyBridge(独立进程,Mac)
位置:hermes_buddy_bridge/
| 文件 | 职责 |
|---|---|
| `http_server.py` | HTTP Server (:8765),接收 Hermes POST /buddy/state,暴露 /internal/approve 端点 |
| `json_codec.py` | NUS JSON 编解码 |
| `main.py` | 入口,整合所有组件,管理 prompt_id → session_key 映射 |
5. Hermes Plugin(pre_tool_call hook)
位置:hermes_plugin/
- 注册 pre_tool_call hook
- 可选:插件侧 allowlist 直接 approve 某些工具
# ~/.hermes/config.yaml
plugins:
enabled:
- buddy-bridge
HTTP 接口
| 进程 | Port | Method | Path | Direction | Body |
|---|---|---|---|---|---|
| BuddyBridge | 8765 | GET | `/buddy/status` | Hermes → Bridge | — |
| BuddyBridge | 8765 | POST | `/internal/approve` | Bridge → Hermes | `{"session_key","choice"}` |
| Approval Relay | 8766 | POST | `/approve` | Bridge → Hermes | `{"session_key","choice"}` (fallback) |
启动命令
# Terminal 1: BuddyBridge(推荐方式,PR #11812 合并后)
python -m hermes_buddy_bridge.main \
--http-port 8765 \
--hermes-approve-url http://localhost:8642 \
--relay-url http://localhost:8766
# PR #11812 合并前,需启动 Approval Relay 作为 fallback
python -m hermes_buddy_bridge.approval_relay \
--hermes-home ~/.hermes \
--port 8766
Hermes 配置(PR #11812 合并后)
# ~/.hermes/config.yaml
# 1. 启用 BuddyBridge Platform Adapter(via platform_class)
platforms:
buddy:
enabled: true
platform_class: "agent_buddy_bridge.platform.BuddyPlatformAdapter"
bridge_url: "http://localhost:8765"
hermes_approve_url: "http://localhost:8642"
# 2. 启用 BuddyBridge Plugin(pre_tool_call hook)
plugins:
enabled:
- buddy-bridge
# 3. 确保 approvals 配置(默认 telegram 或你的主平台)
approvals:
mode: "telegram" # 或 "buddy"(PR #11812 后支持)
安装 agent-buddy-bridge
# 编辑模式安装,Hermes 可自动发现
cd ~/code/agent-buddy-bridge
pip install -e .
# 或者手动符号链接插件
ln -s ~/code/agent-buddy-bridge/hermes_plugin ~/.hermes/plugins/buddy-bridge
关键文件清单
~/code/agent-buddy-bridge/
├── README.md
├── LICENSE
├── requirements.txt # bleak, aiohttp
├── .gitignore
├── hermes_plugin/ # Hermes 插件(pre_tool_call hook)
│ ├── __init__.py # register() + _on_pre_tool_call()
│ └── plugin.yaml
└── hermes_buddy_bridge/ # BuddyBridge 主程序
├── __init__.py
├── platform.py # BuddyPlatformAdapter + BuddyApprovalCallback (PR #11812)
├── ble_central.py # BLE Central(bleak + CoreBluetooth)
├── json_codec.py # NUS JSON 编解码
├── http_server.py # HTTP Server (:8765,接收 Hermes 状态 + /internal/approve)
├── approval_relay.py # Approval Relay Server (:8766,fallback 方案)
└── main.py # Bridge 入口
PR #11812 关键改动(待合并)
| 改动 | 文件 | 意义 |
|---|---|---|
| `pre_tool_call` → `{"action": "approve"}` | `tools/terminal_tool.py` | 插件可绕过 dangerous command 审批 |
| `"plugin"` approval mode | `tools/approval.py` | 新的审批模式,插件处理审批 |
| `approval_callback` param | `run_agent.py` | AIAgent 接收审批回调参数 |
参考资料
参考资料
- Claude Desktop Buddy 源码:https://github.com/anthropics/claude-desktop-buddy
- BLE NUS 协议:src/ble_bridge.cpp, src/data.h, REFERENCE.md
- PR #11812:https://github.com/NousResearch/hermes-agent/pull/11812
- PR #11816(实现):https://github.com/NousResearch/hermes-agent/pull/11816
- Hermes Plugin 系统:AGENTS.md → Plugin 部分
- bleak 文档:https://bleak.readthedocs.io/
开发日志
| 日期 | 阶段 | 内容 | 产出 |
|---|---|---|---|
| 2026-04-26 | 项目初始化 | 创建 GitHub 仓库 `harryfan1985/agent-buddy-bridge`,编写代码骨架 | `ble_central.py`, `http_server.py`, `http_client.py`, `json_codec.py`, `main.py`, `approval_relay.py` |
| 2026-04-26 | Hermes 调研 | 分析 Hermes 扩展机制(Plugin、Webhook、Platform Adapter),确认 Hermes 没有内置 HTTP 审批回调端点 | 结论:需要 PR #11812 |
| 2026-04-26 | PR #11812 研究 | 详细查看 Issue 和 PR #11816 代码,理解 `platform_class`、`pre_tool_call approve`、`approval_callback` 三大改动 | 明确基于 PR #11812 的新架构 |
| 2026-04-26 | 集成开发 | 基于 PR #11812 设计实现 BuddyPlatformAdapter + Hermes Plugin + 双路径 fallback | `platform.py`, `hermes_plugin/`, `http_server.py` 更新,`main.py` 重构 |
后续任务计划
Phase 1: BuddyBridge 独立测试(不依赖 Hermes)
- [ ] BLE Central 扫描测试
- 测试 bleak 能否在 Mac 上扫描到 M5StickC 设备(设备名 Claude-XXXX)
- 验证 CoreBluetooth 权限
- [ ] BLE 连接测试
- 建立 BLE 连接,启用 NUS TX notify
- 测试 JSON 心跳收发
- [ ] NUS 协议验证
- 对比 Claude Desktop Buddy 固件的 NUS 协议与 json_codec.py 实现是否完全匹配
- 必要时调整编解码格式
Phase 2: Hermes 侧桩代码(不等 PR 合并)
- [ ] 手动注册 BuddyAdapter 到 Platform 枚举
- 修改 gateway/config.py 的 Platform 枚举添加 BUDDY
- 在 gateway/platforms/ 创建 buddy.py
- 绕过 platform_class,直接走 Hermes 内置加载机制
- ⚠️ 违反"不修改 Hermes 核心代码"约束,仅用于原型验证
- [ ] 添加 Hermes /internal/approve 端点
- 在 gateway/platforms/api_server.py 添加 /internal/approve POST 端点
- 调用 resolve_gateway_approval(session_key, choice)
- ⚠️ 同样需要修改 Hermes
Phase 3: 端到端集成(需硬件 + Hermes 改动)
- [ ] 完整审批流程测试
- Hermes 检测 dangerous command → send_exec_approval() → POST /buddy/state
- BuddyBridge 接收 → BLE → M5StickC 显示
- M5StickC 按钮 A/B → BLE 回传 → POST /internal/approve
- Hermes resolve_gateway_approval() → Agent 线程解锁
- [ ] 超时和错误处理
- M5StickC 无响应超时(60s Hermes 默认超时)
- BLE 断线重连
- Hermes 端点不可用 fallback 到 Approval Relay
Phase 4: 硬件与固件
- [ ] M5StickC 固件适配
- 确认 Claude Desktop Buddy 固件是否需要修改
- 验证 NUS 心跳间隔、permission 消息格式兼容性
- [ ] 设备配对流程
- macOS BLE 配对对话框处理
- 首次配对后的自动重连
Phase 5: PR #11812 合并后
- [ ] 移除桩代码
- 删除 Phase 2 的 Hermes 临时修改
- 切换到正式的 platform_class 配置方式
- [ ] 正式部署
- pip install -e . 安装 agent-buddy-bridge
- 配置 ~/.hermes/config.yaml 的 platforms.buddy 和 plugins.buddy-bridge
- 验证 Hermes 自动加载 BuddyPlatformAdapter
阻塞项
| 阻塞 | 依赖 | 解决方案 |
|---|---|---|
| `platform_class` 不存在 | PR #11812 未合并 | Phase 2 桩代码 或 等待 PR 合并 |
| 无法真机测试 BLE | 需要 M5StickC Plus 硬件 | Phase 1 扫描测试验证 bleak 是否正常工作 |
| NUS 协议兼容性未知 | 需要抓包或查看 Claude Buddy 固件源码 | Phase 1 协议验证 |