Your desk-side hardware sidekick for subctl — an M5Stack ESP32 companion that watches your AI subscriptions, mirrors orchestrator state, and answers operator prompts with a button tap.
A tiny ESP32 device that sits on your desk and mirrors the state of 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
| 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 — 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.
┌─────────────────┐ BLE NUS JSON ┌──────────────────────┐
│ M5Stack CoreS3 │ ◀──────────────────▶ │ bridge/ (Bun+noble) │
│ - pet + dash │ │ - subctl state poll │
│ - btn taps │ │ - launchd supervised │
└─────────────────┘ └──────────┬───────────┘
│
▼
┌────────────────┐
│ subctl │
│ (tmux orch + │
│ rate-limit + │
│ ask inbox) │
└────────────────┘
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
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.
# 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-E4C1If subctl-buddy resolves globally (wrapper at ~/.bun/bin/subctl-buddy), just subctl-buddy install.
HANDOFF.md— full state-of-the-world, "where are we, what's next"docs/design.md— original architecture sketchdocs/handoff-subctl-surface.md— what we need from the subctl maintainer to unblock the operator-prompt path
Built by Jason Brashear (@webdevtodayjason) as part of the subctl ecosystem.
Inspired by Anthropic's 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.
MIT