Drive any wired VIA-compatible RGB keyboard from Claude Code status
Project description
claude-color
Live docs & demo → edocksil.github.io/claude-color
Drive a wired VIA-compatible keyboard's RGB from Claude Code status — see at a glance whether Claude is working, waiting for you, or idle, without looking at the terminal.
- working → blue-purple
- waiting for you (permission / input) → amber
- idle (turn done, session alive) → deep green
- Claude Code exits / no session running → your normal lighting is restored
Why claude-color
Built to be correct under real conditions, not just a demo:
- Multi-session aware — one keyboard, many Claude Code sessions, resolved by
priority (
waiting>working>idle). - Survives crashes & sleep — sessions are tracked by their Claude process; dead ones are pruned, and a boot/logon/unlock reconcile restores your lighting when no session is running.
- Accurate status — distinguishes a real permission prompt (amber) from a
finished-but-idle session (green) via Claude Code's
notification_type. - Restores your lighting — captures your real keyboard color and puts it back, with a guard against capturing its own status colors.
- Windows-first, keyboard-generic (any wired VIA RGB keyboard), 85+ tests.
Requirements
- Windows 11, Python 3.11+ — installed and run via uv (no system Python needed).
- Any wired keyboard exposing a VIA raw-HID interface with an RGB matrix, connected by USB cable. VIA support is most commonly provided by QMK firmware with VIA enabled, but only the VIA protocol is required — not QMK itself. Developed and validated on the Keychron Q6 Max. Wireless is not supported (wired only). See docs/COMPATIBILITY.md.
- Optional but recommended: the
qmk_hidbinary on your PATH (primary backend). Without it, the built-in Pythonhidapibackend is used.
Install
uv run claude-color doctor # confirm the keyboard is detected
uv run claude-color test # cycle working/waiting/idle, then restore
uv run claude-color install # add hooks to %USERPROFILE%\.claude\settings.json
To make claude-color a global command (so Claude Code can invoke the hooks from any
terminal), install it as a uv tool — --editable keeps it tracking this repo:
uv tool uninstall kbstatus # remove the old command (if previously installed)
uv tool install --editable . # exposes `claude-color` on PATH (~\.local\bin)
claude-color install # wire hooks (migrates any old kbstatus wiring)
Ensure the uv tool bin dir is on PATH so Claude Code and the scheduled task can
invoke claude-color.
Demo
Run the color cycle any time to see (or show off) all three statuses. It cycles working → waiting → idle and then restores your current lighting:
claude-color test # ~2s per color (quick check)
claude-color test --dwell 30 # hold each color 30s (slow demo)
Configure
Edit %LOCALAPPDATA%\claude-color\config.toml:
backend—auto(default),qmk_hid, orhidapisolid_effect_index— the VIA "solid color" effect index for your keymap. Ifclaude-color testshows an animation instead of a solid color, change this and rerunclaude-color test.vid/pid— hex, only needed if multiple HID devices match. Find yours withclaude-color doctororqmk_hid -l.[colors]— H/S/V (0–255) per statestaleness_minutes— a stuck session is forgotten after this (default 120)
How it works
flowchart LR
CC["Claude Code hooks"] -->|"SessionStart · UserPromptSubmit · Notification · Stop · SessionEnd"| K["claude-color hook"]
K --> S["state.json<br/>(per session, by PID)"]
S -->|"winner: waiting > working > idle"| KB["keyboard RGB<br/>(VIA raw-HID)"]
R["claude-color reconcile<br/>(logon / unlock)"] --> S
Claude Code fires hooks (SessionStart, UserPromptSubmit, Notification,
Stop, SessionEnd). Each runs claude-color hook, which updates a per-session
state file (%LOCALAPPDATA%\claude-color\state.json) and pushes the highest-priority
color (waiting > working > idle) across all live sessions. Sessions are
tracked by their Claude process id; dead ones are pruned, and a scheduled
claude-color reconcile (logon/unlock) restores your lighting when no Claude is
running. When the last session ends, the lighting captured at first
SessionStart is restored.
Troubleshooting
- No color changes: run
claude-color doctor. Ifavailable: False, check the USB cable (wireless is not supported) and trybackend = "hidapi"or setvid/pid. - Animation instead of solid color: fix
solid_effect_index. - Colors never restore: baseline capture may be unsupported on your firmware
via the active backend; try
backend = "hidapi". Logs are in%LOCALAPPDATA%\claude-color\claude-color.log. - Uninstall:
claude-color uninstall.
License
MIT — © 2026 Edocksil.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file claude_color-0.1.0.tar.gz.
File metadata
- Download URL: claude_color-0.1.0.tar.gz
- Upload date:
- Size: 30.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
083f0f4213f2db355417872088c52f1a062be216da29b0fca6d8496fb47ff56e
|
|
| MD5 |
c0c4f80db8af740ab670cb7615e0c473
|
|
| BLAKE2b-256 |
b2938faee27407d1970ed7d7dca2c9b50b5f3df32c7edaca8e6b93815407d580
|
Provenance
The following attestation bundles were made for claude_color-0.1.0.tar.gz:
Publisher:
release.yml on Edocksil/claude-color
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
claude_color-0.1.0.tar.gz -
Subject digest:
083f0f4213f2db355417872088c52f1a062be216da29b0fca6d8496fb47ff56e - Sigstore transparency entry: 2260747606
- Sigstore integration time:
-
Permalink:
Edocksil/claude-color@0445efe315c32768126d6fced09223bffa92ff54 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Edocksil
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@0445efe315c32768126d6fced09223bffa92ff54 -
Trigger Event:
push
-
Statement type:
File details
Details for the file claude_color-0.1.0-py3-none-any.whl.
File metadata
- Download URL: claude_color-0.1.0-py3-none-any.whl
- Upload date:
- Size: 22.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5049b1e49c6a703925cf7689adf00331b8d99458fc110c501ad490af9356fa81
|
|
| MD5 |
7fa13c3600c1e88e5f6b58298e0f85bb
|
|
| BLAKE2b-256 |
0a3c01001cefb9e93cb095abca6692b39983e84fef73a4d1c8b3888e3112af72
|
Provenance
The following attestation bundles were made for claude_color-0.1.0-py3-none-any.whl:
Publisher:
release.yml on Edocksil/claude-color
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
claude_color-0.1.0-py3-none-any.whl -
Subject digest:
5049b1e49c6a703925cf7689adf00331b8d99458fc110c501ad490af9356fa81 - Sigstore transparency entry: 2260747975
- Sigstore integration time:
-
Permalink:
Edocksil/claude-color@0445efe315c32768126d6fced09223bffa92ff54 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Edocksil
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@0445efe315c32768126d6fced09223bffa92ff54 -
Trigger Event:
push
-
Statement type: