Last verified: 2026-05-19
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
cargo build # Debug build
cargo build --release # Release build (LTO enabled)
cargo test # Run all tests
cargo test -p buttplug_server # Run tests for specific crate
cargo +nightly fmt --all -- --check # Check formatting (MUST use nightly)
cargo +nightly fmt # Auto-format (2-space indent, edition 2024)Formatting gotcha: rustfmt.toml uses nightly-only options (imports_layout, empty_item_single_line). Running cargo fmt on the STABLE toolchain silently ignores them and rewrites the entire workspace into the wrong style (~190 files of import-collapsing churn). Always use cargo +nightly fmt. CI checks formatting with nightly.
Linux dependencies: libudev-dev, libusb-1.0-0-dev (for serial/HID support)
WASM build:
wasm-pack build --dev crates/buttplug_server --no-default-features --features wasmButtplug is a framework for interfacing with intimate hardware devices. It uses a client-server architecture where:
- Clients send commands (vibrate, rotate, etc.) through a connector
- Servers translate commands to device-specific protocols and manage hardware
Core Libraries:
buttplug_core- Protocol messages, errors, shared typesbuttplug_client- Client API for connecting to serversbuttplug_server- Server implementation, device management, 115+ device protocolsbuttplug_client_in_process- Integrated client+server for standalone apps
Hardware Managers (under buttplug_server_hwmgr_*):
btleplug- Bluetooth LE (primary, cross-platform)serial,hid- USB serial and HID deviceslovense_dongle,lovense_connect- Lovense-specific (deprecated)xinput- Windows gamepad vibrationwebsocket- WebSocket device forwarderssimulated- In-process simulated devices (no real hardware; lives inbuttplug_server)
Infrastructure:
buttplug_server_device_config- Device configuration databasebuttplug_transport_websocket_tungstenite- WebSocket transportintiface_engine- CLI frontend for running servers
Message-Based Protocol: All client-server communication uses versioned JSON messages (v0-v4). Version negotiation happens during handshake.
Async Architecture: Heavy use of tokio channels (mpsc, broadcast, oneshot) for communication between components. Runtime abstraction supports tokio (production) and WASM.
Device Lifecycle:
Scanning → Identification → Connection → Configuration → Operation
Identification and protocol matching are a single step — a device is identified via its protocol's specifiers.
Server Connection State Machine:
AwaitingHandshake → Connected { client_name, spec_version }
→ Disconnected
→ PingedOut
Trait-Based Device Abstraction:
ButtplugProtocol- Device capability definitionsHardware- Device communication interfaceDeviceCommunicationManager- Hardware discoveryServerDeviceManager- Orchestrates devices and protocols
Output Observability (opt-in):
When emit_output_observations is enabled, the server broadcasts OutputObservation events for every output command sent to a device. The data flows through broadcast channels:
DeviceHandle → ServerDeviceManager → ButtplugServer::output_observation_stream()
→ ButtplugRemoteServer (as ButtplugRemoteServerEvent::OutputObservation)
→ Frontend (as EngineMessage::DeviceOutputObservation)
Each observation carries device_index, feature_index, output_type, and value. Disabled by default to avoid overhead; enable via ServerDeviceManagerBuilder::emit_output_observations(true) or EngineOptions::emit_output_observations.
Simulated Devices (no-hardware testing):
Simulated devices allow testing the full device lifecycle without real hardware. Configuration lives in the user config under simulated_devices, each entry referencing an archetype from simulated.yml (5 archetypes: simulated-1vibe, simulated-2vibe, simulated-rotator, simulated-oscillator, simulated-stroker). Key contracts:
SimulatedSpecifiervariant onProtocolCommunicationSpecifier-- matches devices by archetype nameSimulatedDeviceConfigEntryinUserConfigDefinition-- identifier (archetype name), optional display_name, auto-generated UUID addressDeviceConfigurationManager::available_simulated_archetypes()-- lists valid archetypes with feature summariesServerDeviceManagerBuilder::finish()auto-wiresSimulatedHardwareCommunicationManagerwhen simulated_devices is non-empty- Validation rejects unknown archetypes and duplicate addresses at config build time
SimulatedProtocolis a no-op handler;SimulatedHardwareConnectorcreates in-memory endpoints
GitHub Issues on buttplugio/buttplug via the gh CLI. See docs/agents/issue-tracker.md.
Default label vocabulary (needs-triage, needs-info, ready-for-agent, ready-for-human, wontfix). See docs/agents/triage-labels.md.
Single-context layout — one CONTEXT.md + docs/adr/ at the repo root. See docs/agents/domain.md.
Issues must be filed and discussed before PRs are submitted. Approval from @qdot required. Non-issue PRs will be closed.
Communication: Discord (discord.buttplug.io), Forums (discuss.buttplug.io), GitHub Issues