Krolyxon
Commit 54dede1

Branches

Refs →

budctlCLAUDE.md

127 lines · 8.5 KB

budctl

budctl is a Linux CLI (and later a GUI) for controlling wireless earbuds without the vendor app. It has no telemetry, needs no account and never makes a network call.

The first supported device is the realme Buds T310. More devices are added as plugins when the owner gets new earbuds.

Goals

Non-goals

Hard rules

  1. No network code. Nothing in this workspace may open a socket except a Bluetooth socket (RFCOMM for the control link, L2CAP for SDP).
    • The one exception, approved by the owner: the local system D-Bus Unix socket, used through zbus only to talk to BlueZ (org.bluez). budctl opens that socket itself at the fixed path, so an environment variable can never redirect it to TCP.
    • No HTTP clients (reqwest, hyper, ureq, surf, etc.) may appear in the dependency tree, direct or transitive. This is enforced with cargo deny (deny.toml), clippy disallowed-types, and crates/budctl-core/tests/guards.rs.
  2. Clean-room protocol work. Protocol facts (UUIDs, channel numbers, packet framing, command IDs, init sequences) may come from public references, but no other project's source code is ever translated or copied. Write findings into docs/protocol/<device>.md in our own words, then implement from that spec.
    • Committed files do not name or cite those references. Each fact carries an evidence level instead (rule 3).
    • Only the owner can change this rule, by editing it here.
  3. Never guess command bytes. Every command in a device module must trace back to an anchor in its protocol spec, and the spec must give the fact's evidence level (realme_t310.md#sources): seen on a T310, vendor behavior, another model of the family, derived, or verified by us on hardware (ours-YYYY-MM-DD).
    • Put the spec reference in a doc comment on the constant, as /// Spec: realme_t310.md#anchor. tests/guards.rs checks that each anchor exists.
  4. Write commands are the risky part. Read-only commands (battery, current ANC mode, firmware version) get implemented and tested first. Write commands are added one at a time and tested on real hardware before the next one.
  5. No unwrap()/expect()/panic!/indexing outside tests. Bluetooth fails in many ways, and every failure becomes a typed budctl_core::Error. Workspace clippy lints enforce this. unsafe is allowed only in crates/budctl-core/src/transport/socket.rs.

Stack

Device plugin contract

Each module in crates/budctl-core/src/devices/ defines one Device implementation and is listed in devices::REGISTRY. A device declares:

Many realme / OPPO / OnePlus buds share one protocol family. devices/realme_t310/frame.rs and link.rs hold the shared framing and request/reply logic, and contain no T310 tables. If a second device from that family is added, move them to devices/oppo_family/ then, not before.

Connection behavior

CLI shape

budctl list                      # paired devices budctl recognizes
budctl status                    # battery, ANC mode, EQ, game mode
budctl touch                     # touch controls (gesture table) per bud
budctl anc off|on|transparency
budctl eq <preset>
budctl game on|off
budctl --device <MAC> ...        # when more than one supported device is paired
budctl --json status             # machine-readable output for scripts/status bars ("schema": 1)
budctl --debug ...               # hex-dump every frame sent/received (stderr)

Write commands (anc, eq, game, set, bass, touch <side> …, find, custom EQ) are added one at a time, following rule 4. The plan is in docs/protocol/realme_t310.md#roadmap.

Exit codes:

Code Meaning
0 success
1 usage error
2 device not found / not connected
3 channel busy
4 device rejected command or timed out

Roadmap

  1. Spec: docs/protocol/realme_t310.md and docs/protocol/transport.md. Done when they cover transport, framing, handshake and the command table with sources.
  2. Read-only CLI: connect, handshake, list, status, touch. Verify on real buds (checkpoint HW1).
  3. Write commands, one at a time, each verified on hardware before the next:
    1. ANC
    2. ANC levels
    3. game mode
    4. EQ preset
    5. switches (bass boost, 3D sound, wind; dual connection last)
    6. bass level
    7. find
    8. touch controls
    9. hold cycle
    10. fit test (dropped: the T310 acks it but runs no test)
    11. custom EQ
  4. GUI: Quickshell/Aurora via --json, or a Rust GUI on top of the same core.
  5. More devices: as acquired.

Working with Claude

License

GPL-3.0-or-later (LICENSE). Rule 2 forbids copying other projects' code.