From aradotso-trending-skills-37
Enables WebUSB (navigator.usb) in Firefox via browser extension and Rust native stub using native messaging for USB device access from web pages. Guides installation, building from source, and manifest setup.
npx claudepluginhub joshuarweaver/cascade-ai-ml-agents-misc-1 --plugin aradotso-trending-skills-37This skill uses the workspace's default tool permissions.
> Skill by [ara.so](https://ara.so) — Daily 2026 Skills collection.
Guides Next.js Cache Components and Partial Prerendering (PPR) with cacheComponents enabled. Implements 'use cache', cacheLife(), cacheTag(), revalidateTag(), static/dynamic optimization, and cache debugging.
Guides building MCP servers enabling LLMs to interact with external services via tools. Covers best practices, TypeScript/Node (MCP SDK), Python (FastMCP).
Generates original PNG/PDF visual art via design philosophy manifestos for posters, graphics, and static designs on user request.
Skill by ara.so — Daily 2026 Skills collection.
awawausb adds WebUSB (navigator.usb) to Firefox via a two-part system: a browser extension (.xpi) and a native stub binary (compiled Rust) that communicates over native messaging.
Web Page (navigator.usb)
↕ WebExtension API
Firefox Extension (extension/)
↕ Native Messaging (stdio, JSON-framed)
Native Stub Binary (native-stub/ — Rust)
↕ OS USB APIs (WinUSB / libusb / IOKit)
USB Device
.xpi from GitHub Releases, open in Firefox.about:debugging → "This Firefox" → "Load Temporary Add-on…" → select extension/manifest.json.Download and unzip the release archive for your platform, then run:
# Linux / macOS
./install.sh
# Windows
install.bat
Supported platforms: macOS x86_64/ARM64, Linux x86_64/aarch64, Windows AMD64/ARM64.
# Clone
git clone https://github.com/ArcaneNibble/awawausb
cd awawausb/native-stub
# Default build (host platform)
cargo build --release
| Platform | Notes |
|---|---|
| macOS | Should "just work"; vendored .tbd files included |
| Linux | Uses musl libc by default for static binaries; glibc builds work but untested |
| Windows | Uses mingw-w64 UCRT (*-windows-gnullvm); MSVC not supported |
# Install mingw-w64, then:
rustup target add x86_64-pc-windows-gnullvm
cargo build --release --target x86_64-pc-windows-gnullvm
After building, tell Firefox where the native stub binary is by placing a JSON manifest file in the correct location.
{
"name": "awawausb_native_stub",
"description": "Allows WebUSB extension to access USB devices",
"path": "/absolute/path/to/awawausb-native-stub",
"type": "stdio",
"allowed_extensions": ["awawausb@arcanenibble.com"]
}
On Windows, path can be just "awawausb-native-stub.exe" (no absolute path required).
macOS
# Global
/Library/Application Support/Mozilla/NativeMessagingHosts/awawausb_native_stub.json
# User-local
~/Library/Application Support/Mozilla/NativeMessagingHosts/awawausb_native_stub.json
Linux
# Global
/usr/lib/mozilla/native-messaging-hosts/awawausb_native_stub.json
/usr/lib64/mozilla/native-messaging-hosts/awawausb_native_stub.json
# User-local
~/.mozilla/native-messaging-hosts/awawausb_native_stub.json
Windows (registry keys)
# Global
HKLM\SOFTWARE\Mozilla\NativeMessagingHosts\awawausb_native_stub
# User-local
HKCU\SOFTWARE\Mozilla\NativeMessagingHosts\awawausb_native_stub
The registry value should be the full path to the manifest .json file.
#!/usr/bin/env bash
STUB_PATH="$(pwd)/native-stub/target/release/awawausb-native-stub"
MANIFEST_DIR="$HOME/.mozilla/native-messaging-hosts"
mkdir -p "$MANIFEST_DIR"
cat > "$MANIFEST_DIR/awawausb_native_stub.json" <<EOF
{
"name": "awawausb_native_stub",
"description": "Allows WebUSB extension to access USB devices",
"path": "$STUB_PATH",
"type": "stdio",
"allowed_extensions": ["awawausb@arcanenibble.com"]
}
EOF
echo "Native manifest written to $MANIFEST_DIR/awawausb_native_stub.json"
#!/usr/bin/env bash
STUB_PATH="$(pwd)/native-stub/target/release/awawausb-native-stub"
MANIFEST_DIR="$HOME/Library/Application Support/Mozilla/NativeMessagingHosts"
mkdir -p "$MANIFEST_DIR"
cat > "$MANIFEST_DIR/awawausb_native_stub.json" <<EOF
{
"name": "awawausb_native_stub",
"description": "Allows WebUSB extension to access USB devices",
"path": "$STUB_PATH",
"type": "stdio",
"allowed_extensions": ["awawausb@arcanenibble.com"]
}
EOF
$stubPath = "C:\path\to\awawausb-native-stub.exe"
$manifestPath = "C:\ProgramData\Mozilla\awawausb_native_stub.json"
$manifest = @{
name = "awawausb_native_stub"
description = "Allows WebUSB extension to access USB devices"
path = $stubPath
type = "stdio"
allowed_extensions = @("awawausb@arcanenibble.com")
} | ConvertTo-Json
Set-Content -Path $manifestPath -Value $manifest
# Register for current user
New-Item -Path "HKCU:\SOFTWARE\Mozilla\NativeMessagingHosts\awawausb_native_stub" -Force
Set-ItemProperty -Path "HKCU:\SOFTWARE\Mozilla\NativeMessagingHosts\awawausb_native_stub" `
-Name "(Default)" -Value $manifestPath
Once installed, navigator.usb is available. Usage is identical to Chrome's WebUSB API:
// Request a device (requires user gesture)
async function connectDevice() {
try {
const device = await navigator.usb.requestDevice({
filters: [
{ vendorId: 0x1234 }, // by vendor
{ vendorId: 0x5678, productId: 0x9abc }, // by vendor+product
{ classCode: 0xff } // by class
]
});
await device.open();
await device.selectConfiguration(1);
await device.claimInterface(0);
// Send data
const data = new Uint8Array([0x01, 0x02, 0x03]);
await device.transferOut(1, data);
// Receive data
const result = await device.transferIn(1, 64);
console.log('Received:', new Uint8Array(result.data.buffer));
await device.close();
} catch (err) {
console.error('USB error:', err);
}
}
// List previously-authorized devices
async function listDevices() {
const devices = await navigator.usb.getDevices();
devices.forEach(d => {
console.log(`${d.manufacturerName} ${d.productName} (${d.vendorId}:${d.productId})`);
});
}
// Watch for connect/disconnect
navigator.usb.addEventListener('connect', e => {
console.log('Device connected:', e.device);
});
navigator.usb.addEventListener('disconnect', e => {
console.log('Device disconnected:', e.device);
});
Note: The WebUSB API is only available on the main page — not in Web Workers.
| OS | Requirement |
|---|---|
| macOS | 10.15+; macOS 12 recommended |
| Windows | Windows 10+ (WinUSB driver required for target device) |
| Linux | Kernel 4.8+; udev daemon; /dev and /sys mounted |
# /etc/udev/rules.d/99-webusb.rules
SUBSYSTEM=="usb", ATTR{idVendor}=="1234", ATTR{idProduct}=="5678", MODE="0666", GROUP="plugdev"
sudo udevadm control --reload-rules
sudo udevadm trigger
If a device isn't listed, it may not use WinUSB. Use Zadig:
⚠️ Switching to WinUSB removes the device from other Windows subsystems (e.g., a printer will no longer appear as a printer).
Click the awawausb toolbar button (under the Extensions icon) → use "List devices" to see all USB devices the extension can see.
Symptoms: extension toolbar shows an error; no devices listed.
"path" in the manifest points to the actual binary.chmod +x /path/to/awawausb-native-stubabout:debugging → inspect extension) for native messaging errors.# Verify udev is running and broadcasting on NETLINK_KOBJECT_UEVENT group 2
udevadm monitor --udev --subsystem-match=usb
# Check kernel version
uname -r # must be >= 4.8
# Install musl target
rustup target add x86_64-unknown-linux-musl
# Install musl toolchain (Debian/Ubuntu)
sudo apt install musl-tools
cargo build --release --target x86_64-unknown-linux-musl
The native manifest uses absolute paths, which breaks when the same home directory is used across machines with different CPU architectures. Workarounds:
execs the correct binary based on uname -m.