KEYBARS PRO

The command line

keybars Pro comes with one command, keybars-pro, for everything the window does that’s worth doing from a terminal: lighting keys when a build finishes, starting a Focus session from a keybind, keeping your rules in a dotfiles repo, or letting a coding agent tap you on the shoulder. keybars Pro isn’t out yet; this is its command line as it will ship.

keybars-pro                       # open keybars Pro, or bring its window forward
keybars-pro run -- make test      # light the keyboard while it runs, then green or red
keybars-pro light esc red         # hold Escape red until you clear it
keybars-pro focus start 50m       # a 50-minute Focus session
keybars-pro help                  # every command

Install

The command comes with the app. In keybars Pro, open App settings and choose Install the command-line tool under Command line. That puts keybars-pro on your PATH:

SystemWhere it goes
Linux, macOSa link in /usr/local/bin if keybars Pro can write there, else ~/.local/bin
Windowsa small keybars-pro.cmd in %LocalAppData%\keybars-pro\bin, which is added to your user PATH

It never replaces a file it didn’t make. If the folder isn’t on your PATH yet, the app says so: add ~/.local/bin to your shell’s PATH, or on Windows open a new terminal. Remove in the same place takes it off again.

Behind the link is a small program that sits beside the app, keybars-pro-cli. You don’t need its name, except that hooks written by the coding agents’ Set up for me use its full path so they work without a PATH at all.

How it works

The command talks to the running app through a local socket that only your user account can open: $XDG_RUNTIME_DIR/keybars-pro.sock on Linux, and control.sock beside the settings elsewhere. It isn’t reachable over the network.

  • The app has to be running. Every command but keybars-pro on its own, completion, engine and mcp’s startup needs it. When it isn’t, the command says keybars Pro isn't running and exits with status 3. keybars-pro with no command starts it.
  • It does what the window does. Each command calls the same code as the window’s buttons, so a change made here shows in the window at once, and is checked and saved the same way.
  • Free copies work too. As in the window, Pro features play in the preview on a free copy and on the keyboard with a licence. keybars-pro status says which you have.
  • Flags go anywhere after the command: keybars-pro light esc red -for 5s and keybars-pro light -for 5s esc red are the same. Anything after -- is left alone.
  • -json on any command that prints something gives JSON instead, for scripts and jq.

Exit status

StatusMeans
0done
1it failed; the reason is on standard error
2the command or its arguments weren’t right; its usage is printed
3keybars Pro isn’t running
otherrun passes on the exit status of the command it ran

Builds and scripts

run

keybars-pro run [-name build] [-q] -- command [args...]

Runs a command and lights the keyboard for it: build.running as it starts, then build.passed or build.failed by its exit status, which run passes on as its own. Standard input and output go straight through, and Ctrl-C reaches the command. With the default rules, the top row chases amber while it runs and Escape holds red if it fails.

keybars-pro run -- make test
keybars-pro run -name deploy -- ./ship.sh     # deploy.running, deploy.passed, deploy.failed
keybars-pro run -q -- go test ./...           # no warning when the app isn't open

If keybars Pro isn’t running, the command runs anyway, with a one-line warning unless -q.

notify

keybars-pro notify [-q] [-source cli|github|forgejo] [-repo r] [-branch b] event [state]

Sends an event to your Notify rules. The second word turns a task into an event name:

You typeEvent sent
notify build 0build.passed
notify build 1, or any other numberbuild.failed
notify build $?whichever the last command’s status says
notify build runningbuild.running
notify deploy.donedeploy.done, as written

-repo and -branch say what the event is about, for rules that only fire for one repository or branch. -source is cli unless you say otherwise; a tool that watches GitHub or Forgejo itself, such as herdr-gh, sends -source github (or forgejo) with their event names, so rules for that service play its events whether they came through the relay or not. -q prints nothing and exits 0 even when the app isn’t running, which is what agents’ hooks want. Without it, notify prints the rules the event played, or no rule matches.

make test; keybars-pro notify build $?
keybars-pro notify -repo keybars -branch main deploy.done
keybars-pro notify -source github -repo me/app pull_request.merged

Lighting keys

light

keybars-pro light keys colour [-effect hold] [-for 5s]

Lights keys straight away, with no rule to set up. keys is one or more key names, comma-separated; colour is a colour name or #rrggbb. The effect is any of the nine effects, hold if you leave it out. Held lights stay until you clear them; -for clears them after that long (5s, 2m).

keybars-pro light esc red
keybars-pro light top-row amber -effect pulse
keybars-pro light all green -effect wave -for 5s
keybars-pro light r1c1,r1c12 '#ff3df2' -effect breathe

Lighting the same keys again replaces the light that was there. Lights play over the music and under nothing: they sit at the top of your rules.

clear

keybars-pro clear [lights | rule name]
You typeIt stops
cleareverything playing: lights, held rules and effects
clear lightseverything lit with light
clear CI failedthat rule, by its name
clear top-rowthe light on those keys

Key names

A keyboard tells keybars where a key is, never what it types: that’s up to your layout. So keys are named by position, top row first and the left-most key first, counted from 1. keybars-pro map prints your keyboard’s positions.

NameKeys
allevery key
top-row, home-row, bottom-rowthe top row, the third row down, the bottom row
thumbsthe bottom row: the thumb keys on a Moonlander or Voyager
left, righteach half
top-left, escthe top-left key, Escape on most layouts
top-rightthe top-right key
row:2, col:5a whole row or column
r3c4the key at row 3, column 4
led:12the key with LED 12, as map numbers them
row:1-2, col:2-4, led:1-4a range of rows, columns or LEDs
r1c2-r2c5every key in the rectangle between two corners, in either order

Combine them with commas: esc,top-right, row:1,col:12, r1c2-r1c5,led:30. Case and spaces don’t matter.

Colours

red, amber, orange, green, blue, cyan, purple, pink, white, and off (dark), or any #rrggbb (quote it in most shells: '#ff3df2').

Effects

EffectPlaysWhat it does
flash0.9 son and off three times
pulse3 sfades up and down three times
wave1.5 ssweeps left to right across the keys
fade3 slights up, then fades away
sparkle3 sthe keys twinkle at random
ripple1.5 srings spread over the whole board from each key
holduntil clearedstays lit
breatheuntil clearedglows up and down slowly, never dark
chaseuntil cleareda light runs along the keys, for something running

The app

status

keybars-pro status [-json]
on · Pro, updates until 2027-10-14 · Voyager
bars: music · typing: off · focus: work, 18:42 left
hearing: Built-in Audio Analog Stereo
playing: CI failed, Agent waiting
service: github connected

Whether the keyboard is lit, the licence and how long its updates run, the keyboard, what the bars show, Typing, Focus, what the app hears, the rules playing now, connected services, and any startup step that failed. -json adds the startup steps in full.

on, off, toggle

The switch at the top of the window. off hands the keyboard back to its own layout and the preview with it; on lights it again; toggle flips it, which is the one to bind to a key in your desktop’s shortcuts.

test

keybars-pro test plays the 30-second test (a sweep through every column and row, with no music needed); keybars-pro test stop ends it early.

open, quit, retry

open brings the window forward; keybars-pro with no command does the same, and starts the app if it isn’t running. quit quits keybars Pro. retry starts again after a startup step failed, such as the keyboard being unplugged.

devices, map

keybars-pro devices [-json]
keybars-pro map [forget]

devices shows the keyboard (how it’s connected, its LEDs and, on a ZSA board, its Oryx protocol), the map in use, the audio source and whether OpenRGB’s server answers. map prints the keyboard’s map, each key’s LED number in its place, for led:N and rRcC:

# voyager: each key's LED, rows top to bottom; - for no key
 0  1  2  3  4  5 26 27 28 29 30 31
 6  7  8  9 10 11 32 33 34 35 36 37

map forget drops a map saved with Find keys, going back to the built-in one.

system

keybars-pro system [-json] prints CPU, memory and temperature now, as System mode reads them: CPU 12% over 8 cores · memory 41% · 52 °C. macOS doesn’t give apps a temperature.

licence

keybars-pro licence [-json]
keybars-pro licence activate KEY
keybars-pro licence activate -here
keybars-pro licence deactivate

Shows the licence on this computer and how long its updates run. activate takes the key from your email. A key is good on three computers; when it’s active on another one, activate -here moves it to this one. deactivate frees this computer’s place.

Modes

focus

keybars-pro focus [start [25m] | stop | status] [-json]

The Focus timer. start begins a session of your usual length, or this one’s: start 50m, start 1h, start 25 (minutes). stop ends it. On its own, or with status, it prints work, 18:42 left, break, 3:10 left or idle.

bars

keybars-pro bars music or bars cpu: what the bars show, the music or each CPU core’s load (System mode).

typing

keybars-pro typing on | off | stats [-json]

Typing mode lights your key presses in place of the music, on ZSA boards. stats prints 62 wpm now · 88 best today · 4210 keys today.

ambient

keybars-pro ambient [scene | on | off | list] [-brightness 40] [-speed 100] [-when-quiet on|off] [-json]

Ambient mode loops a calm scene on the keyboard in place of the music, with no events or sound. Naming a scene turns it on: ambient rain. list shows them all:

ScenePlays
raindrops fall down the columns and splash along the bottom row
zenone slow colour breathing across the board, teal to violet
autumnorange, red and gold leaves blown across in gusts
auroragreen and violet curtains rippling sideways
oceanwaves rolling in, white at the crest
fireflieswarm dots blinking on and off at random
snowflakes drifting down and piling on the bottom row
embersa fire flickering at the bottom, sparks rising
breathingbox breathing: rows fill for 4 seconds, hold, empty, hold

-brightness caps it, 5 to 100 percent (40 to start, so it stays calm); -speed runs it slower or faster, 25 to 400 percent. -when-quiet on plays the scene whenever the music stops, in place of the keyboard’s own layout. Notify’s rules and Focus still show on top. On its own, ambient prints on · rain · 40% bright · 100% speed.

clock

keybars-pro clock [rows | ring | spelled | binary | off]

A clock on the keyboard, through Ambient mode:

ClockShows
rowsthe hour on the top row (a key each, 1 to 12), five-minute steps on the second with the current key filling, and a key walking the third row with the seconds
ringthe board’s outer keys as a clock face: the hour amber, the minute cyan, a faint second hand
spelledthe time spelled on the number row’s digit keys, one at a time: for 14:30, 1, 4, a pause, 3, 0
binaryhours, minutes and seconds as six bits on the top three rows

clock on its own is the rows clock; clock off turns Ambient off.

timer

keybars-pro timer [10m [name] | stop] [-json]

A countdown draining across the top two rows, green to amber to red, flashing for three seconds when it’s done. It plays over whatever’s showing: the music, a scene, Typing. timer 25m tea names it; on its own, timer prints tea, 18:42 left.

Notify rules

A rule lights keys when an event arrives. The window’s rule editor is the easy way to paint keys; these are for everything else.

rules

keybars-pro rules [list] [-json]
keybars-pro rules add name event -keys k [-colour red] [-source cli] [-effect hold]
                  [-clear-on events] [-clear-after minutes] [-repo r] [-branch b] [-off]
keybars-pro rules remove | on | off | try name
keybars-pro rules export > rules.json
keybars-pro rules import [-replace] rules.json
ActionWhat it does
listeach rule: on or off, its name, source, event, effect and how many keys
adda new rule at the top, where the window adds them; -keys takes key names
removedeletes a rule
on, offswitches a rule without deleting it
tryplays a rule now, as the editor’s Test does
exportprints every rule as JSON
importadds rules from a file, or standard input with -; -replace replaces yours

Rules are found by name, ignoring case. The higher a rule, the more it wins when two light the same key.

keybars-pro rules add "CI failed" ci.failed -source github -keys esc -colour red -clear-on ci.passed
keybars-pro rules add "Doorbell" doorbell -source webhook -keys all -colour cyan -effect ripple
keybars-pro rules add "Agent waiting" agent.waiting -keys top-right -colour blue \
  -effect breathe -clear-on "agent.working agent.done" -clear-after 60

-source is where the event comes from: cli (this command and agents’ hooks), github, forgejo, webhook or system. Held effects (hold, breathe, chase) stay until one of -clear-on’s events arrives, space-separated, or -clear-after minutes pass (0 for never), or you clear them.

events

keybars-pro events [-n 10] [-json] lists what Notify got lately, newest first, with the rules each played:

14:02:11  github   pull_request.merged          jwarykowski/keybars main  PR merged
13:58:40  cli      build.failed                                           Escape red

Event names

SourceEvents
clianything you send: build.running, build.passed, build.failed, deploy.done, …
agents’ hooksagent.working, agent.waiting, agent.done
githubpull_request.merged, pull_request.opened, pull_request.closed, pull_request.review_requested, review.approved, review.changes_requested, ci.running, ci.passed, ci.failed, push, release.published, issue.opened
forgejoas GitHub’s, without ci.running (Forgejo only reports finished runs)
webhookthe name at the end of the address, or a JSON body’s "event"
systemcpu.high, cpu.normal, memory.high, memory.normal, temperature.high, temperature.normal

Services

GitHub, Forgejo and any other service reach keybars Pro through a relay, which gives each a private address and passes events on while the app is open.

services, connect, disconnect

keybars-pro services [-json]
keybars-pro connect github | forgejo | webhook
keybars-pro disconnect github | forgejo | webhook

services lists what’s connected, its state and when the last delivery came. connect makes an address and prints it, with the secret to paste into GitHub’s or Forgejo’s webhook settings. disconnect removes the service; its address stops working, so delete the webhook on the other side too.

webhook

keybars-pro webhook url [event] [-secret]
keybars-pro webhook test
keybars-pro webhook secret on | off

For Any webhook: url backup.failed prints the address for that event, ready to paste into a monitor, a deploy hook or Home Assistant; -secret also prints the Authorization: Bearer header. test sends a test event through the relay. secret on makes the relay refuse anything without the secret; with it off, the address itself is the secret.

curl -X POST "$(keybars-pro webhook url deploy.done)"

Coding agents

agents

keybars-pro agents [-json]
keybars-pro agents setup claude | codex | gemini | cursor | opencode | aider
keybars-pro agents remove claude

Lists the agents keybars Pro knows, and whether each is on this computer and set up. setup adds keybars Pro’s hooks to the agent’s own settings beside the hooks already there, after copying the file to <file>.keybars-backup; remove takes them out and leaves the rest. Each hook runs notify -q agent working, agent waiting or agent done. Codex and Aider take only one notify command; if one is already set, agents says so and you add keybars Pro’s by hand.

AgentSettings fileSends
Claude Code~/.claude/settings.jsonworking, waiting, done
Codex CLI~/.codex/config.tomldone
Gemini CLI~/.gemini/settings.jsonworking, waiting, done
Cursor~/.cursor/hooks.jsonworking, done
OpenCode~/.config/opencode/plugins/keybars.jswaiting, done
Aider~/.aider.conf.ymldone

mcp

keybars-pro mcp is a Model Context Protocol server on standard input and output, so an agent can use keybars Pro as tools of its own, with no hooks to set up:

claude mcp add keybars -- keybars-pro mcp
ToolDoes
light_keyslights keys, as light
clear_keysclears them, as clear
notifysends an event to your rules
statusreads the app’s status
focusstarts, stops or reads the Focus timer

Other agents take the same command in their MCP settings.

Marketplace

market

keybars-pro market search [words] [-json]
keybars-pro market show item [-json]
keybars-pro market install item
keybars-pro market remove id
keybars-pro market list [-json]

Looks, rule packs, key maps and integrations from the marketplace. item is an ID (ci-pack), a .keybars file or a link to one. Items from keybars.app are signed, and one whose signature doesn’t check out is refused; with no connection, search and install fall back to keybars’ own items, which come with the app.

install applies a look, adds a pack’s rules at the top of your Notify rules, or saves a key map, and records what it changed. remove undoes exactly that: a look puts back the settings you had (where you haven’t changed them since), a pack’s rules come out, a map goes back to the one before. Installing again replaces the version that’s there. An integration isn’t installed: show gives the link it installs from. list shows what’s installed.

A pack names keys by where they are (top-row, esc, r1c2-r1c5), so it fits your board whatever it is.

Sharing your own

keybars-pro market export look -name "Night bus" [-o night-bus.keybars]
keybars-pro market export pack -name "Deploy alerts" -rules a1,b2 -o deploy.keybars
keybars-pro market export map -name "Keychron Q1" [-keyboard name]
keybars-pro market login
keybars-pro market publish deploy.keybars
keybars-pro market logout

export makes a .keybars item from your settings: your look as it is, the rules you list (every rule without -rules; rules shows their IDs), or the map Find keys saved for this keyboard (or -keyboard’s). -id (made from the name otherwise), -version (1.0), -licence (an SPDX name such as MIT) and -description fill in the rest. A pack rule has one colour, so a rule that lights keys in several keeps its most used one; export says when, and when a key isn’t on your keyboard’s map. It prints the item, or writes it to -o’s file. The app’s Share buttons (beside Import, on Notify’s rules and on the keyboard in Devices) make the same files.

publish sends a file (or - for standard input) to the marketplace, where it’s checked and, if it passes, live under your name straight away. It needs login first, which asks for a token from the publish page (Publishing from the terminal) and keeps it in market-token beside the settings, readable only by you. KEYBARS_MARKET_TOKEN is used instead when it’s set. logout forgets the token; delete it on the publish page too if you’re done with it.

KEYBARS_MARKET points every market command at another marketplace, such as a local one while developing.

Settings

settings

keybars-pro settings get [key]
keybars-pro settings set key value
keybars-pro settings export > keybars.json
keybars-pro settings import keybars.json

Settings are named by their key in the settings file, dotted: equaliser.gain, focus.work. get prints one as JSON, or every setting with no key. set takes JSON where it parses, else text: set equaliser.gain 1.5, set equaliser.peaks false, set equaliser.colours '["#00ff00","#ff0000"]', set typing.look heatmap. A value out of range is refused, with the reason, and nothing changes. export prints the whole settings file; import reads one (or a keybars config) as the window’s Import does, and prints what it left out.

KeyMeans
themesystem, light or dark
palettegreen, meter, ice, sunset, synthwave or ember
surprise, matchKeyboard, startInTraya new theme each launch; the bars in the theme’s colours; start in the tray
equaliser.devicethe audio source; empty for what the computer plays
equaliser.lowHz, equaliser.highHzthe frequency range, 50 to 12000 by default
equaliser.gainhigher reaches the top more often; 1.5 by default
equaliser.colours, equaliser.brightnessthe bars’ colours bottom to top, and brightness 0 to 100
equaliser.peaks, equaliser.peakColour, equaliser.peakHoldMs, equaliser.peakFallpeak dots: on, colour, how long they hold, how fast they fall
equaliser.smoothing, equaliser.fps0 jumpy to 100 smooth; frames a second
equaliser.symmetryempty (mirror split boards), off, centre or edges
equaliser.keyboard, equaliser.openrgb, equaliser.model, equaliser.heightwhich keyboard, OpenRGB’s address, the built-in map, how many rows the bars use
equaliser.reserve, equaliser.idleMsLEDs the bars leave alone; how long silence lasts before the layout comes back
system.bars, system.coloursCPU cores on the bars; their colours
system.cpu, system.memory, system.temperaturethe alert limits, percent and °C, 0 for off
focus.work, focus.breakminutes
focus.homeRow, focus.quiet, focus.colour, focus.breakColourdim all but the home row; only held rules during work; the timer’s colours
typing.on, typing.look, typing.colours, typing.gauge, typing.targetTyping: on, ripple, afterglow or heatmap, its colours, the speed gauge, target words a minute

Rules have their own command, rules.

theme

keybars-pro theme [palette] [-scheme system|light|dark]

On its own, prints the theme. With a palette, green, meter, ice, sunset, synthwave or ember, it colours the window, the tray icon, and the bars too with Match the keyboard on. -scheme sets light or dark.

colours

keybars-pro colours [colour,colour,...] [-of bars|cpu|typing]

The bars’ colours, bottom to top, by name or #rrggbb: keybars-pro colours green,amber,red. On its own it prints them. -of cpu sets System’s CPU bars and -of typing Typing’s colours instead. It’s a short way to settings set equaliser.colours.

reset

keybars-pro reset equaliser | system | focus | typing | appearance | all puts that part of the settings back to a fresh install’s. all keeps your rules and saved key maps.

Watching

watch

keybars-pro watch [-only events] [-format template]

Prints a JSON line each time something happens, until you stop it with Ctrl-C: the same news the window gets. Status bars, scripts and dashboards can follow along.

{"event":"notified","data":{"source":"cli","name":"build.failed","rules":["Escape red"],"at":"2026-10-17T14:02:11+11:00"}}
{"event":"focus","data":{"phase":"work","remaining":1122,"length":1500}}
EventWhenIts data
notifiedan event reaches Notifysource, name, repo, branch, number, rules played, at
focuseach second of a sessionphase (work, break or empty), remaining and length in seconds
typingeach second Typing is onwpm, best, today
pausedthe On switch changestrue when off
stepa startup step changesid (keyboard, map, audio, mode), state, detail
servicesa service connects, drops or gets a deliverythe list services prints
settingssettings are savedevery setting
testthe test playsrunning, elapsed, length, part

-only focus,typing picks events. -format prints a Go template of each event’s data instead of the JSON, with mmss to show seconds as minutes and seconds.

keybars-pro watch -only focus -format '{{mmss .remaining}}'      # 18:42
keybars-pro watch -only typing -format '{{.wpm}} wpm'

In a status bar

A waybar module showing the Focus timer:

"custom/focus": {
  "exec": "keybars-pro watch -only focus -format '{{if .phase}}{{.phase}} {{mmss .remaining}}{{end}}'",
  "on-click": "keybars-pro focus start",
  "on-click-right": "keybars-pro focus stop"
}

In tmux, status-right can run a command; keybars-pro focus prints the time left each time it’s asked.

Shell completion

keybars-pro completion zsh > "${fpath[1]}/_keybars-pro"    # zsh
source <(keybars-pro completion bash)                       # bash, in ~/.bashrc
keybars-pro completion fish > ~/.config/fish/completions/keybars-pro.fish
keybars-pro completion powershell | Out-String | Invoke-Expression   # in your $PROFILE

It completes commands and their words: actions, key names, colours, effects, themes, agents and settings parts, and your rule names for clear and rules on, off, try and remove, asked of the running app.

Running the engine alone

keybars-pro engine runs the equaliser in the terminal with the app’s saved settings and without the app: -preview draws the bars in the terminal too, -test plays the 30-second test and exits. It’s for trying the engine out; with the app open, the two would fight over the keyboard.