Cross-platform Go CLI library for programmatic/agent-friendly control of VIA-compatible keyboard RGB lighting (starting with Impact 80).
cmd/ # Cobra-based CLI entrypoints
internal/device/ # HID device discovery (VID/PID matching)
internal/via/ # VIA protocol implementation + LED subsystem
internal/rgb/ # Effects, values, color definitions
keyboards.json # VID/PID database + keyboard metadata
qmk-rgb keyboard info
qmk-rgb rgb effect breathing
qmk-rgb rgb effect rainbow_moving_chevron
qmk-rgb rgb effect rainbow_moving_chevron --zone backlight
qmk-rgb rgb brightness <val> # 0-255
qmk-rgb rgb speed <val> # 0-255
qmk-rgb rgb color <hex> # Six hexadecimal digits
qmk-rgb rgb mode <index> # Raw zone-specific effect ID
qmk-rgb rgb enable
qmk-rgb rgb disable
qmk-rgb rgb info
rgb has a persistent --zone flag accepting logo, backlight, or side.
Without --zone, commands target Logo, Backlight, and Side in that order.
With --zone, commands target exactly one zone. Unsupported default targets
are skipped with a stderr warning; unsupported explicit-zone effects and
unknown names fail before the device is opened.
Logo and Side use IDs 0–6: none, wave, fixed_wave, spectrum,
breathing, light, and shutdown.
Backlight uses the complete ID 0–45 family:
none, solid_color, alphas_mods, gradient_up_down, gradient_left_right,
breathing, band_sat, band_val, band_pinwheel_sat, band_pinwheel_val,
band_spiral_sat, band_spiral_val, cycle_all, cycle_left_right,
cycle_up_down, cycle_out_in, cycle_out_in_dual, rainbow_moving_chevron,
cycle_pinwheel, cycle_spiral, dual_beacon, rainbow_beacon,
rainbow_pinwheels, flower_blooming, raindrops, jellybean_raindrops,
hue_breathing, hue_pendulum, hue_wave, pixel_flow, digital_rain,
solid_reactive, solid_reactive_wide, solid_reactive_multiwide,
solid_reactive_cross, solid_reactive_multicross, solid_reactive_nexus,
solid_reactive_multinexus, splash, multisplash, solid_splash,
solid_multisplash, starlight, starlight_dual_hue, starlight_dual_sat,
riverflow
ID 39 is multisplash; ID 41 is solid_multisplash. Supported aliases are
off → none, breathe → breathing, rainbow (zone-dependent),
rainbow_wave (Logo/Side), solid (zone-dependent), and legacy static.
Do not assume a numeric effect ID is valid on every zone; use the zone-aware
name resolver or deliberately use rgb mode as a raw escape hatch.
rgb info emits a zones array containing each selected zone's channel,
enabled state, effect name and ID, brightness, speed, and color. The
top-level summary comes from the first selected zone. A failed zone includes
an error field while other zone results remain available; the command
prints JSON before returning non-zero.
00x07 — Custom set value0x08 — Custom get value0x02 logo, 0x03 backlight, 0x04 side0x01, effect 0x02, speed 0x03, color 0x04| Keyboard | VID | PID |
|---|---|---|
| Wobkey Rainy 75 | 0x6666 | 0x0001 |
| Wobkey Impact 80 | 0x36B0 | 0x309F |
keyboards.json maps VID+PID → VIA protocol config + RGB layout metadata.
github.com/sstallion/go-hid for HID accessgithub.com/spf13/cobra for CLI frameworkAll documentation (README.md, comments, AGENTS.md) must stay in sync with the code. When code and documentation conflict, ask the user before deciding which one to change. Do not silently pick a winner — explicitly state the conflict and get direction.
gopls — Go Language Server, built into Go toolchain (LSP, diagnostics, go-to-def, rename, references)gofmt / goimports — formatting. goimports adds/removes imports automatically. Always run before committing.go test — built-in test framework. Tests live in *_test.go files alongside source.go vet — static analysis. Run before committing.go build — compiles without installing. Fast, cached.go mod tidy — adds missing deps, removes unused ones. Run after every import change.gofmt or goimports. Tabs for indentation, no line-length limit but avoid uncomfortably long lines.MixedCaps / mixedCaps, no underscores. Short local variables (i, c, r). Descriptive for globals.URL, ID, HTTP → appID, urlPony, ServeHTTP.// Package rgb provides RGB effect handling.panic for normal control flow.go
if err != nil {
return err
}
// normal code
- Error strings: lowercase, no period — fmt.Errorf("device not found").
- Do not discard errors with _.
### Interfaces & Types
- Define interfaces in the consumer package, not the producer.
- Use pointer receivers when in doubt (mutation, large structs, sync fields).
- Return concrete types from constructors — let consumers mock if needed.
- Empty slices: var t []string (nil), not t := []string{} (non-nil), unless JSON encoding requires [].
### Concurrency
- Pass context.Context as first parameter. Never store in structs.
- Clear goroutine lifetimes — document when/why they exit. Avoid leaks via channels.
- Prefer synchronous functions — callers can add concurrency, not remove it.
### Testing
- Table-driven tests preferred for multiple cases.
- Failure messages: t.Errorf("Effect(%q) = %d, want %d", input, got, want).
- Use *_test.go files. Test package should match source package (internal tests).
- Example functions (func Example...) double as docs and tests.
### Modules & Packages
- Module path: github.com/<user>/<project> (when published).
- Package names: short, single-word, lowercase. No util, common, api, types.
- Zero values should be useful (e.g. bytes.Buffer, sync.Mutex).
## graphify
This project has a knowledge graph at graphify-out/ with god nodes, community structure, and cross-file relationships.
When the user types /graphify, use the installed graphify skill or instructions before doing anything else.
Rules:
- For codebase questions, first run graphify query "<question>" when graphify-out/graph.json exists. Use graphify path "<A>" "<B>" for relationships and graphify explain "<concept>" for focused concepts. These return a scoped subgraph, usually much smaller than GRAPH_REPORT.md or raw grep output.
- Dirty graphify-out/ files are expected after hooks or incremental updates; dirty graph files are not a reason to skip graphify. Only skip graphify if the task is about stale or incorrect graph output, or the user explicitly says not to use it.
- If graphify-out/wiki/index.md exists, use it for broad navigation instead of raw source browsing.
- Read graphify-out/GRAPH_REPORT.md only for broad architecture review or when query/path/explain do not surface enough context.
- After modifying code, run graphify update . to keep the graph current (AST-only, no API cost).