Control WiZ smart lamps over WiFi/UDP based on Claude Code hook events. Your lamp becomes a physical status indicator — animated scenes while Claude works, solid colors when idle, purple when input is needed.
sequenceDiagram
participant Claude as Claude Code
participant Hook as wiz_hook.sh
participant State as State File
participant Daemon as wiz_daemon.ts
participant Bulbs as WiZ Bulbs
participant UI as Config UI:38900
Claude->>Hook: Event triggered
Hook->>State: Write state
Daemon->>State: Poll every 200ms
Daemon->>Bulbs: Send UDP command
Bulbs->>Daemon: Acknowledge
Daemon->>UI: Serve on :38900
| State | Default Look | Trigger |
|---|---|---|
| working | Ocean scene (animated) | Claude is thinking/using tools |
| idle | Warm mango (solid) | Claude finished, waiting for prompt |
| input | Purple (solid) | Permission needed / question asked |
| off | Lamp off | Session ended |
- Bun runtime (
curl -fsSL https://bun.sh/install | bash) - WiZ smart bulbs on the same WiFi network
- Claude Code CLI
You can add and install the plugin directly from the command line:
claude plugin marketplace add https://github.com/erhant/claude-code-wiz
claude plugin install claude-code-wizYou can use /plugin command in any Claude Code session to add and install/uninstall the plugin directly:
/plugin marketplace add https://github.com/erhant/claude-code-wiz
/plugin install claude-code-wizOr, you can clone the repo and add the plugin via its path for a single Claude session:
git clone https://github.com/erhant/claude-code-wiz.git
claude --plugin-dir /path/to/claude-code-wizThe daemon starts automatically on the first session event. Open http://localhost:38900 to discover and select your WiZ bulbs.
- Click Scan to find bulbs on your network.
- Check the bulbs you want to control.
- Click Save.
claude-code-wiz/
├── .claude-plugin/
│ └── plugin.json # Plugin manifest
├── hooks/
│ └── hooks.json # Hook event definitions
├── scripts/
│ ├── claude_wiz_hook.sh # Shell hook: writes state, starts daemon
│ ├── claude_wiz_daemon.ts # Main entry: UDP, state machine, HTTP server
│ ├── constants.ts # Shared constants, types, WIZ_SCENES
│ ├── config.ts # Config/theme I/O helpers
│ ├── discovery.ts # UDP broadcast discovery + bulb info query
│ ├── ui.ts # Config UI HTML template
│ └── themes.json # Theme config for each state
├── README.md
├── package.json
└── tsconfig.json
Open http://localhost:38900 and use the theme editor below the bulb list, or edit scripts/themes.json directly:
{
"working": { "sceneId": 4, "speed": 150, "dimming": 90 },
"idle": { "r": 0, "g": 255, "b": 100, "dimming": 50 },
"input": { "r": 255, "g": 0, "b": 0, "dimming": 100 }
}# Get current themes
curl http://localhost:38900/api/themes
# Save themes
curl -X POST http://localhost:38900/api/themes \
-H 'Content-Type: application/json' \
-d '{"working":{"sceneId":4,"speed":150,"dimming":90},"idle":{"r":0,"g":255,"b":100,"dimming":50},"input":{"r":255,"g":0,"b":0,"dimming":100}}'
# Test a theme on active bulbs (without saving)
curl -X POST http://localhost:38900/api/themes/test \
-H 'Content-Type: application/json' \
-d '{"state":"idle","params":{"r":0,"g":255,"b":100,"dimming":50}}'Set r, g, b (0-255) and dimming (10-100) for a solid color.
Set sceneId (1-35), optionally speed (10-200) and dimming (10-100).
| ID | Scene | ID | Scene | ID | Scene |
|---|---|---|---|---|---|
| 1 | Ocean | 13 | Cool white | 25 | Mojito |
| 2 | Romance | 14 | Night light | 26 | Club |
| 3 | Sunset | 15 | Focus | 27 | Christmas |
| 4 | Party | 16 | Relax | 28 | Halloween |
| 5 | Fireplace | 17 | True colors | 29 | Candlelight |
| 6 | Cozy | 18 | TV time | 30 | Golden white |
| 7 | Forest | 19 | Plantgrowth | 31 | Pulse |
| 8 | Pastel colors | 20 | Spring | 32 | Steampunk |
| 9 | Wake-up | 21 | Summer | 33 | Diwali |
| 10 | Bedtime | 22 | Fall | 34 | White |
| 11 | Warm white | 23 | Deep dive | 35 | Alarm |
| 12 | Daylight | 24 | Jungle |
Set temp (2200-6500 Kelvin) and dimming (10-100).
Bulbs not responding
- Verify bulbs are on the same WiFi network as your computer
- Check the daemon log:
cat /tmp/claude_wiz_daemon.log - Try scanning again from http://localhost:38900
Daemon not starting
- Check that Bun is installed:
bun --version - Check for errors:
cat /tmp/claude_wiz_daemon.log - Kill stale daemon:
rm /tmp/claude_wiz_daemon.pid
Port 38900 in use
- Set a different port:
export WIZ_UI_PORT=38901(before starting Claude Code)
No bulbs found during scan
- Some networks block UDP broadcast. Try adding bulbs manually to
scripts/config.json:{ "bulbs": [{ "ip": "192.168.1.42", "mac": "unknown", "active": true }] }
Rapid flickering between states
- The daemon has built-in debouncing (400ms for idle→working transitions). If flickering persists, check for conflicting hooks.
Daemon lifecycle
- PID file:
/tmp/claude_wiz_daemon.pid - State file:
/tmp/claude_wiz_state - Log file:
/tmp/claude_wiz_daemon.log - The daemon auto-shuts off after 30 minutes of idle.