CLED (Claude/Codex LED) — ambient keyboard daemon that maps your AI agents' status onto the keys via OpenRGB
Project description
CLED
Claude/Codex LED — an ambient daemon that turns your keyboard into a live status panel for your AI coding agents (and your machine), driven by OpenRGB.
CLED maps your running agent sessions onto the keys: glance down and see, by color, which of your Claude Code / Codex sessions is working, which is waiting on you, and how hard your machine is breathing — without alt-tabbing to check.
Live demo & install →
Demo video made with /brag
What you see
F1 ─────────────── F12 RAM usage, fills left → right
1 2 3 4 ... 9 one slot per agent tab in the focused iTerm2 window
┌ red = busy (mid-turn, working)
├ green = idle (waiting for you)
├ amber = stale (idle > 20 min)
└ blue = other (tab isn't a recognized agent)
Numpad 0–9 per-core CPU load, green → yellow → red
Enter rainbow heartbeat (the daemon is alive)
everything else dim
Requirements
- A keyboard with LEDs!
- macOS. Agent detection reads the focused iTerm2 window via AppleScript, so iTerm2 + macOS are assumed.
- OpenRGB installed (the app). CLED talks to its
server on
127.0.0.1:6742and launches it for you if it isn't running. - Python ≥ 3.11, managed with uv.
- An OpenRGB-supported RGB keyboard. Developed against a Corsair K70 RGB MK.2 SE (Direct mode, 116 LEDs); key regions are addressed by OpenRGB LED name, so it generalizes to other boards where those names match.
Install & run
CLED is on PyPI, so the quickest path — no clone — is with uv:
uvx cled # fetch and run in one step, nothing installed
For a persistent cled command on your PATH:
uv tool install cled
cled
In Claude Code? Install the plugin and let your agent do the setup — it checks your machine (OpenRGB, a controllable keyboard, iTerm2) and launches the daemon in its own window:
/plugin marketplace add latent-spaces/cled
/plugin install cled@cled
Then invoke it with /cled. The plugin is a thin launcher around the same uvx cled, so the PyPI package above stays the single source of truth.
Or run from a clone, handy if you want to hack on it (see Make it yours below):
git clone https://github.com/latent-spaces/cled
cd cled
uv run cled
However you start it, the daemon connects to OpenRGB if it's already up, and
otherwise starts the server itself. Press Ctrl-C to quit (the OpenRGB server is
left running).
macOS, no root
On macOS, OpenRGB can drive the keyboard as a plain user — no sudo, no Input
Monitoring grant — but only when the server runs inside your GUI/Aqua session.
CLED relies on this: it self-heals the server with
open -a OpenRGB --args --server --noautoconnect
which is the launch context that has HID access. The catch: start CLED from a
terminal in your normal desktop session. Running under sudo (or from a
non-GUI/CLI-orphan context) sees zero devices, and also breaks agent detection —
Path.home() and iTerm2 automation both need your user session.
How it works
| File | Role |
|---|---|
rgb.py |
OpenRGB client + render loop (RGBSession). Self-heals: reconnects on connection errors, and refreshes the server when it detects a wake-from-sleep (a >60s wall-clock gap between frames means the HID handle went stale). |
agent_tabs.py |
Watches tabs in the focused iTerm2 window (osascript + ps) and maps each to a status — Claude Code reads its session JSONL, Codex reads its rollout state — to tell busy from idle. |
cled.py |
The daemon. Composes each frame (agents + CPU + RAM + heartbeat) and runs the loop at 10 fps. |
Make it yours
CLED is deliberately small and self-contained — three short modules, the Python
standard library, and two dependencies (openrgb-python, psutil). There's no
framework and no hidden machinery; the whole thing fits in one sitting.
So fork it and bend it to your setup — a different key layout, your own status colors, a provider for another agent or terminal. Each behavior lives in a few small, obvious functions. Just ask Claude to change the behavior you want.
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 cled-0.1.0.tar.gz.
File metadata
- Download URL: cled-0.1.0.tar.gz
- Upload date:
- Size: 6.6 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
04db4c772b1590fa573583a304b8c2f94f2880dbaf6c4ca5be1411c5a1d68c19
|
|
| MD5 |
3664c7184e8b4be5109f4c5a9321120c
|
|
| BLAKE2b-256 |
1e6a0d8557318bf018350de070cdef2b5ddf5096a5bd1dccf872649ffd3ed563
|
File details
Details for the file cled-0.1.0-py3-none-any.whl.
File metadata
- Download URL: cled-0.1.0-py3-none-any.whl
- Upload date:
- Size: 13.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
859d890e1fbbe045fae6cadc3c19c24335b13554cef53f322a45ecb40664d8e8
|
|
| MD5 |
4d9f1731125080d739e16104c416b655
|
|
| BLAKE2b-256 |
da5795ad7790048fe2807cb74a0228cd5167df823016aef50406df0e79c87a6a
|