| name | keyboard-backlight |
| description | Use when the user wants Claude Code to blink the MacBook keyboard backlight as a notification, or asks to install, tune, mute, disable, debug or remove that notifier ("flash the keyboard when you are done", "the blinks are too long", "stop the blinking at night", "why is it blinking twice"). User-invoked via /keyboard-backlight. |
Keyboard backlight notifier
Blinks the MacBook keyboard backlight when Claude Code finishes a response, so
the user knows the turn is done without watching the terminal. Driven by a
Stop hook that calls bin/notify.js in this package.
The one command that matters
Everything runs through the kbdnotify CLI. Never hand-edit settings.json for
this: the installer backs it up, dedupes its own entries, and removes the older
claude-code-pulse.js hook that would otherwise double every blink.
node <repo>/bin/kbdnotify.js install
node <repo>/bin/kbdnotify.js status
node <repo>/bin/kbdnotify.js doctor
node <repo>/bin/kbdnotify.js test
node <repo>/bin/kbdnotify.js uninstall
<repo> is the checkout of claude-code-macos-keyboard-backlight. If
kbdnotify is on PATH (installed with npm link or npm i -g), use that name
instead of the full path.
Deciding what to do
| The user says | Do this |
|---|
| "make it blink when you're done" | kbdnotify install, then kbdnotify test |
| "it doesn't blink" | kbdnotify doctor first, fix what it names, never guess |
| "it blinks twice" | Two notifiers registered. kbdnotify install removes the legacy one; confirm with status |
| "too long / too many / too bright" | kbdnotify config set Stop.onMs 400 etc. See references/configuration.md |
| "not at night" | kbdnotify config set quietHours.start 23:30 and quietHours.end 07:00 |
| "quiet for the next few hours" | kbdnotify mute 09:00 (one-shot, survives a reboot) |
| "also when you need permission" | kbdnotify install --events Stop,Notification |
| "turn it off" | kbdnotify config set enabled off (keeps the install) or kbdnotify uninstall |
| "remove it completely" | kbdnotify uninstall, then say the checkout can be deleted |
After changing configuration, say that it takes effect on the very next hook
run. After install or uninstall, say that Claude Code reads settings.json
at session start, so the hook registration itself lands in the next session.
kbdnotify test works immediately either way.
Rules
- Report what the tool printed.
doctor exits non-zero and names the exact
failure. Do not paraphrase it into a guess.
- Do not edit
~/.claude/settings.json directly. The CLI is the supported
path, and it is the one that makes a backup.
- Never claim a blink happened without running
test. The hook is silent by
design; there is nothing in the transcript to check.
- A missing backlight is not a bug to fix. External keyboards and Mac minis
have no backlight API.
doctor says so; relay it and stop.
How it works, in four lines
- Claude Code fires the
Stop hook and pipes a JSON payload to its stdin.
notify.js reads ~/.claude/kbdlight-notify.json, merged over the defaults,
and decides whether this event blinks right now.
- If yes, it re-spawns itself detached and exits in milliseconds, so the turn is
never held open by a blink that takes about a second.
- The detached child calls
blink() from macos-keyboard-backlight, which
snapshots brightness and the auto-brightness flag per keyboard, blinks, and
restores exactly what it found.
Exit code is 0 on every path, including every failure: a notifier that breaks
the hook it hangs off is worse than a missed blink.
References
references/configuration.md: every key, its default, why the default is
what it is, and the recipes people actually ask for.
references/events.md: the three hook events, what each one means, and when
to enable the two that are off by default.
references/troubleshooting.md: symptom to cause to fix, including double
blinks, an nvm node path that vanished, and a stale lock.