Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 3 additions & 27 deletions .github/workflows/nexting-devices-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@ on:
pull_request:
paths:
- "devices/**"
- "Package.swift"
- ".github/workflows/nexting-devices-ci.yml"
push:
paths:
- "devices/**"
- "Package.swift"
- ".github/workflows/nexting-devices-ci.yml"

permissions:
Expand All @@ -19,38 +17,16 @@ jobs:
javascript-and-boundary:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 22
- run: npm run check
working-directory: devices

swift:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- run: swift test
- run: >-
swiftc -warnings-as-errors -o /tmp/nexting-device-sim
main.swift ../../sdk/swift/Sources/NextingDeviceKit/Protocol.swift
working-directory: devices/examples/macos-device-simulator

kotlin:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 21
- uses: gradle/actions/setup-gradle@v4
- run: gradle test
working-directory: devices/sdk/kotlin

c99:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
- run: cmake -S devices/sdk/c -B build -DNEXTING_DEVICE_SANITIZE=ON
- run: cmake --build build && ctest --test-dir build --output-on-failure
93 changes: 78 additions & 15 deletions .github/workflows/nexting-devices-firmware.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ on:
- "devices/west.yml"
- ".github/workflows/nexting-devices-firmware.yml"
push:
tags:
- "devices-v*"
paths:
- "devices/firmware/**"
- "devices/sdk/c/**"
Expand All @@ -30,11 +32,13 @@ jobs:
include:
- board: nrf52840dk/nrf52840
artifact: nrf52840dk
flash: west flash with the onboard SWD debugger
- board: xiao_ble/nrf52840/sense
artifact: xiao-nrf52840-sense
flash: copy zephyr.uf2 to the XIAO BLE mass-storage bootloader
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- uses: actions/checkout@v7
- uses: actions/setup-python@v7
with:
python-version: "3.12"
- uses: zephyrproject-rtos/action-zephyr-setup@v1
Expand All @@ -44,14 +48,30 @@ jobs:
sdk-version: 0.17.4
west-version: 1.5.0
- run: west build -p always -b ${{ matrix.board }} devices/firmware/zephyr
- uses: actions/upload-artifact@v4
- name: Package self-describing firmware asset
env:
BOARD: ${{ matrix.board }}
ARTIFACT: ${{ matrix.artifact }}
FLASH: ${{ matrix.flash }}
run: |
set -eu
bundle="nexting-device-${ARTIFACT}-${GITHUB_SHA}"
mkdir -p "${bundle}"
for image in build/zephyr/zephyr.elf build/zephyr/zephyr.bin build/zephyr/zephyr.hex build/zephyr/zephyr.uf2; do
if [ -f "${image}" ]; then cp "${image}" "${bundle}/"; fi
done
test -n "$(find "${bundle}" -type f -print -quit)"
(
cd "${bundle}"
sha256sum zephyr.* > SHA256SUMS
printf '{\n "schemaVersion": 1,\n "sourceCommit": "%s",\n "board": "%s",\n "artifact": "%s",\n "flash": "%s",\n "zephyr": "4.3.0",\n "zephyrSdk": "0.17.4",\n "west": "1.5.0",\n "evidence": "Build verified",\n "boardVerified": false\n}\n' \
"${GITHUB_SHA}" "${BOARD}" "${ARTIFACT}" "${FLASH}" > artifact-manifest.json
)
tar -czf "${bundle}.tar.gz" "${bundle}"
- uses: actions/upload-artifact@v7
with:
name: nexting-device-${{ matrix.artifact }}-${{ github.sha }}
path: |
build/zephyr/zephyr.elf
build/zephyr/zephyr.bin
build/zephyr/zephyr.hex
build/zephyr/zephyr.uf2
path: nexting-device-${{ matrix.artifact }}-${{ github.sha }}.tar.gz
if-no-files-found: error

espressif:
Expand All @@ -62,11 +82,13 @@ jobs:
include:
- board: xiao_esp32c3/esp32c3
artifact: xiao-esp32c3
flash: west flash through the Espressif serial bootloader
- board: xiao_esp32s3/esp32s3/procpu
artifact: xiao-esp32s3
flash: west flash through the Espressif serial bootloader
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- uses: actions/checkout@v7
- uses: actions/setup-python@v7
with:
python-version: "3.12"
- uses: zephyrproject-rtos/action-zephyr-setup@v1
Expand All @@ -77,11 +99,52 @@ jobs:
west-version: 1.5.0
- run: west blobs fetch hal_espressif
- run: west build -p always -b ${{ matrix.board }} devices/firmware/zephyr
- uses: actions/upload-artifact@v4
- name: Package self-describing firmware asset
env:
BOARD: ${{ matrix.board }}
ARTIFACT: ${{ matrix.artifact }}
FLASH: ${{ matrix.flash }}
run: |
set -eu
bundle="nexting-device-${ARTIFACT}-${GITHUB_SHA}"
mkdir -p "${bundle}"
for image in build/zephyr/zephyr.elf build/zephyr/zephyr.bin build/zephyr/zephyr.hex; do
if [ -f "${image}" ]; then cp "${image}" "${bundle}/"; fi
done
test -n "$(find "${bundle}" -type f -print -quit)"
(
cd "${bundle}"
sha256sum zephyr.* > SHA256SUMS
printf '{\n "schemaVersion": 1,\n "sourceCommit": "%s",\n "board": "%s",\n "artifact": "%s",\n "flash": "%s",\n "zephyr": "4.3.0",\n "zephyrSdk": "0.17.4",\n "west": "1.5.0",\n "evidence": "Build verified",\n "boardVerified": false\n}\n' \
"${GITHUB_SHA}" "${BOARD}" "${ARTIFACT}" "${FLASH}" > artifact-manifest.json
)
tar -czf "${bundle}.tar.gz" "${bundle}"
- uses: actions/upload-artifact@v7
with:
name: nexting-device-${{ matrix.artifact }}-${{ github.sha }}
path: |
build/zephyr/zephyr.elf
build/zephyr/zephyr.bin
build/zephyr/zephyr.hex
path: nexting-device-${{ matrix.artifact }}-${{ github.sha }}.tar.gz
if-no-files-found: error

release:
if: startsWith(github.ref, 'refs/tags/devices-v')
needs:
- nordic
- espressif
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/download-artifact@v8
with:
pattern: nexting-device-*-${{ github.sha }}
path: release-assets
merge-multiple: true
- name: Publish immutable Experimental release
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release create "${GITHUB_REF_NAME}" release-assets/*.tar.gz \
--repo "${GITHUB_REPOSITORY}" \
--prerelease \
--title "Nexting Devices SDK ${GITHUB_REF_NAME#devices-v}" \
--notes "Public Experimental release. Firmware assets are Build verified with pinned Zephyr 4.3.0, Zephyr SDK 0.17.4, and west 1.5.0. They are not Board verified; inspect each artifact-manifest.json and the repository conformance guide."
28 changes: 0 additions & 28 deletions Package.swift

This file was deleted.

4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -242,8 +242,8 @@ MIT

## Build hardware for Nexting

The open hardware protocol, C99 device SDK, Swift and Kotlin host SDKs,
conformance vectors, and reference firmware live in [`devices/`](devices/).
The open hardware protocol, C99 device SDK, conformance vectors, and reference
firmware live in [`devices/`](devices/).

- Start with the [Devices SDK overview](devices/README.md).
- Read the [wire protocol](devices/SPEC.md).
Expand Down
6 changes: 2 additions & 4 deletions devices/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Do not import files from outside this repository root into public code. The expo

- Interface or behavior change: `docs/foundation-development.md` → `docs/interfaces.md` → `SPEC.md` → vectors → component README.
- New chip or board: `docs/foundation-development.md` → `docs/implementation-tracks.md` → `docs/porting-guide.md` → `docs/hardware-support.md` → `docs/conformance.md`.
- Host product integration: `docs/interfaces.md` → the Host track in `docs/implementation-tracks.md` → `sdk/swift/README.md`. Keep the product adapter thin and private.
- Device integration: `docs/interfaces.md` → the reference-board or MCU track in `docs/implementation-tracks.md`. The official Nexting App owns Host integration.
- Documentation change: update the owning guide and the documentation-contract test in the same commit.

## Protocol change order
Expand All @@ -57,7 +57,6 @@ From the repository root:

```sh
npm run test:reference
swift test --package-path sdk/swift
cmake -S sdk/c -B /tmp/nexting-device-c -DNEXTING_DEVICE_SANITIZE=ON
cmake --build /tmp/nexting-device-c
ctest --test-dir /tmp/nexting-device-c --output-on-failure
Expand All @@ -69,8 +68,7 @@ npm run check:naming
`npm run check` is the final aggregate gate. At the 2026-07-27 snapshot it
passes, including Device Info 0.2, the audited exporter, mandatory bonding,
three-second bond reset, and notification fragmentation. Run
`gradle test` in `sdk/kotlin` as the Android Host SDK gate. Do not weaken or
delete those assertions; a source contract and compiler gate still do not
Do not weaken or delete these assertions; a source contract and compiler gate still do not
replace the real-board checklist.

## Hardware claims
Expand Down
85 changes: 67 additions & 18 deletions devices/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,68 @@ This file records changes to public protocol behavior, shared vectors, SDK surfa

## Unreleased

- Add the first ILX MultiPad case guide with pinned upstream source, public
adapter integration, key mapping, build separation, and SWD/serial evidence
rules.
### Changed

- Reframed the Quickstart around the device–App–Agent architecture and split
the XIAO two-button exercise into a clearly labeled Developer Reference
tutorial.
- Removed custom Apple and Android Host SDKs from the public candidate. The
official Nexting App is the supported Host; this package is device-side.
- Added a machine-readable SDK and public developer-enrollment availability
source for the repository and website.
- Expanded the security model with implemented BLE protection, Host
authorization and freshness checks, minimum disclosure, volatile-state
clearing, and the production identity boundary.

## 0.2.0-experimental.2 — 2026-07-29

This release keeps wire major 1 and adds seven frozen interaction profiles
without changing `approval/1` or `status/1`.

### Added

- Frozen interaction profiles `navigation/1`, `keys/1`, `rotary/1`, `voice/1`,
`text/1`, `usage/1`, and `config/1`.
- Shared valid and hostile vectors plus JSON Schema definitions for all 15 new
messages.
- Strict JavaScript and fixed-buffer C99 implementations of every new message.
- Device Info profile negotiation helpers and device-side profile gating.
- Sequence numbers for replay/out-of-order rejection on navigation, key,
rotary, and push-to-talk input.
- Versioned, atomic configuration results. Invalid configuration leaves the
current device configuration unchanged.

### Changed

- The Codex guide now documents the public protocol boundary and freezes the
fail-closed one-time approval projection into `approval/1`.
- `voice/1` carries control only. Audio capture, permission, and transcription
stay on the Host microphone; audio and transcripts never cross this BLE
profile.

## 0.2.0-experimental.1 — 2026-07-28

This developer-experience release keeps wire major 1 and the `approval/1` and
`status/1` profiles unchanged.

### Added

- A source-first ILX MultiPad USB CDC developer binding that reuses the portable
C99 state machine, preserves the upstream HID and `AA BB xx` commands, and
includes a host-side CMake contract test.
- A GitHub-ready MultiPad guide, conservative Device Info template, CDC smoke
check, and fail-closed STM32 serial-flash preparation script. Physical board
and bootloader evidence remain explicitly pending.
- A public XIAO nRF52840 Quickstart with exact wiring, flashing, expected
output, and an explicit public-App availability gate.
- A rerunnable Zephyr 4.3.0 / west 1.5.0 / SDK 0.17.4 bootstrap with board
aliases, dry-run output, isolated Python dependencies, and actionable errors.
- A reproducible firmware and protocol verification path for the Developer
Reference boards.
- Setup, toolchain, flashing, Bluetooth, Device Info, and public-App
troubleshooting.

### Changed

- Public docs no longer require unpublished product software.
- Claude Code and Codex docs separate published protocol surfaces from roadmap
profiles and from public App availability.
- Website SDK pages have stable shareable routes and keep the official App
boundary explicit.

## 0.2.0-experimental.0 — 2026-07-27

Expand All @@ -27,33 +77,32 @@ profile versions.
### Added

- BLE GATT and newline-delimited `approval/1` protocol for one bounded Allow/Deny request.
- Profile `status/1`: a Host→device downlink that replaces the full rendered state of up to eight anonymous agent-status slots (`idle`, `thinking`, `working`, `complete`, `needs_input`, `error`) with an optional 64-byte label, negotiated through the new optional `statusSlots` Device Info capability field and cleared on disconnect or reboot. Ships with shared `status-v1.json` vectors, a schema def, and JavaScript, Swift, and C implementations. The Zephyr reference does not declare `statusSlots` until per-slot indicator rendering is implemented and board-verified.
- Profile `status/1`: an App→device downlink that replaces the full rendered state of up to eight anonymous agent-status slots (`idle`, `thinking`, `working`, `complete`, `needs_input`, `error`) with an optional 64-byte label, negotiated through the new optional `statusSlots` Device Info capability field and cleared on disconnect or reboot. Ships with shared `status-v1.json` vectors, a schema def, and JavaScript and C implementations. The Zephyr reference does not declare `statusSlots` until per-slot indicator rendering is implemented and board-verified.
- Shared valid and hostile-input vectors plus a JSON Schema.
- Executable JavaScript reference with explicit `protocol`, `framing`, and `relay` entry points.
- `NextingDeviceKit` for Apple hosts and a fixed-buffer portable C99 device core.
- A fixed-buffer portable C99 device core for firmware authors.
- Developer documentation for architecture, security, ports, hardware support, verification, and Agent-driven changes.
- Public foundation blueprint, interface catalog, implementation tracks, conformance evidence rules, and an executable documentation contract for third-party and Agent development.
- Optional, bounded Device Info identity, hardware-capability, Battery Service,
and vendor-extension metadata shared by all language SDKs.
- A Kotlin/JVM protocol SDK for Android hosts.
and vendor-extension metadata shared by the device SDK and protocol reference.
- Explicit iOS and Android enrollment, revocation, and extensible accessory
information-table contracts in the Nexting App.
- A deterministic allowlisted exporter into `Nexting-ai/nexting/devices`,
root SwiftPM integration, SHA-256 manifest, and hostile-input tests.
SHA-256 manifest, and hostile-input tests.

### Security and correctness

- Official JavaScript, Swift, and C decoders share 15 valid and 29 hostile vectors, covering every enum and exact summary boundaries while consistently rejecting duplicate known fields, decoded NUL, lone surrogates, non-canonical integers, excessive nesting, oversized frames, invalid UTF-8, and over-limit summaries.
- Official JavaScript and C decoders share 15 valid and 29 hostile vectors, covering every enum and exact summary boundaries while consistently rejecting duplicate known fields, decoded NUL, lone surrogates, non-canonical integers, excessive nesting, oversized frames, invalid UTF-8, and over-limit summaries.
- Complete-frame byte limits include the newline across all three stream decoders; Device Info accepts safely negotiable larger capacities while rejecting incompatible profiles and control characters.
- Physical approval is restricted to exact two-option, one-time Allow/Deny prompts and resolves only after the Agent accepts the answer.
- Host queues limit bytes and retained frame objects; synchronous enqueue rejection rolls back presentation state, and discovery recovers from malformed or failed Device Info reads.
- The macOS peripheral simulator requires encrypted answer subscription, accepts writes only from the subscribed central, reuses the Swift codec and monotonic TTL, and fragments notifications without interleaving frames.
- The reference protocol tests exercise encrypted-link assumptions, monotonic TTL,
and fragmented notifications without interleaving frames.
- The Zephyr Developer Reference requires bonding, offers a fail-closed three-second physical bond reset, fragments one fixed answer frame through notification completion callbacks with stream resynchronization after an abandoned partial frame, disconnects failed security upgrades, and retries advertising after the connection slot is released.

### Verification status

- JavaScript, Swift, Kotlin, C sanitizer, iOS Simulator, Android build/unit/lint,
private integration, exporter, boundary, and simulator gates pass at the
- JavaScript, C sanitizer, firmware, exporter, and boundary gates pass at the
2026-07-27 snapshot.
- Pinned Zephyr 4.3.0 / SDK 0.17.4 builds produce named artifacts for all four
reference boards. Real-board BLE evidence remains pending; see
Expand Down
Loading