https://github.com/webdevtodayjason/subctl-buddy
ESP32 desk-side hardware companion for subctl — animated pet + live dashboard for your AI subscription orchestrator. Speaks the claude-desktop-buddy BLE wire protocol.
https://github.com/webdevtodayjason/subctl-buddy
ai-agents arduino ble bluetooth-low-energy bun claude claude-code esp32 hardware-companion m5stack m5stack-cores3 nordic-uart-service platformio subctl typescript
Last synced: 1 day ago
JSON representation
ESP32 desk-side hardware companion for subctl — animated pet + live dashboard for your AI subscription orchestrator. Speaks the claude-desktop-buddy BLE wire protocol.
- Host: GitHub
- URL: https://github.com/webdevtodayjason/subctl-buddy
- Owner: webdevtodayjason
- Created: 2026-05-25T22:26:24.000Z (about 1 month ago)
- Default Branch: main
- Last Pushed: 2026-05-25T22:29:52.000Z (about 1 month ago)
- Last Synced: 2026-06-05T07:18:49.177Z (28 days ago)
- Topics: ai-agents, arduino, ble, bluetooth-low-energy, bun, claude, claude-code, esp32, hardware-companion, m5stack, m5stack-cores3, nordic-uart-service, platformio, subctl, typescript
- Language: C++
- Homepage: https://github.com/webdevtodayjason/subctl
- Size: 152 KB
- Stars: 2
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# 🐸 subctl-buddy
**Your desk-side hardware sidekick for [subctl](https://github.com/webdevtodayjason/subctl) — an M5Stack ESP32 companion that watches your AI subscriptions, mirrors orchestrator state, and answers operator prompts with a button tap.**






---
## What is this?
A tiny ESP32 device that sits on your desk and **mirrors the state of [subctl](https://github.com/webdevtodayjason/subctl)** — Jason Brashear's multi-account AI subscription orchestrator — in real time. Instead of context-switching to Telegram or a terminal to see what your fleet of Claude/Codex/etc. agents are up to, you glance at the buddy:
- 🐸 **Animated pet** on the left (bufo GIF or one of 18 ASCII species) that levels up from real output-token throughput
- 💬 **Thought-bubble dashboard** on the right with dispatch verdict, per-account chips, active conversation summary, and cost-saved-this-month
- 🔘 **Button taps** answer operator yes/no prompts — APPROVE / DENY without opening Telegram
- ⚙️ **Settings menu** for brightness, sound, demo mode, and device info
- 🔄 **launchd-supervised** bridge daemon: power-cycle the device and it auto-reconnects in <1s
## Hardware
| Device | Firmware | Status |
|---|---|---|
| **M5Stack CoreS3** | `firmware-cores3/` v0.2.0 | Primary target — full-color GIF pet, dashboard, settings menu |
| **M5StickC Plus** | `firmware/` v0.1.x | Bare dashboard only, forward-compatible with the v0.2 bridge |
Both speak the **same Nordic UART Service JSON wire protocol** as Anthropic's [`claude-desktop-buddy`](https://github.com/anthropics/claude-desktop-buddy) — the project that inspired this one. The bridge daemon translates subctl's state into that protocol and routes button taps back to subctl's notification inbox.
## Architecture
```
┌─────────────────┐ BLE NUS JSON ┌──────────────────────┐
│ M5Stack CoreS3 │ ◀──────────────────▶ │ bridge/ (Bun+noble) │
│ - pet + dash │ │ - subctl state poll │
│ - btn taps │ │ - launchd supervised │
└─────────────────┘ └──────────┬───────────┘
│
▼
┌────────────────┐
│ subctl │
│ (tmux orch + │
│ rate-limit + │
│ ask inbox) │
└────────────────┘
```
## Repo layout
```
bridge/ Bun + noble BLE central daemon (TypeScript)
firmware/ M5StickC Plus firmware (v0.1.x, Arduino/PlatformIO)
firmware-cores3/ M5Stack CoreS3 firmware (v0.2.0, full-color UI)
docs/ Design doc, integration notes, BLE investigation log
HANDOFF.md Latest session state — read this first
```
## Status
**Phase 2 shipped (2026-05-24/25).** CoreS3 runs the v0.2.0 firmware with animated pet, live dashboard, settings menu, buddy profile overlay, and a level-up loop wired to real output-token counts. Bridge daemon runs under launchd with KeepAlive + continuous BLE scan — device off/on auto-reconnects in <1s once the first-run BT permission is granted.
**Blocked on subctl-side surface:** the operator-prompt path (buddy receives a question, taps APPROVE/DENY, reply lands in subctl). Firmware is wired; waiting on `/api/asks/pending` from the subctl maintainer. See `docs/handoff-subctl-surface.md`.
## Quick start
```bash
# One-time install of the launchd-supervised daemon
# (auto-opens System Settings → Bluetooth for the one-time TCC grant):
bridge/src/cli.ts install --device subctl-E4C1
# OR run manually:
cd bridge && bun run src/cli.ts daemon --device subctl-E4C1
```
If `subctl-buddy` resolves globally (wrapper at `~/.bun/bin/subctl-buddy`), just `subctl-buddy install`.
## Read this next
- [`HANDOFF.md`](./HANDOFF.md) — full state-of-the-world, "where are we, what's next"
- [`docs/design.md`](./docs/design.md) — original architecture sketch
- [`docs/handoff-subctl-surface.md`](./docs/handoff-subctl-surface.md) — what we need from the subctl maintainer to unblock the operator-prompt path
## Credits
Built by **[Jason Brashear](https://jasonbrashear.com)** ([@webdevtodayjason](https://github.com/webdevtodayjason)) as part of the [subctl](https://github.com/webdevtodayjason/subctl) ecosystem.
Inspired by Anthropic's [**claude-desktop-buddy**](https://github.com/anthropics/claude-desktop-buddy) — the reference Bluetooth API for makers building hardware companions for Claude. subctl-buddy speaks the same wire protocol so any firmware built for claude-desktop-buddy will also light up when paired with the subctl-buddy bridge.
## License
MIT