AGENTS.md 7.5 KB

Agent Guidelines — Wobkey Impact 80 RGB CLI

Objective

Cross-platform Go CLI library for programmatic/agent-friendly control of VIA-compatible keyboard RGB lighting (starting with Wobkey Impact 80).

Architecture

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

CLI Interface

wobkey keyboard info
wobkey rgb effect breathing
wobkey rgb effect rainbow_moving_chevron
wobkey rgb effect rainbow_moving_chevron --zone backlight
wobkey rgb brightness <val>       # 0-255
wobkey rgb speed <val>            # 0-255
wobkey rgb color <hex>            # Six hexadecimal digits
wobkey rgb mode <index>           # Raw zone-specific effect ID
wobkey rgb enable
wobkey rgb disable
wobkey 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.

Impact 80 Effect Families

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.

VIA Protocol Essentials

  • Transport: QMK Raw HID over a 32-byte hidraw report, report number 0
  • Message types:
    • 0x07 — Custom set value
    • 0x08 — Custom get value
  • Impact 80 lighting channels: 0x02 logo, 0x03 backlight, 0x04 side
  • RGB value IDs: brightness 0x01, effect 0x02, speed 0x03, color 0x04
  • No separate enable handshake is used

Keyboards (Known Wobkey VID/PID)

Keyboard VID PID
Wobkey Rainy 75 0x6666 0x0001
Wobkey Impact 80 0x36B0 0x309F

keyboards.json maps VID+PID → VIA protocol config + RGB layout metadata.

Stack

  • Go 1.26+ (cross-platform: Linux, macOS, Windows)
  • github.com/sstallion/go-hid for HID access
  • github.com/spf13/cobra for CLI framework

Constraints

  • CLI-first, no GUI — designed for automation and agent consumption
  • Output should be machine-parseable (JSON when possible)
  • Cross-platform from day one

Go Development

Tooling

  • 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.

Style (Effective Go + Code Review Comments)

  • Formatting: always gofmt or goimports. Tabs for indentation, no line-length limit but avoid uncomfortably long lines.
  • Names: MixedCaps / mixedCaps, no underscores. Short local variables (i, c, r). Descriptive for globals.
  • Initialisms: consistent case — URL, ID, HTTP → appID, urlPony, ServeHTTP.
  • Comments: doc comments start with the name, end with period. // Package rgb provides RGB effect handling.
  • Imports: standard library first, blank line, then third-party. Grouped.

Error Handling

  • Return errors, never panic for normal control flow.
  • Indent error flow early — happy path at minimal indentation: 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).