A tiny ESP32-C3 gadget that glows and beeps to show you what Claude Code is doing — in real time.
No more alt-tabbing to check your terminal.
🔴 Working · 🔵 Done · 🟢 Needs approval · 🔵 Idle breathing · ⚫ Offline
StatusClawd is a physical LED indicator that connects to Claude Code through hooks. When Claude is thinking, the light turns red. When it finishes, it turns blue and plays a little melody. When it needs your permission, it pulses green and beeps at you.
It sits on your desk and lets you focus on something else while Claude works.
Claude Code ──HTTP hooks──▸ Bridge Server ──WebSocket──▸ ESP32-C3
(your IDE) (Python, local) (LED + buzzer)
| State | LED | Sound | What it means |
|---|---|---|---|
| Working | 🔴 Solid red | — | Claude is thinking or running tools |
| Done | 🔵 Solid blue | Ascending chord (C5→E5→G5) | Task completed |
| Approval | 🟢 Pulsing green | Alert beeps (A5→A5→C6) | Claude needs your permission |
| Idle | 🔵 Breathing blue | — | Connected, waiting for input |
| Offline | ⚫ Off | — | Not connected to server |
After a configurable timeout, the LED auto-dims to save power. Any new state change wakes it back up.
| Part | What it is | Price range |
|---|---|---|
| ESP32-C3 | SuperMini or DevKitM-1 | ~$3 |
| RGB LED module | Common cathode (or 3 separate LEDs + 220Ω resistors) | ~$0.50 |
| Passive buzzer | 2-pin, must be passive for tone control | ~$0.30 |
| HW-357 (TP4056) | USB-C LiPo charger/protection board | ~$0.80 |
| LiPo battery | 3.7V 300mAh (e.g. DYD 602030) | ~$2 |
| Switch | Any small on/off toggle or slide | ~$0.20 |
Total cost: under $7
Default pin mapping (change in firmware/src/config.h):
| Component | GPIO |
|---|---|
| Red LED | 3 |
| Green LED | 1 |
| Blue LED | 0 |
| Buzzer | 20 |
Heads up: GPIO 4–7 are JTAG debug pins on ESP32-C3 and won't work as outputs on most boards. Stick to GPIOs 0, 1, 2, 3, 8, 9, 10, 20, 21.
Step 1 — Battery + charger module
Place the LiPo battery on the HW-357 (TP4056) module and solder the battery wires to the B+/B- pads.
Step 2 — Power output wires
Solder output wires (red = positive, black = ground) to the OUT+/OUT- pads of the HW-357. These will power the ESP32-C3 through the switch.
Step 3 — ESP32-C3 + buzzer
Solder the passive buzzer to the ESP32-C3 SuperMini (GPIO 20 and GND). Connect the RGB LED module to the appropriate GPIO pins.
Step 4 — Final assembly
Connect everything together: battery → switch → HW-357 → ESP32-C3. The USB-C port on the HW-357 allows charging while running.
git clone https://github.com/tomymiron/StatusClawd.git
cd StatusClawd
./install.shEdit firmware/src/config.h:
#define WIFI_SSID "YourNetwork"
#define WIFI_PASSWORD "YourPassword"
#define SERVER_HOST "192.168.0.100" // your computer's local IPOpen the firmware/ folder in PlatformIO and upload to your ESP32-C3.
./start.shPaste this into your ~/.claude/settings.json:
{
"hooks": {
"SessionStart": [{
"matcher": ".*",
"hooks": [{"type": "http", "url": "http://127.0.0.1:8768/idle", "async": true, "timeout": 2}]
}],
"UserPromptSubmit": [{
"hooks": [{"type": "http", "url": "http://127.0.0.1:8768/working", "async": true, "timeout": 2}]
}],
"PreToolUse": [{
"matcher": ".*",
"hooks": [{"type": "http", "url": "http://127.0.0.1:8768/working", "async": true, "timeout": 2}]
}],
"PostToolUse": [{
"matcher": ".*",
"hooks": [{"type": "http", "url": "http://127.0.0.1:8768/working", "async": true, "timeout": 2}]
}],
"PermissionRequest": [{
"matcher": ".*",
"hooks": [{"type": "http", "url": "http://127.0.0.1:8768/approval", "async": true, "timeout": 2}]
}],
"Stop": [{
"hooks": [{"type": "http", "url": "http://127.0.0.1:8768/done", "async": true, "timeout": 2}]
}],
"Notification": [{
"matcher": "idle_prompt",
"hooks": [{"type": "http", "url": "http://127.0.0.1:8768/idle", "async": true, "timeout": 2}]
}]
}
}curl http://localhost:8768/working # Red
curl http://localhost:8768/done # Blue + melody
curl http://localhost:8768/approval # Green pulse + alert
curl http://localhost:8768/idle # Blue breathingAll tunable values live in firmware/src/config.h:
| Setting | Default | What it does |
|---|---|---|
BUZZER_VOLUME |
25 |
Volume 0–100 (0 = mute) |
INACTIVITY_IDLE |
30 |
Seconds before idle LED dims (0 = never) |
INACTIVITY_WORKING |
0 |
Seconds before working LED dims (0 = never) |
INACTIVITY_DONE |
30 |
Seconds before done LED dims |
INACTIVITY_APPROVAL |
120 |
Seconds before approval LED dims |
Zero-latency hooks — Uses "type": "http" hooks instead of command hooks. Claude Code makes the HTTP request internally with no process spawn, so state changes are near-instant (~0ms vs 3–5s with shell commands).
No timer conflicts — The buzzer generates tones 100% in software by toggling a GPIO pin with micros(). This avoids the well-documented LEDC channel conflicts on ESP32-C3 when running multiple PWM outputs simultaneously.
Auto-dim — Each state has its own inactivity timeout. After the timeout, the LED fades to off. Any new state change wakes it right back up.
MIT — do whatever you want with it.
Built with an ESP32-C3, a few LEDs, and way too many hours debugging JTAG pins.