硬件生态
开放设备生态
Nexting Devices SDK · 实验版 0.4 · 2026 年 9 月
1. 这是什么
Nexting Devices 是一套开放的设备 SDK。你的硬件只跟 Nexting App 说一门小 BLE 协议——别的一概不管。难的部分 App 和 Nexting 云已经做好了:Claude Code、 Codex、Grok 和 Cursor 会话的翻译与实时转发。设备上不跑任何 Agent 代码、不持有任何凭证, 第一天起就同时支持这些 Agent。
你的设备
任何 BLE 硬件
Nexting App + 云
翻译 · 转发
CC · Codex · Grok · Cursor
你的 Agent
你只做硬件;App、服务器和 Agent 集成都由 Nexting 提供。
2. 设备能做什么
SDK 向设备开放的全部操作,按 Agent 列出。Claude Code、Codex、Grok 与 Cursor 的差异由 App 归一化——设备看到的是同一个界面。总览如下,每一项的协议细节在后面逐条展 开。
| 能力 | 设备操作 | Claude Code · Codex · Grok · Cursor | 状态 |
|---|---|---|---|
| 权限审批 | 显示请求摘要 + 倒计时;回答 Allow / Deny | ✓ | 已发布 · approval/1 |
| Agent 状态显示 | 渲染最多 8 个 Agent 槽位 × 6 种状态,可带标签 | ✓ | 已发布 · status/1 |
| 选项导航 | 在多选项提示里上下移动、确认选择 | 需 Host 适配 | 已发布 · navigation/1 |
| 命令键 | 专用按键:批准、拒绝、fork、发送、切换会话 | 需 Host 适配 | 已发布 · keys/1 |
| 屏幕内容 | 接收对话文本,显示在设备屏幕上 | 需 Host 适配 | 已发布 · text/1 |
| 旋钮控制 | 在 App 下行的选项档位间转动选择 | 需 Host 适配 | 已发布 · rotary/1 |
| 按住说话 | 按住按键,直接对 Agent 说话 | 需 Host 适配 | 已发布 · voice/1 |
| 远程配置 | 键位映射与灯光从 App 下载,免重刷固件 | 需 Host 适配 | 已发布 · config/1 |
| 用量显示 | 显示模型和有界 token/context 计数 | 需 Host 适配 | 已发布 · usage/1 |
2.1 权限审批 · approval/1(已发布)
解决什么:Agent 干到一半需要你拍板——Claude Code 的权限提 示、Codex 的审批、Grok 或 Cursor 的 ACP 权限。App 把这类两选项请求转成一条 present 发给设备,你在设备上按一个键就回答了,不用摸手机。
协议消息(全部四条 + 错误):
| 消息 | 方向 | 字段 | 含义 |
|---|---|---|---|
| present | App → 设备 | id(1–64 字符请求 ID)· sum(≤ 240 字节摘要)· opt 固定 ["allow","deny"] · ttl(1–300000 毫秒倒计时) | 有一条请求待你回答;新的 present 替换旧的 |
| answer | 设备 → App | id · ch("allow" 或 "deny") | 你的回答;只允许回答当前正在显示的那条 |
| resolved | App → 设备 | id · r(answered / expired / cancelled / replaced) | 这条请求终结了;设备立即清掉显示和重试状态 |
| error | 双向 | id · code(bad_message / message_too_large / unsupported_version / unsupported_profile / unknown_request / not_authorized / busy) | 协议级错误;畸形输入静默丢弃也算合法 |
App → 设备 {"v":1,"t":"present","id":"3bb7","sum":"Allow git push?","opt":["allow","deny"],"ttl":30000}
设备 → App {"v":1,"t":"answer","id":"3bb7","ch":"allow"}
App → 设备 {"v":1,"t":"resolved","id":"3bb7","r":"answered"}设备侧规则:只对当前可见的请求作答;发出 answer 后等 resolved,1 秒没等到可原样重发(不允许改答案);同一请求重复回答不会产生 第二次操作(App 按请求 ID 幂等,第一次硬件选择锁定)。同一时刻只有一条待 决请求——超过两个选项的提示(如 Claude Code 的 AskUserQuestion)今天不会 发到设备,留给选项导航能力。
2.2 Agent 状态显示 · status/1(已发布)
解决什么:你同时跑着好几个 Agent,想知道谁在干活、谁卡 住了、谁干完了——不用打开 App。App 把每个 Agent 会话的实时状态推给设备, 设备用 LED、按键背光或屏幕渲染出来。
六种状态(每个槽位必居其一):
| 状态 | 含义 | 典型渲染 |
|---|---|---|
| idle | 会话空闲,没在干活 | 灯灭 / 灰 |
| thinking | 在思考——等模型输出、规划下一步 | 慢闪 / 蓝 |
| working | 在执行——改文件、跑命令 | 常亮 / 绿 |
| complete | 这一轮任务做完了 | 亮一下 / 青 |
| needs_input | 卡住了,在等人回答(权限、提问) | 快闪 / 橙 |
| error | 出错了,需要人看一眼 | 常亮 / 红 |
{"v":1,"t":"status","agents":[{"slot":0,"state":"thinking","label":"fix login bug"}]}设备侧规则:最多 8 个匿名槽位(slot 0–7),每条消息是全量 替换——数组里没出现的槽位就是空的,空数组清空全部;带屏设备可多拿一条 ≤ 64 字节的 label。状态是易失的:断连、重启或重新配对,全部槽 位清空,指示灯绝不显示陈旧状态。App 只向声明了 statusSlots ≥ 1 的设备发这种消息——没声明就收不到,发了也不 算 App 错。
2.3 选项导航 · navigation/1
Claude Code 的 AskUserQuestion、Codex 的多选确认、Cursor 的提问——超过两个选项的提示。 App 下行选项列表和当前高亮位置;设备用上/下键(或摇杆)移动高亮,确认键 提交选择。数据方向:下行 options + cursor,上行 nav_move / nav_select。消息已在 SPEC 与共享向量冻结,序号用于 拒绝重放和乱序。
2.4 命令键 · keys/1
每个物理键映射一条 Agent 命令:批准(等价于审批里按 Allow)、拒绝、fork(从当前会话分叉出 新分支)、发送(把预设文本注入 Agent 输入框并发送)、切换会话(在你多个活跃 Agent 会话间轮换,状态灯跟着换)。 数据方向:下行 keymap,上行 key_event。按键事件 刻意保持通用,最终含义与权限由可信 Host 的 Agent 适配器负责。
2.5 屏幕内容 · text/1
审批摘要只有 240 字节,带屏设备想看更多。文本内容能力让 App 下行更长的对 话片段,设备滚屏阅读。App 侧仍做最小化过滤:只下发必要的对话文本,凭证、 内部标识永远不出门。text 只承载有界纯文本,不承载标记或任意 Agent 载荷。
2.6 旋钮控制 · rotary/1
一只旋转编码器在档位间转动——比如模型档位、审批严格度、会话选择。数据方 向:上行相对增量与按压,下行有界标签和状态。消息为 rotary_map / rotary_event / rotary_press,内部模型或会话 ID 不会发给设备。
2.7 按住说话 · voice/1
按住设备上的键开始说话,松开发送。voice_event 只发开始、停止 与取消,voice_state 下发进度。音频与转写绝不经过这个 Profile; 麦克风权限、采集和识别都留在 Host。
2.8 远程配置 · config/1
键位映射、灯光方案、显示偏好从 App 直接下载到设备,不用重刷固件。配置带 版本号。config 原子应用,config_result 返回已应用 或拒绝;校验失败时旧配置完全不动。
2.9 用量显示 · usage/1
usage 下发有界模型标签与 token/context 计数,usage_clear 清空显示。这些值只用于展示,不是计费权威数据。
2.10 SDK API 一览
| 层 | 实现 | 关键 API |
|---|---|---|
| 设备 SDK | 可移植 C99 | nexting_device_decode / encode · nexting_device_stream_push · nexting_device_status_on_message |
| 参考实现 | JavaScript | 可读的协议实现,钉在共享向量上 |
| 测试向量 | JSON | approval-v1.json · status-v1.json——所有语言逐字节验证 |
3. 怎么集成
3.1 设备侧:C99 设备核
设备固件只需要一个循环:收字节 → 解码 → 渲染;用户操作 → 编码 → 发回。C99 核是固定缓冲区、零堆分配、无操作系统依赖,任何 RTOS 都 能移植:
// 初始化:流解析器 + 状态机
nexting_device_stream_init(&stream, storage, sizeof storage);
nexting_device_status_init(&status);
// ① BLE 收到字节 → 喂给流解析器,每拼出一帧就回调
nexting_device_stream_push(&stream, bytes, len, on_message, ctx);
// ② 回调里:解码 → 按类型渲染(灯 / 屏 / 键)畸形、越界、未知类型的输入由 SDK 直接失败即关闭——你的渲染代码永远看不到 坏数据。Zephyr 参考固件就是这个循环的完整实现,四块板共用。
3.3 授权流程
设备出厂什么都做不了。用户在 Nexting App 里显式授权这台设备 → 建立加密绑 定链路 → 才开始收发任何流量;在 App 里撤销授权,所有流量立即停止。Device Info 在授权前可读,仅供 App 做兼容性发现——读到不等于授权。同一套契约服 务两层身份:Nexting 自有产品(PIN、Ring)携带生产身份;第三方与 DIY 设备 走显式授权,App 里明确标注。
4. 做出第一台设备
1. 选一块板。Nordic nRF52840 DK、Seeed XIAO nRF52840 / Sense、XIAO ESP32C3 或 XIAO ESP32S3——同一个 Zephyr 应用覆盖全部四块,CI 全板 Build verified(Zephyr 4.3.0 / SDK 0.17.4)。
2. 烧录参考固件。开箱即是一块双键审批板。
3. 在 Nexting App 里授权它,回答一次你自己 Agent 的真实 请求。
4.1 MultiPad USB CDC 开发路径
ILX MultiPad 是另一条公开的 STM32F103VET6 USB HID + CDC 开发路径,和上面 的 BLE 参考板不是同一种传输。公开适配层复用 portable C99 SDK,把同一门approval/1 / status/1 协议帧放到 CDC;它不会把 App、Agent 或凭证放进固件,也不会自动获得 Nexting App 的 USB 注册。
| 仓库内容 | 用途 | 当前证据 |
|---|---|---|
| firmware/multipad | 适配层、CMake 测试、Device Info 模板 | 主机测试通过 |
| tools/multipad-cdc-smoke.py | AA BB CC 回显与 present 发送 | 需适配器固件 |
| tools/flash-multipad.sh | 备份与显式确认写入 | 不自动进入 bootloader |
| docs/multipad-usb.md | Module/FPC 识别和 GitHub 教程 | 拆机后补物理证据 |
这台设备能否通过 Type-C 烧录,取决于拆机后是否看到上游所说的串口模块、 SERIAL 开关和 BOOT/RESET 按键;FPC 版本需要 SWD/J-Link。请先备份原始 flash,再使用仓库里的脚本,不要把普通 CDC 端口当成 bootloader。
4.2 第一个案例:ILX MultiPad 接入
这是第一个完整的公开硬件案例。先固定上游iLx11/multi-pad commit,原样构建并保存原版 HEX;再把公开 C99 设备核和 nexting_multipad_adapter 作为一层薄 CDC 适配 接进去。第一个稳定映射故意很小:矩阵键 1 回答 Allow,矩阵键 2 回答 Deny;其他按键与旋钮先保持上游行为,等对应 profile 发布后再扩展。
| 步骤 | 做什么 | 什么算证据 |
|---|---|---|
| 1 · 固定源码 | checkout 上游 78c1ee5… 并保存原版 HEX | 记录原版哈希 |
| 2 · 接入适配层 | JSON CDC 帧先于原有 AA BB xx 分支处理 | C99 + CMake 测试通过 |
| 3 · 选择烧录路径 | Module 只有确认 SERIAL/BOOT/RESET 后走串口;FPC 走 ST-Link/J-Link SWD | 确认 PCB 路径 |
| 4 · 验证一条链路 | present → Allow/Deny → resolved,再测超时与断连 | request ID 一致且状态清空 |
完整的 source-first 顺序、构建分离、引脚证据和回滚规则见公开 GitHub 教程:docs/cases/multipad-first-case.md。上游现成的 leden.hex 不是 Nexting 镜像,不能直接当适配固件 烧录。
4.3 AhaKey X1 BLE 案例
AhaKey X1 是一把量产在售的 BLE vibecoding 键盘——4 个按键、一个审 批拨杆、一条 LED 灯带、一块 OLED,并有语音输入场景。当前公开的 Devices SDK 是 Experimental 0.4,已包含 AhaKey 目录和设备音频 profile。生产 PCM 绑定、目标构建、移动端一致性 收口和实物板测仍待完成。
| X1 硬件 | Nexting 接口 | 行为 |
|---|---|---|
| 按键 F18 / F19 | approval/1 | 批准 / 拒绝当前请求 |
| 按键 F13–F16 + 拨杆 | keys/1 槽位 0–3 和 7 | Host 映射的动作 |
| LED 灯带 | status/1 | Agent 状态灯效 |
| OLED 160×80 | text/1 | 请求与状态文本 |
| 设备麦克风 + 语音键 | device-audio/1 | 设备 PCM → 加密 BLE → App;不借用手机麦克风 |
AhaKey X1 指南说明当前 0.4 契约,以及 AhaKey 文件宣称 Board verified 之前必须具备的证据。
5. 协议参考
BLE 传输
| 角色 | UUID | 属性 | 方向 |
|---|---|---|---|
| Service | 6EADC0DE-0001-4A21-9C5E-1B7F3D9E42A0 | Primary | — |
| Downlink | 6EADC0DE-0002-4A21-9C5E-1B7F3D9E42A0 | Write | App → 设备 |
| Uplink | 6EADC0DE-0003-4A21-9C5E-1B7F3D9E42A0 | Notify | 设备 → App |
| Device Info | 6EADC0DE-0004-4A21-9C5E-1B7F3D9E42A0 | Read | 设备 → App |
Wire 格式
每条消息一个紧凑的 UTF-8 JSON 对象,换行结尾;帧可拆分到多次 BLE 写入与通 知;官方实现帧上限 4096 字节。枚举值小写;字段重复即非法;未知类型、缺字段、 越界一律失败即关闭——丢弃该消息,保留先前状态。
Device Info —— 能力声明
连接时 App 读取设备能渲染什么,只发它消费得了的内容。没有指示灯?不声明 statusSlots,零状态流量。只有一颗 LED?声明 1, 而不是 8。
{
"protocol": "nexting-device",
"spec": "0.1.0-experimental",
"wire": [1],
"profiles": ["approval/1", "status/1", "navigation/1", "keys/1", "rotary/1", "voice/1", "text/1", "usage/1", "config/1"],
"model": "xiao-nrf52840-ref",
"fw": "0.1.0",
"max_message_bytes": 4096,
"max_summary_bytes": 240,
"statusSlots": 4
}6. 基本规则
默认拒绝。设备在用户在 App 里显式授权之前什么都不做;撤销 即停止所有流量。
失败即关闭。畸形、陈旧、超大或未授权的输入永远不会批准任 何事,也永远不会弄花显示。
状态易失。审批与状态只活在 RAM,断连、重启或重新配对即清 空。
诚实声明能力。只声明硬件真正渲染得了的。
7. 源码
协议规范、共享测试向量、SDK、参考固件与完整开发者指南——快速上手、接口目 录、实现路线、一致性等级、用例集: