- tags
- [BLE, 协议, Anthropic, Claude Code, 参考实现, 嵌入式, 对照样本]
- created
- 2026-04-30
- updated
- 2026-04-30
- sources
- [raw/notes/2026-04-30-claude-desktop-buddy-vs-sentino-iot-sample-architecture.md]
定义¶
Anthropic 2026-04-20 开源的桌宠固件 + BLE 协议规范,让 Claude Cowork / Claude Code 桌面应用通过蓝牙把会话状态、权限请求、token 计数推到 maker 设备。仓库 anthropics/claude-desktop-buddy(公开,Apache-2.0)。核心定位:协议是产品(REFERENCE.md),固件是示范——README 第一段就告诉 maker"Building your own device? You don't need any of the code here"。CONTRIBUTING.md 31 行明说"best contribution is a fork",拒收新功能、拒收新板移植。
参考硬件是 M5StickC Plus(ESP32 + 135×240 TFT + IMU + 两按键 + AXP192 PMU),Arduino 框架 + PlatformIO 编译,全 C++,约 1700 行源码。
→ 这是 Anthropic 第二次执行"协议优先"套路:第一次是 mcp-protocol(MCP 开放协议 + Claude Code 是最佳实现),buddy 是同一套路在 BLE 硬件场景的复刻——开放协议拉生态、自家实现做最佳示范。
七项关键事实¶
1. BLE 协议风格:业界标准 NUS + newline JSON¶
// src/ble_bridge.cpp:13-15
#define NUS_SERVICE_UUID "6e400001-b5a3-f393-e0a9-e50e24dcca9e"
#define NUS_RX_UUID "6e400002-b5a3-f393-e0a9-e50e24dcca9e"
#define NUS_TX_UUID "6e400003-b5a3-f393-e0a9-e50e24dcca9e"
代码注释明说:"every BLE serial example uses these, so existing tools (nRF Connect, bluefy, Web Bluetooth examples) can talk to us without custom UUIDs"——选 NUS 是为了让 maker 能用业界工具直接接,不发明新 UUID。
数据格式:UTF-8 JSON,每条消息以 \n 终止,分包由发送端裸切字节、接收端按 \n 重组。没有应用层帧头/序号/CRC——分包可靠性委托给 BLE 协议栈。
2. 加密:LE Secure Connections + Passkey + Bond,BLE 链路层强制加密¶
// src/ble_bridge.cpp:106-125
txChar->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED);
rxChar->setAccessPermissions(ESP_GATT_PERM_WRITE_ENCRYPTED);
sec->setAuthenticationMode(ESP_LE_AUTH_REQ_SC_MITM_BOND);
sec->setCapability(ESP_IO_CAP_OUT); // DisplayOnly
- TX/RX 特征 + CCCD 全部
ENCRYPTED——未加密链路无法读写 - IO capability = DisplayOnly,桌面是 KeyboardOnly → 走 passkey-entry:设备显示 6 位数字、用户在桌面输入
- 加密由 BLE 协议栈做(AES-CCM),应用层不见明文流
{"cmd":"unpair"}触发bleClearBonds()清 LTK
REFERENCE.md "Security and pairing" 段直接写明动机:"transcript snippets and tool-call hints flow over this link, so an unencrypted device is sniffable by anyone in radio range with a cheap nRF dongle. You should require LE Secure Connections bonding"。
→ 与"应用层加密"路径相反:加密责任完全委托 OS BLE 协议栈,应用层只需 mark 特征 ENCRYPTED + 设 SC_MITM_BOND 模式。
3. 协议消息:Heartbeat snapshot + Turn events + Permission decisions¶
桌面 → 设备的核心消息(REFERENCE.md):
- Heartbeat snapshot(变化时 + 10s keepalive):
{total, running, waiting, msg, entries, tokens, tokens_today, prompt},prompt字段在等审批时出现 - Turn events:
{evt:"turn", role:"assistant", content:[...]},>4KB 序列化丢弃 - One-shot on connect:
{time:[epoch_sec, tz_offset_sec]}+{cmd:"owner", name:"Felix"} - Commands:
{cmd:"status"}/{cmd:"name"}/{cmd:"owner"}/{cmd:"unpair"},每个都有{ack, ok, n}回执
设备 → 桌面:
- Permission decisions:
{cmd:"permission", id:"req_abc123", decision:"once"|"deny"}——id必须匹配prompt.id - Status response:
{ack:"status", ok:true, data:{name, sec, bat, sys, stats}},桌面每秒级轮询填 stats panel
4. Folder push:内容无关的文件流传输¶
desktop: {"cmd":"char_begin","name":"bufo","total":184320}
desktop: {"cmd":"file","path":"manifest.json","size":412}
desktop: {"cmd":"chunk","d":"<base64>"} ← 重复直到文件结束
desktop: {"cmd":"file_end"}
desktop: {"cmd":"char_end"}
每步设备必须 ack 才能继续,设备可以选择"不接受推送"(不 ack char_begin → 桌面 5s 后超时)。<1.8MB 总量,base64 chunk + 顺序协议(设备不需要缓冲整文件)。
→ 协议把"文件 schema"全推给 maker——可以用来推 GIF 角色包、配置 blob、firmware 镜像,协议只规定传输不规定语义。
5. 代码组织:"够用就行" + Species 函数指针表¶
src/main.cpp 1265 行 — loop + UI + 状态机 + 菜单 + 物种切换
src/buddy.cpp ASCII species dispatch + render helpers
src/buddies/ 一文件一物种,七动画函数(sleep/idle/busy/attention/celebrate/dizzy/heart)
src/ble_bridge.cpp 180 行 — Nordic UART service + 安全 + ring buffer
src/character.cpp GIF decode + render
src/data.h 185 行 — JSON parse + 状态机 + demo mode
src/xfer.h folder push receiver
src/stats.h NVS-backed stats / settings / owner / species choice
- 全局变量 30+,模块级
static(_lastLiveMs/_demoMode/_FAKES[]等) - 1265 行单文件 main.cpp 主导
- 18 个 ASCII 物种用函数指针表注册插件
→ 典型 Arduino 工程风格。复杂度刻意保持低,因为它只是 225 行协议规范的一种解读——固件不重要,能被 fork、能被改、能跑就行。
6. 两种字符模式:ASCII 物种 + GIF 角色包¶
- 18 个内置 ASCII 物种 × 7 个状态 = 126 个 ASCII 帧动画,菜单循环切换、NVS 持久化选择
- GIF 模式:用户拖角色包文件夹到桌面 Buddy 窗口的 drop target → 通过 folder push 流到设备 → 设备实时切换到 GIF 模式
- 角色包 =
manifest.json+ 96px 宽 GIFs,单包 <1.8MB tools/prep_character.py工具自动处理 resize
→ 与 Anthropic Claude Code 的"agent skills 嵌套发现"一脉相承:协议把内容形态推给社区(你想给 buddy 用什么角色都行),自家做基础工具。
7. CONTRIBUTING.md:明确的"反贡献"姿态¶
## What we will take
- REFERENCE.md 文档错误修正
- 让参考实现工作不起来的 bug 修复
## What we won't take
- New features, new pets, new screens
- Ports to other boards (fork!)
- Refactors, style changes, dependency bumps
→ 这种"明确拒收"在开源项目里罕见。Anthropic 把 maintenance 成本降到最低("It's not an actively maintained project"),把自由度推到 fork 那边。
与 sentino-iot-sample 对比(同为"BLE + 设备"参考代码的两种哲学)¶
sentino-iot 的 sentino-iot-sample(仓库 sentino-jp/sentino-iot-sample,private;本地目录别名 Conversational-AI-IOT-Sample,因 fork 自 Shengwang-Community/Conversational-AI-IOT-Sample)是另一种完全不同的设计哲学样本。
| 维度 | claude-desktop-buddy | sentino-iot-sample |
|---|---|---|
| stable surface | REFERENCE.md 225 行协议 |
整套链路(BLE → MQTT → Agora RTC → AI Agent) |
| BLE 协议 | Nordic UART Service(业界标准 UUID) | 自定义 GATT service 0x1910(广告用 0xA101,两个不同) |
| 数据格式 | newline-delimited JSON | V1 帧:HEAD(0xFF)+TYPE(0x01)+SN(2)+TOTAL(2)+LEN(2)+C_LEN(1)+DATA(N)+CRC(1) |
| 分包 / 重组 | 发送端裸切,接收端按 \n 重组 |
SN 序号 + CRC 校验 + 整帧丢弃语义,MAX_PAYLOAD 118B,包间 20ms |
| 加密 | LE Secure Connections + Passkey + Bond,特征 ENCRYPTED 强制(AES-CCM 链路层) |
BLE 链路不强加密;应用层声称 AES-ECB/PKCS5Padding,但 web 工具走 plaintext(web-app/js/app.js:370 注释明说 "Skip encryption, send plaintext") |
| 架构 | 端到端两点(桌面 ↔ 设备),无云 | 三段式(Web 浏览器配网 + MQTTS 上云 + Agora RTC 媒体面) |
| 设备身份 | 无(OS BLE bond 即够) | 三元组 UUID/KEY/PID 存 NVS(key d_stn_triple),MQTT password = HMAC-SHA256("uuid={uuid},ts={ts}", key),username 必须 {uuid}\|signMethod=hmacSha256,ts={ts} |
| 代码组织 | main.cpp 1265 行单文件主导,全局变量 30+,"够用就行" |
BK SDK 组件目录式,4 层架构(business / adapter / SDK / BSP),多 PROJECT 切换 |
| 维护姿态 | "best contribution is a fork",明确拒收新功能 | 主动维护 + 4 层重构 + 多客户配置 |
| 加密责任 | OS BLE 协议栈 | 应用层(实际可能放弃) |
| 复杂度推到哪 | OS BLE 协议栈 + maker 自己 fork | 自家 SDK + 云端账号体系 |
→ 这两种哲学没有谁对谁错——它们对应不同的商业目标。
设计哲学:协议优先 vs 平台优先¶
buddy 派:"协议是产品,固件是示例"¶
- 用业界标准(NUS UUID + newline JSON),不发明新协议
REFERENCE.md是契约,固件随便 fork- 加密委托 OS BLE 协议栈
- 没有云、没有身份、没有平台账号
- 商业模式:开放协议拉生态、自家做最佳实现——与 mcp-protocol "标准开放,最佳实现封闭"完全同源。MCP 是 software 协议层的复刻,buddy 是 hardware 协议层的复刻。
sentino-iot 派:"设备是产品,协议是接入手段"¶
- 自定义 GATT + 自定义 V1 帧 + 自定义身份 + 自定义 HMAC
- 整套链路(BLE → MQTT → Agora RTC)才是 stable surface
- 平台中立性弱:协议 / URL / 三元组都打 Sentino 烙印
- 商业模式:卖云服务 / 卖整体方案 ——与 Tuya / 阿里云 IoT / 腾讯云 IoT Explorer 一致
- 复杂度推到自家 SDK + 云端账号体系
两种哲学的根本权衡¶
- 协议优先派省固件复杂度,但需要协议本身有商业价值(Anthropic 模型才是赚钱来源)
- 平台优先派省客户决策(客户拿现成方案接),但必然需要厂商持续维护整链路(FAE / 售后 / 多客户配置)
→ Sentino 选平台优先并非反 best-practice——是商业模式决定的。但 web-app 配网工具可以学 buddy 的"REFERENCE.md 是契约"姿态:把 BLE V1 帧 + 状态码 + bind 双信号确认明确写成对外协议文档(已部分做到 raw/snippets/iot-docs/ref-ble.md),让客户能自己 fork 配网工具。
关键 take-away¶
- Anthropic 两次开放协议路线一致:MCP(2024-11)软件协议 + buddy(2026-04)硬件协议——同一套路在两个层面的复刻。Anthropic 不是协议优先派的发明者,但是当下最强的执行者(mcp-protocol 16 个月生态规模 + buddy 仓库一发布就有第三方 fork 移植到其他 ESP32 板)。
- NUS 选型是"反发明 UUID"姿态的具体形态:很多硬件厂商出于"差异化 / 平台锁定"会发明新 UUID,buddy 用业界事实标准是明确的反向选择,让 maker 能用 nRF Connect / Web Bluetooth Examples 直接 talk。这与 naming-shapes-thinking "命名塑造思维"的反面——选别人已用的名字而不是发明新名字,减少认知负担也减少生态门槛。
- 加密委托 OS BLE 协议栈是工程上更省力的方案:Sentino 生产固件如果要启用 BLE 链路加密,buddy 的 LE Secure Connections + Bond 模型比"应用层 AES-ECB"更省事——OS 帮做了所有事(密钥协商 / 防重放 / 抗 MITM / Bond 持久化)。值得评估。
- 设备身份的有/无是云存在性的直接函数:buddy 没云所以不需要身份,sentino-iot-sample 有云所以必须三元组 + HMAC。这不是工程选择对错,是云存在性的结构性后果。任何想做"开放硬件协议但又有云能力"的厂商需要回答:身份系统怎么设计才不绑死客户。
- CONTRIBUTING.md 的"反贡献"姿态降低 maintenance 成本:开源项目最大的成本通常不是写代码,是审 PR + 拒绝功能 + 兼容老用户。buddy 直接说"fork it",把这部分成本完全推开,是 Anthropic 知道自己不想长期维护一个固件项目的清醒判断。Sentino sentino-iot-sample 没有这种边界(毕竟是客户接入示范),但任何"参考实现"性质的开源项目可以学这条。
在 Sentino 知识库中的位置¶
本页是 sentino-iot 的对照样本页——通过 buddy 的极简协议优先实现,反衬 sentino-iot-sample 的平台优先 + 复杂度推到自家 SDK + 云端的设计姿态。两份代码都是"BLE + 设备"参考代码,但完全相反的哲学,对照阅读对理解 Sentino 自己的设计选择最有帮助。
也是 mcp-protocol "Anthropic 协议优先方法论"在硬件场景的实证——MCP + buddy 是同一套路两次执行,证据级而非个案级判断。
相关概念¶
- sentino-iot — 平台优先派的对照样本(sentino-iot-sample 详见该页)
- ble-provisioning — Sentino 自定义 V1 帧,buddy 是另一种 BLE 协议设计参考(NUS 标准而非自定义帧)
- ble-classic-vs-le — buddy 也属于 BLE-only 形态,系统蓝牙不可见
- mcp-protocol — Anthropic"协议优先"另一案例,与 buddy 同一套路
- iot-platform-fundamentals — 后台 vs IoT 概念对照;buddy 因为没云所以不在这个体系内(反例对照)
- embedded-firmware-layering — Sentino 4 层架构 vs buddy 1265 行单文件,组织复杂度的两端
- naming-shapes-thinking — buddy 选 NUS UUID 是"用别人已有的名字",反向应用