Skip to content

danielbowne/claude-pager

Lloyd Pager 3000

"Is there a market for a pager that has one thin screen to display the command line of your coding session and two buttons for 'allow' and 'deny'?" — Lloyd Evans, Slack, moments before this was built

Yes, Lloyd. Yes there is.

What is this?

A physical status display for Claude Code built on an ESP32 with a touchscreen. It sits on your desk and tells you when Claude is waiting for you, what it's working on, and lets you approve or deny tool calls by tapping the screen.

Because alt-tabbing to your terminal is so 2025.

Features

  • YOUR TURN — big yellow banner when Claude is done and waiting for input
  • Task list — live view of Claude's todo list with color-coded status
  • Approve / Deny — tap to approve tool calls from across the room (or the couch)
  • Session info — model name, git branch, context window %, and version
  • Touch navigation — swipe between Status, Tasks, and Info screens
  • Auto-reconnect — WiFi and MQTT reconnect on dropout

Screenshots

Status Screen Approval Flow Your Turn
Status Approval Your Turn

Hardware

  • Waveshare ESP32-S3-Touch-LCD-3.5 (~$25)
    • ESP32-S3, 320x480 IPS touchscreen, WiFi, USB-C
    • ST7796 display driver, FT6336 capacitive touch
  • That's it. One board. One USB cable.

Architecture

Claude Code                        ESP32 Pager
    |                                  |
    |-- [Stop hook] ------------------>|
    |   publishes status via MQTT      |  shows YOUR TURN + tasks
    |                                  |
    |-- [PreToolUse hook] ------------>|
    |   publishes approval request     |  shows APPROVE / DENY
    |                                  |
    |<-- [MQTT response] --------------|
    |   reads approve/deny             |  you tap the screen
    |                                  |

        Mosquitto MQTT Broker
        (Docker container)

Quick Start

1. Start the MQTT broker

docker compose up -d

2. Configure WiFi and MQTT

cp esp32/include/config.h.example esp32/include/config.h

Then edit esp32/include/config.h with your values:

#define WIFI_SSID     "your-wifi"
#define WIFI_PASSWORD "your-password"
#define MQTT_HOST     "192.168.x.x"  // your machine's LAN IP

The real config.h is gitignored so your credentials stay local.

3. Flash the ESP32

# Install PlatformIO
uv tool install platformio

# You may need serial port access
sudo usermod -aG dialout $USER  # then log out/in

# Build and flash
cd esp32
pio run -t upload

4. Install the Claude Code hooks

Add to ~/.claude/settings.json:

{
  "hooks": {
    "Stop": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/claude-pager/hooks/claude-pager.sh"
          }
        ]
      }
    ],
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/claude-pager/hooks/claude-approve.sh"
          }
        ]
      }
    ]
  }
}

5. Install mosquitto-clients and jq

Linux (Debian/Ubuntu):

sudo apt install mosquitto-clients jq

macOS:

brew install mosquitto jq

The mosquitto-clients package provides mosquitto_pub and mosquitto_sub which the hook scripts use to talk to the broker. jq is used to build and parse JSON payloads.

6. Done

Start a Claude Code session. The pager lights up.

Testing without hardware

# Terminal 1: watch messages
./scripts/test-subscribe.sh

# Terminal 2: send a fake status update
./scripts/test-publish.sh

Project Structure

claude-pager/
├── docker-compose.yml           # Mosquitto MQTT broker
├── mosquitto/config/
│   └── mosquitto.conf           # Broker config
├── hooks/
│   ├── claude-pager.sh          # Stop hook → publishes status
│   └── claude-approve.sh        # PreToolUse hook → approval flow
├── esp32/
│   ├── platformio.ini           # PlatformIO build config
│   ├── include/config.h         # Pin defs, WiFi, MQTT settings
│   └── src/main.cpp             # The firmware
├── scripts/
│   ├── test-publish.sh          # Simulate Claude status
│   └── test-subscribe.sh        # Monitor MQTT messages
└── screenshots/

MQTT Topics

Topic Direction Purpose
claude/status Hook → ESP32 Status updates (waiting, tasks, model info)
claude/approval/request Hook → ESP32 Tool approval requests
claude/approval/response ESP32 → Hook Approve/deny responses

Status Line Integration

The pager reads model, branch, and context window data from Claude Code's status line. If you use a custom statusline.sh, add this before the final echo:

jq -n \
  --arg model "$MODEL" \
  --arg branch "$BRANCH" \
  --arg version "$VERSION" \
  --arg context_left "$PERCENT_LEFT" \
  '{model: $model, branch: $branch, version: $version, context_left: $context_left}' \
  > /tmp/claude-pager-info.json 2>/dev/null &

Home Assistant Bonus

Since it's MQTT, you can also add Claude's status as a Home Assistant sensor:

mqtt:
  sensor:
    - name: "Claude Code Status"
      state_topic: "claude/status"
      value_template: "{{ value_json.status }}"

Then automate your office lights to flash when Claude needs you. Because why not.

Origin Story

This whole thing started when Lloyd posted in Slack asking if there was a market for a pager with a screen and two buttons. There wasn't a product, so we built one in a single Claude Code session. The entire project — broker, firmware, hooks, approval flow — was written in one conversation.

Lloyd, this one's for you.

License

MIT — do whatever you want with it.

About

Lloyd Pager 3000 — ESP32 touchscreen status display for Claude Code. Approve/deny tool calls from anywhere with WiFi.

Topics

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors