A cross-platform Rust engineering core with CLI and Tauri/Svelte frontends for discovering BLE and USB HID endpoints, opening independent sessions, exchanging raw protocol messages, observing asynchronous events, and running recipes. All product knowledge is loaded from external YAML bundles.
V1 targets Linux, Windows, and macOS. BLE GATT and USB HID remain independent transport endpoints. The synthetic adapter provides a runnable, tested vertical slice.
cargo test --workspace
cargo run -p workbench-cli -- --config examples/synthetic-config scan --all
cargo run -p workbench-cli -- --config examples/synthetic-config scan --all --transport ble
cargo run -p workbench-cli -- --config examples/synthetic-config scan --all --transport usb
cargo run -p workbench-cli -- --config examples/synthetic-config protocol search star
cargo run -p workbench-cli -- --config examples/synthetic-config recipe list
cargo run -p workbench-cli -- --config examples/synthetic-config --output jsonl \
send --profile aurora-widget 0xF00D 0x0101 "01 00 2A"
cargo run -p workbench-cli -- --config examples/synthetic-config \
recipe run overlapping-stars --profile aurora-widget
cargo run -p workbench-cli -- --config examples/synthetic-config \
console --profile aurora-widgetTo validate a BLE link without assuming any protocol UUIDs or packet framing, copy an endpoint ID from the diagnostic BLE scan and inspect its GATT surface. The CLI connects, discovers services, reports characteristic properties and descriptors, and then disconnects.
cargo run -p workbench-cli -- --config examples/synthetic-config \
gatt inspect --endpoint "<endpoint-id>"
cargo run -p workbench-cli -- --output json gatt read --endpoint "<endpoint-id>" \
--service "<service-uuid>" --characteristic "<characteristic-uuid>"
cargo run -p workbench-cli -- --output json gatt listen --endpoint "<endpoint-id>" \
--service "<service-uuid>" --characteristic "<characteristic-uuid>" --listen-ms 10000
cargo run -p workbench-cli -- --config "<external-bundle>" --output json \
gatt request --endpoint "<endpoint-id>" --profile "<profile-id>" "<command>" "<body>"gatt read and gatt listen act only on UUIDs supplied explicitly at runtime. Listening performs
a bounded subscribe, records notifications, unsubscribes, and disconnects. These diagnostics do not
assign protocol roles or send initialization or protocol packets.
gatt request is the configuration-selected write diagnostic. It accepts only a profile whose codec
is packet_u16be_pair and whose BLE connection map explicitly provides vendor_id,
service_uuid, write_characteristic, notify_characteristic, and write_type (with_response
or without_response). It subscribes before writing, sends the two configured/supplied big-endian
16-bit values followed by the opaque body, collects raw notifications for a bounded interval, and
disconnects. The workbench does not infer any characteristic role from UUID order or properties.
BLE scans default to 12 seconds. The GUI displays and updates BLE endpoints as advertisement events
arrive, retains existing results while rescanning, shows the remaining scan time, and can stop a
scan without discarding devices already found. Endpoint actions acknowledge pending work immediately
and can begin from a live result before the scan window ends. Use --scan-ms 20000 or the GUI's BLE
scan selector for devices with slower or intermittent advertisements.
Pairing is an explicit, separate operation. Check the current platform pairing state first, then
request pairing only for the intended endpoint. On Linux, the basic operation asks BlueZ to pair and
reports its paired/bonded state. For dual-mode devices it requires BlueZ's experimental D-Bus
properties to be enabled and sets the selected device's PreferredBearer to le while disconnected;
any required interaction is handled by the registered desktop or system Bluetooth agent. Windows may
present its own pairing UI. The workbench reports the platform result and never unpairs a device
automatically.
See Linux Bluetooth pairing for BlueZ configuration, dual-mode bearer selection, and reconnect troubleshooting.
An external BLE profile may declare security.bonding: required and select basic, confirm_only,
or encryption under security.windows.pairing_mode. The GUI uses that policy for its normal bonding
action; explicit CLI modes and GUI diagnostic fallbacks remain available for investigation. An
unrelated Bluetooth Classic bond must not be assumed to provide a BLE bond through cross-transport derivation.
The Windows pairing-mode selection does not apply on Linux, where normal profile-driven bonding uses
BlueZ's basic pairing operation.
cargo run -p workbench-cli -- ble pairing --endpoint "<endpoint-id>"
cargo run -p workbench-cli -- ble pair --endpoint "<endpoint-id>"
cargo run -p workbench-cli -- ble pair --endpoint "<endpoint-id>" --mode confirm-only
cargo run -p workbench-cli -- ble pair --endpoint "<endpoint-id>" --mode encryptionIf Windows returns failed while canPair remains true, confirm that the target is in its pairing
mode and compare with pairing from Windows Settings. Basic pairing delegates any required
interaction to Windows. The explicit confirm-only diagnostic accepts only a Windows ConfirmOnly
request, while encryption requests an encrypted bond without inventing a PIN or passkey. The
workbench does not guess any pairing ceremony data. See
Windows Bluetooth bonding for configuration and platform behavior.
The CLI supports text, json, and jsonl output. Scans include generic read-only BLE and HID enumeration; --all exposes unrecognized interfaces for diagnostics. BLE endpoints remain separate GATT connections. demo runs a synthetic asynchronous session and is useful without hardware.
cargo run -p workbench-cli -- --config examples/synthetic-config --output jsonl demoSee architecture.md for boundaries and unresolved hardware integration work. The GUI lives under apps/gui; run npm install && npm run tauri dev there. Its Tauri backend loads the synthetic bundle, owns discovery and sessions, and forwards authoritative history events to Svelte.
The GUI also supports standalone, external recipe books. A book can hold multiple described command sequences, can be created before choosing a file, and is opened or saved with native cross-platform dialogs. The blank recipe selection remains a transient free-form command editor.
After a user loads an external bundle successfully, the GUI remembers its canonical directory in a versioned state file under the platform application-data directory and restores it on the next run.
The current Tauri configuration produces a standalone x64 workbench-gui.exe, not an installer.
Copy that executable to the target Windows 10 or 11 machine; Rust, Node.js, and the source tree are
not required there. The application uses the system Microsoft Edge WebView2 Runtime. It is included
with Windows 11 and most updated Windows 10 installations; install the
Evergreen WebView2 Runtime if the window
cannot initialize on an older, LTSC, Server, or stripped-down system.
Keep product configuration outside the application directory. In the endpoint browser, use
Browse… to select the external folder containing bundle.yaml; a successful selection is loaded
and remembered in the current user's platform application-data directory. Recipe books are optional
and remain separate external YAML files. BLE requires a working Windows Bluetooth adapter and its
normal vendor driver. USB HID uses the standard Windows HID stack and does
not require replacing the device driver with WinUSB or libusb.
Release executables are currently unsigned, so Windows SmartScreen may identify a newly copied build as unrecognized. Code-sign releases before distributing them beyond trusted test machines.
Licensed under 0BSD. See LICENSE.