An open API service indexing awesome lists of open source software.

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.

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.**

![Platform](https://img.shields.io/badge/platform-ESP32-blue?logo=espressif&logoColor=white)
![Hardware](https://img.shields.io/badge/hardware-M5Stack%20CoreS3%20%2F%20StickC%20Plus-orange)
![Bridge](https://img.shields.io/badge/bridge-Bun%20%2B%20TypeScript-black?logo=bun&logoColor=white)
![Transport](https://img.shields.io/badge/transport-BLE%20NUS-5E5DF0?logo=bluetooth&logoColor=white)
![Status](https://img.shields.io/badge/status-Phase%202%20shipped-success)
![License](https://img.shields.io/badge/license-MIT-lightgrey)

---

## 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