The lightweight G HUB & Options+ alternative

It's a mouse,
not a platform.

A nibble is half a byte. This one is an under-1-MB download that runs your Logitech mouse — native settings window, menu bar, or terminal. No daemon, no account, no telemetry.

Get Nibble on GitHub
Under 1 MB Zero dependencies Open source · MIT macOS today · Windows beta · Linux soon
zsh — nibble
$ nibble status
device    G502 LIGHTSPEED · receiver 046D:C539
protocol  HID++ 4.2 · link ok
battery   63% · 3.92 V · charging
dpi       1600
rate      1000 Hz
mode      host

$ nibble dpi 3200
dpi 3200 ✓  read back from device

$ nibble rate
rate 1000 Hz (supported: 1000/500/250/125 Hz)

$ nibble battery
63% 3.92V charging

$ nibble doctor
Nibble doctor v1.8.1

  input-monitoring  granted
  transports        receiver 046D:C539
  device            G502 LIGHTSPEED · HID++ 4.2
  battery           63% charging (0x1001)
  remap-capable     0x8110 MouseButtonSpy
  config            ~/.config/nibble.json · 2 maps · profile Gaming
  remap-engine      running · 2 mapping(s) · 0x8110 spy
  menubar           running (remap engine host)
login-startup     on
login-replay      installed
low-battery-alert below 20%

 All good.
$ 
The pitch, to scale

G HUB is a 4 GB install. Nibble is under 1 MB.

G HUB
4 GB
Options+
~800 MB
Nibble
543 KB

A 543 KB download as of v1.8.1 (universal app; ~750 KB of binary per architecture). Drawn to scale that bar would be ~0.1 px wide — we rounded up so you can see it.

Why Nibble

Small, native, and honest.

Under 1 MB. Zero dependencies.

One static binary built with make. No runtime, no installer, no framework — nothing to keep updated.

Nothing lives in the background.

No daemon, no telemetry, no account. Nibble runs, applies, exits. The opt-in menu bar is the only resident mode.

Remap any button. No G HUB.

The button list is read from the device itself, so any Logitech mouse just works. Bind a keystroke, a macro, or a system action — and switch whole sets with profiles. Quit the menu bar and factory behavior is back instantly.

Verified writes. Real volts.

DPI 50–25600 and 125–1000 Hz writes are read back from the device and confirmed; battery is honest millivolts through a LiPo curve — and rgb off buys the hours back.

Speaks HID++ 4.2, natively.

Raw protocol through IOKit over a Lightspeed / Unifying receiver, a USB cable, or Bluetooth — the same language G HUB speaks.

A real window, not a web view.

Hand-written AppKit: a settings window with DPI, report rate, lighting and a button editor, plus a menu bar that draws the battery inside the mouse icon. No Electron, no SwiftUI runtime.

It tells you why it stopped.

Permissions and engine state are on screen, each failure next to the button that fixes it — and nibble doctor prints the same checks with a concrete next step. Every read command speaks --json, for scripts and agents.

Nothing to take on faith.

MIT, one directory of Swift, no dependencies to audit. 244 checks cover the protocol framing, parsing and config merges — clone it and make test — and a mutation audit proves they bite.

Set once. Comes back at login.

Your config is a tiny JSON. One switch registers the menu bar as a login item so remaps survive a reboot; another re-applies DPI, rate and lighting through a one-shot launchd agent that exits immediately.

The CLI

One binary. Every control.

CommandEffect
nibble statusOverview: link, battery, DPI, report rate, feature flags
nibble batteryOne line, script-friendly: 50% 3.85V charging
nibble doctorDiagnose permissions, device, config, engine — each failure prints its fix
nibble dumpEnumerate all HID++ features (diagnostic)
nibble dpi [50-25600]Get / set DPI, verified by read-back
nibble rate [125|250|500|1000]Get / set report rate in Hz
nibble rgb off|showLights off (power saving) / list zones and effects
nibble mode [host|onboard]Get / set control-mode flag
nibble wheel free|ratchet [threshold N]SmartShift wheel mode — MX-series only (untested)
nibble onboard info|backupOnboard memory info / read-only full dump
nibble config init|showCreate from current state / print ~/.config/nibble.json
nibble applyApply the config file (runtime writes)
nibble replay install|uninstallAuto-apply DPI / rate / lighting at login via a one-shot launchd agent
nibble startup [on|off]Start the menu bar at login, so button remaps survive a reboot
nibble buttonsEnumerate programmable buttons (0x1b04 MX-series / 0x8110 G-series)
nibble spy [seconds]Live button-event monitor, G-series diagnostic
nibble remapInteractive remap: press a button → assign keystroke / macro / system action / disable
nibble profile [list|use|new|copy|rename|delete]Switch between whole sets of button mappings
nibble menubarInteractive menu bar: battery + DPI/rate/RGB; hosts the remap engine (~15 MB, opt-in)
Nibble.appMenu bar launched from Finder — comes with the cask (or make install-app); adds low-battery notifications and the login item
nibble versionPrint the version (--json on this one too)
nibble uiNative settings window: General (DPI, rate, lighting, login, alerts, health) + Buttons (remap table with profiles)
Debug: NIBBLE_DEBUG=1 · Exit codes: 0 ok · 1 no awake device / not applied · 2 transport error · 64 usage · --json on every read command
Get started

Three lines to a configured mouse.

macOS 13+  ✓ shipping Windows  β beta Linux · coming soon

The Windows port is beta: the CLI and tray are built, pass the same protocol vectors as the macOS binary, and CI exercises every no-device path on real Windows — but none of it has touched a real mouse yet. Hardware validation is still to come; the release and Scoop package ship only after it passes. Follow along on GitHub. Linux comes after — the protocol core is OS-free, so a port is one transport file (hidraw).

Install

macOS 13+, no toolchain needed — the cask ships a prebuilt universal app with the CLI included. Logitech mouse on a Lightspeed / Unifying receiver, over a USB cable, or paired directly over Bluetooth. Tested on G502 LIGHTSPEED via receiver; the Bluetooth-direct path follows the HID++ spec but is not yet verified on hardware.

brew tap ben0128/nibble
brew trust ben0128/nibble
brew install --cask nibble

Or build from source (Command Line Tools are enough):

git clone https://github.com/ben0128/nibble && cd nibble
make
./nibble status

The cask already puts Nibble.app in /Applications. Building from source instead? make install-app does the same — menu bar launched from Finder, low-battery notifications, “start at login”.

First run: grant Input Monitoring — System Settings → Privacy & Security → Input Monitoring → enable Nibble (or your terminal when using the CLI), then re-run. Error 0xE00002E2 just means the permission is missing; no restart needed. Button remapping additionally needs Accessibility — the engine asks once and retries on its own, so remaps start working seconds after you grant it.

~/.config/nibble.json

Create it from your current state with nibble config init. Omitted keys are left untouched.

{
  "dpi": 1600,
  "reportRateHz": 1000,
  "rgb": "off",
  "lowBatteryPercent": 20,
  "activeProfile": "Gaming",
  "buttonProfiles": {
    "Gaming": {
      "G502 LIGHTSPEED Wireless Gaming Mouse": {
        "G7": { "type": "keys",   "keys": "cmd+space" },
        "G8": { "type": "macro",  "keys": "cmd+c, 150ms, cmd+v" },
        "G9": { "type": "system", "action": "mission-control" }
      }
    }
  }
}

Also available: lowBatteryNotify false to silence alerts, and wheelMode "free" / "ratchet" with wheelThreshold 1–254 (MX-series). Then nibble apply — or nibble replay install to re-apply at every login. A config from an older version, with mappings directly under buttonMaps, is read as the Default profile and migrated on first write.

Runtime writes, by design

Writes go to device RAM — a power cycle reverts to the onboard profile. replay re-applies your config at login, in one shot.

Host mode, handled

Report-rate and RGB writes need the host-mode flag; commands flip it automatically and it reverts with the mouse.

Your flash stays yours

Onboard flash is read-only by design. onboard backup dumps every sector — restore factory settings via G HUB on any machine, any time.