https://github.com/alenoc/clawdbox
ESP32-S3-BOX desk monitor for Claude Code API usage - polls Anthropic rate-limit headers over WiFi, no host daemon
https://github.com/alenoc/clawdbox
anthropic claude claude-code esp32 esp32-s3 iot lvgl oauth platformio rate-limit
Last synced: about 1 month ago
JSON representation
ESP32-S3-BOX desk monitor for Claude Code API usage - polls Anthropic rate-limit headers over WiFi, no host daemon
- Host: GitHub
- URL: https://github.com/alenoc/clawdbox
- Owner: ALENOC
- License: mit
- Created: 2026-05-16T12:42:37.000Z (about 1 month ago)
- Default Branch: main
- Last Pushed: 2026-05-20T21:57:31.000Z (about 1 month ago)
- Last Synced: 2026-05-22T08:00:03.914Z (about 1 month ago)
- Topics: anthropic, claude, claude-code, esp32, esp32-s3, iot, lvgl, oauth, platformio, rate-limit
- Language: C
- Size: 6.68 MB
- Stars: 4
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Clawdbox
A desk-side Claude Code usage monitor running on an **[Espressif ESP32-S3-BOX](https://github.com/espressif/esp-box)**.
Connects to WiFi and polls the Anthropic API directly - no host daemon, no companion app. OAuth tokens are obtained and refreshed on-device via a QR-code pairing flow.
The splash screen plays pixel-art Clawd animations sourced from [claudepix](https://claudepix.vercel.app). Animation intensity tracks your live usage rate.
---
## Screenshots
| Splash | Usage | Network | Settings |
|--------|-------|---------|----------|
|  |  |  |  |
---
## Photos

---
## Screens
| Screen | Description |
|--------|-------------|
| **Splash** | Boot screen with Clawd pixel-art animation, UTC clock, usage rate ticker |
| **Usage** | 5h session % and 7d weekly % with progress bars, reset timers, live clock |
| **Network** | WiFi state, IP address, OAuth status, Reset config zone |
| **Settings** | Brightness, auto-standby, night mode schedule, timezone offset |
Press **BOOT** to cycle screens. Tap anywhere on the splash to hide/show it. Long-press BOOT (>5 s) to factory reset.
---
## Hardware
All three Espressif ESP32-S3-BOX variants are supported:
| Variant | Display | Touch | Backlight GPIO |
|---------|---------|-------|----------------|
| **[ESP32-S3-BOX](https://github.com/espressif/esp-box)** (original, ~2022) | ILI9342C 320×240 IPS | TT21100 | GPIO 45 |
| **[ESP32-S3-BOX-Lite](https://github.com/espressif/esp-box)** (~2022, no touch) | ST7789 320×240 IPS | none | GPIO 45 |
| **[ESP32-S3-BOX-3](https://github.com/espressif/esp-box)** (~2023, latest) | ILI9342C or ST7789 | GT911 or TT21100 | GPIO 47 |
BOX-3 display driver and touch controller are detected at runtime via I2C probe (mirrors the Espressif BSP auto-detect logic).
### Why ESP32-S3-BOX
The ESP32-S3-BOX family is an **official Espressif product** - not a third-party board. This means a stable, well-documented BSP, long-term availability, and a known-good hardware reference for all three variants.
The more important reason for a desk monitor, though, is the display technology.
**IPS LCD, not AMOLED.** All BOX variants use IPS LCD panels. Competing ESP32 display boards (such as the Waveshare AMOLED series) use AMOLED. For a device that sits on your desk and is on most of the day, this matters:
| | IPS LCD (this device) | AMOLED |
|---|---|---|
| **Burn-in / image retention** | None - backlight is uniform, pixels do not age unevenly | Organic pixels degrade under sustained static content; logos and progress bars burn in over months |
| **Brightness decay** | Negligible over years of use | Organic emitters dim measurably over thousands of hours |
| **Always-on viability** | Yes | No - requires aggressive screen savers, short timeouts, or content rotation to slow degradation |
| **Replacement cost** | Low - commodity panel | Higher - proprietary AMOLED module |
A usage monitor is by definition static content: the same layout, the same progress bars, the same clock position, always in the same spot on your desk. That is exactly the workload that ages AMOLED panels fastest. IPS LCD has no organic emitters and no burn-in mechanism - it will look the same in three years as it does on day one.
The auto-standby and night-mode features (Settings screen) exist to reduce unnecessary backlight hours, but the display is fundamentally safe to leave on indefinitely.
- USB-C cable for flashing
## Prerequisites
- [PlatformIO CLI](https://docs.platformio.org/en/latest/core/installation/index.html)
- Active Claude Code / Anthropic subscription (OAuth tokens obtained via on-device QR flow)
---
## Flash
Select the environment matching your hardware:
```bash
# ESP32-S3-BOX (original)
pio run -d firmware -e s3box -t upload --upload-port /dev/ttyACM0
# ESP32-S3-BOX-Lite
pio run -d firmware -e s3box_lite -t upload --upload-port /dev/ttyACM0
# ESP32-S3-BOX-3
pio run -d firmware -e s3box3 -t upload --upload-port /dev/ttyACM0
```
---
## First-boot setup
1. Fresh flash → device starts AP **`Clawdbox-setup`** (open, no password).
2. Connect to the AP; captive portal opens at `http://192.168.4.1/`.
3. Enter SSID and WiFi password. Submit → device reboots into STA mode.
4. Device connects to WiFi and shows a **QR code** plus a LAN URL (`http:///pair`) on screen.
5. Scan the QR → `claude.ai` OAuth authorization page opens. Authorize.
6. After authorizing, the callback page shows a **`CODE#STATE`** string. Copy it.
7. Navigate to `http:///pair` (shown on screen), paste the `CODE#STATE`, submit.
8. Device exchanges the code for tokens (PKCE), saves them to NVS, and reboots.
9. From now on the device refreshes tokens autonomously (~every 15 min).
---
## Settings (Network screen)
| Setting | Description |
|---------|-------------|
| **Backlight** | PWM brightness slider |
| **Auto-standby** | Turns off the display after the configured idle timeout. Must be enabled for any standby to occur. |
| **Night only** | Restricts auto-standby to a configured hour range (e.g. 22h-7h local time). Requires **Auto-standby** to also be enabled. When both are on, the display turns off after the idle timeout only if the current local time falls within the night window. Device auto-wakes when the window ends. |
| **Timezone** | UTC offset (±h); auto-detected from IP on first WiFi connect via ip-api.com. Used by the Night only window. |
**Standby logic summary:**
| Auto-standby | Night only | Behaviour |
|:---:|:---:|---|
| off | any | Display never turns off |
| on | off | Display turns off after idle timeout, at any hour |
| on | on | Display turns off after idle timeout, only within the night window |
---
## Why WiFi, not Bluetooth
The [original Clawdmeter](https://github.com/HermannBjorgvin/Clawdmeter) uses Bluetooth to receive usage data relayed from the host machine. This approach has a fundamental architectural flaw: **the device is completely dependent on the host being awake, unlocked, and running a companion daemon**. The moment you lock your screen, close the lid, or switch machines, the link breaks and the monitor goes stale. It also requires installing software on every machine you use.
This project takes a radically different approach: the device connects directly to the Anthropic API over WiFi, with no host involvement whatsoever.
| | WiFi - this device | Bluetooth - original Clawdmeter |
|---|---|---|
| **Host dependency** | **None** - polls Anthropic directly | Requires companion app on every host |
| **Works when host sleeps** | **Yes** - always live | No - goes dark when host locks |
| **Works when host is off** | **Yes** | No |
| **Multi-machine** | **Yes** - follows your account, not your laptop | No - tied to the one paired host |
| **Rate-limit data source** | **Official API response headers** - authoritative | Scraped from CLI - fragile, breaks on updates |
| **Token refresh** | **On-device, autonomous** | Host must relay credentials |
| **Setup friction** | One-time portal + OAuth QR scan | Pair per machine, install and maintain daemon |
| **Licensing overhead** | None | Bluetooth product qualification requires **Bluetooth SIG membership and royalties** |
The Bluetooth SIG requires that any product using the Bluetooth trademark or standard undergo a qualification and listing process. For commercial products this involves fees; even for open-source projects, the compliance burden (QDID, Declaration ID, listing) is non-trivial and constrains redistribution.
WiFi with direct API polling sidesteps all of that. The only trade-off is that WiFi requires network access and OAuth tokens are stored on the device. See the [Security note](#security-note) below.
---
## How it works
1. Connects to WiFi; NTP syncs the clock.
2. Timezone auto-detected via `http://ip-api.com/json` on first connect; saved to NVS.
3. Every 60 s (while active): POST 1-token probe to `https://api.anthropic.com/v1/messages`, read rate-limit headers (`anthropic-ratelimit-unified-5h-utilization`, `-5h-reset`, `-7d-utilization`, `-7d-reset`). Polling pauses while the display is in standby; on wake, a fresh poll fires immediately.
4. OAuth token nearing expiry → POST to `https://console.anthropic.com/v1/oauth/token` with refresh token; rotated pair persisted to NVS.
5. Splash animation group selected by current usage-rate (usage % change over sliding window).
---
## Physical buttons
| Button | GPIO | Function |
|--------|------|----------|
| **BOOT** | 0 | Cycle screens; long-press >5 s → factory reset |
| **Mute slider** | 1 | Manual poll trigger |
---
## TLS
All HTTPS connections verify against root CA certificates in `firmware/src/anthropic_ca.h`. This file is **auto-generated at build time** by `firmware/tools/fetch_ca.py` - you never edit it by hand.
| Endpoint | Root CA |
|----------|---------|
| `api.anthropic.com` | GlobalSign Root CA (via GTS Root R4) |
| `console.anthropic.com` | ISRG Root X1 (Let's Encrypt) |
The pre-build script follows the AIA chain from each endpoint to locate the correct root CA, downloads it, verifies the fingerprint, and writes the PEM bundle before compilation. If Anthropic rotates their CA, rebuilding with network access picks up the new cert automatically.
---
## Security note
OAuth tokens are stored in NVS in plaintext. Anyone with USB access can extract them with `esptool.py read_flash`. Before lending, gifting, or recycling the device: long-press BOOT >5 s (or tap **Reset config** on the Network screen) and revoke the token at .
---
## Recompiling fonts
Fonts are pre-compiled LVGL 9 bitmap files in `firmware/src/font_*.c`. To regenerate:
```bash
npm install -g lv_font_conv
for size in 28 20; do
lv_font_conv --font assets/StyreneB-Regular.otf -r 0x20-0x7E \
--size $size --format lvgl --bpp 4 --no-compress \
-o firmware/src/font_styrene_${size}.c --lv-include "lvgl.h"
done
```
Each generated file needs LVGL 9 patching: remove `#if LVGL_VERSION_MAJOR >= 8` guards, drop `.cache`, add `.release_glyph`, `.kerning`, `.static_bitmap`, `.fallback`, `.user_data`.
## Splash animations
```bash
node tools/scrape_claudepix.js # fetch sprites → tools/claudepix_data/*.json
node tools/convert_to_c.js # → firmware/src/splash_animations.h
```
## Converting icons
```bash
node tools/png_to_lvgl.js [W_MACRO] [H_MACRO] [--tint=RRGGBB | --no-tint]
```
Default tint is white. Pass `--no-tint` for pre-coloured artwork.
---
## Disclaimer
**This project is an independent, unofficial, non-commercial community tool created for personal use. It is not affiliated with, endorsed by, sponsored by, approved by, or in any way connected to Anthropic, PBC or any of its subsidiaries or affiliates.**
### Independence
This project was developed independently, without access to any non-public information, internal APIs, or proprietary documentation belonging to Anthropic, PBC. All API usage is based solely on Anthropic's publicly documented interfaces.
### Trademarks
Claude™ and Anthropic™ are registered trademarks of Anthropic, PBC. All rights are reserved by their respective owners. References to these names in this repository are made solely for the purpose of nominative fair use - to accurately describe interoperability with Anthropic's publicly available API - and constitute neither a claim of association nor an implied licence of any kind. No sponsorship, endorsement, or affiliation is suggested or implied.
### Artwork
The pixel-art animations included in this firmware are fan-made, community-created works sourced from [claudepix.vercel.app](https://claudepix.vercel.app) and attributed to [@amaanbuilds](https://x.com/amaanbuilds). They are **not** official Anthropic assets and are reproduced here solely for non-commercial, personal use under fair use principles. The author of this project asserts no ownership over these works and makes no representations regarding their intellectual property status. Use of this firmware does not grant any rights to the underlying artwork.
### API usage and costs
This device makes real API calls to `api.anthropic.com` every 60 seconds while active. Each poll sends a minimal 1-token probe to `claude-haiku` solely to read rate-limit response headers - actual token consumption is negligible (≈ 2 tokens/minute while awake). Polling is suspended automatically while the display is in standby, so no API calls are made while the device is idle overnight. **You are solely and exclusively responsible** for any charges, quota consumption, rate-limit violations, or Terms of Service violations arising from your use of this firmware. Review Anthropic's [Usage Policy](https://www.anthropic.com/legal/usage-policy) before deploying. The author accepts no liability for any costs incurred.
### Security
OAuth tokens are stored unencrypted in the device's NVS flash. **You are solely and exclusively responsible** for the physical security of the device and for revoking credentials promptly if the device is lost, stolen, transferred, resold, or discarded. To revoke: visit . The author accepts no liability for unauthorised access to your Anthropic account resulting from use of this firmware.
### No warranty / limitation of liability
This software is provided **"as is"**, without warranty of any kind, express or implied, including but not limited to warranties of merchantability, fitness for a particular purpose, and non-infringement. In no event shall the author be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including but not limited to procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise), arising in any way out of the use of this software, even if advised of the possibility of such damage. See the full [MIT License](LICENSE).
---
## Credits
- Inspired by [Clawdmeter](https://github.com/HermannBjorgvin/Clawdmeter) by [@HermannBjorgvin](https://github.com/HermannBjorgvin).
- Pixel-art Clawd animations by [@amaanbuilds](https://x.com/amaanbuilds) via [claudepix.vercel.app](https://claudepix.vercel.app).
- Lucide icon set ([lucide.dev](https://lucide.dev), MIT).