tamaclaude

skill
Security Audit
Fail
Health Pass
  • License — License: MIT
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Community trust — 11 GitHub stars
Code Fail
  • rm -rf — Recursive force deletion command in host/Scripts/make-app.sh
  • rm -rf — Recursive force deletion command in host/Scripts/make-dmg.sh
Permissions Pass
  • Permissions — No dangerous permissions requested

No AI report is available for this listing yet.

SUMMARY

Desk device that mirrors live Claude Code session state onto a Cheap Yellow Display over BLE

README.md

TamaClaude

Tamagotchi + Claude — a virtual pet whose moods are your coding sessions.

macOS 14+ Swift 6.0 ESP-IDF v5.5 ESP32-2432S028R BLE with a Wi-Fi fallback MIT license

🌐 English · ไทย

What the screen says · What you need · Getting started · Troubleshooting

Before you start

  • macOS only. The app that talks to Claude Code is a Swift menu bar app for macOS 14
    or newer. There is no Linux or Windows build, and the firmware alone does nothing
    without it.
  • Unofficial. A personal hobby project, not affiliated with or endorsed by Anthropic.
    "Claude" and "Claude Code" belong to them.
  • As-is. Flashing firmware overwrites whatever is on the board, and you do it at your
    own risk. No warranty — see LICENSE.
  • Reading your quota from claude.ai is optional and needs an account credential. Read
    step 5 before you turn it on.

A desk device that shows what Claude Code is doing right now. A blocky orange mascot
lives on a small screen next to your keyboard: it types when Claude types, waves when a
session needs your answer, and celebrates when a build finishes. The bars at the bottom
are your Claude usage quota.

Three sessions working, cards stacked on the right, quota bars at the bottom The menu bar panel: session usage, weekly usage, and the board's state

The board, and the menu bar app that feeds it.

Nothing leaves your network. A menu bar app on your Mac reads Claude Code's hooks and
pushes a small snapshot to the board over Bluetooth LE — and, if you set up Wi-Fi, over
your own LAN as a sealed fallback when Bluetooth goes quiet. The board never talks to
claude.ai.

What the screen says

While a session runs

Busy Waiting for you Done
busy waiting done
Up to three sessions and the tool each one is using. A session stopped and wants an answer. The mascot celebrates a finished turn.

When nothing is happening

Idle No sessions Offline
idle empty offline
One session, sleeping. Night sky and clock. The mascot strolls. Clock and date. The Mac is out of range or the app is not running.

Quota

Normal Running hot Unknown
usage usage hot usage unknown
The current 5-hour window and the weekly one. Near the limit; the tick marks your pace against the clock. --, never a guess, when no number has arrived.

Over Wi-Fi

Still live Nobody feeding it
lan wifi
Bluetooth is gone, so the label is the board's IP and the icon is a wave — but the snapshot still arrives, sealed, over the network. The board is on the network with nothing to show: the Mac is asleep or the app is not running.

What you need

Hardware

  • An ESP32-2432S028R board — the "Cheap Yellow Display", 2.8" 320x240, roughly 300 baht.
    Tested against ESP32-D0WD-V3 rev 3.1, 4 MB flash, no PSRAM.
  • A USB data cable for the board's micro-USB port. Charge-only cables do not enumerate.

Buy the ESP32 2.8" board on Shopee

Mac

  • macOS 14 or newer, with Bluetooth.
  • Claude Code installed and logged in.

The Mac app is always built from source. The firmware you can either download or build —
step 2 has both routes.

1. Get the repository and the Swift compiler

xcode-select --install
git clone https://github.com/thaitop/tamaclaude.git
cd tamaclaude

2. Put the firmware on the board

Plug the board in and put its serial port into a variable, so the commands below work
as written:

PORT=$(ls /dev/cu.usbserial-* | head -1)
echo "$PORT"

That should print one path, something like /dev/cu.usbserial-1420 — the number differs
from board to board and from port to port, which is why nothing below spells it out. If
it prints nothing, see Troubleshooting.

PORT only exists in the terminal window you typed it in; if you open a new one, set it
again.

Option A — flash a ready-made image (no ESP-IDF)

Download tamaclaude-esp32-*.bin from the
latest release. It is one file,
about 1 MB, containing the bootloader, the partition table and the app.

python3 -m pip install esptool
python3 -m esptool --chip esp32 --port "$PORT" \
    write_flash 0x0 ~/Downloads/tamaclaude-esp32-1.0.4.bin

That is the whole toolchain: about 10 MB of Python, no compiler. Skip to step 3.

Option B — build it yourself

Take this route if you want to change the firmware, or if your board turns out to need
different panel settings.

Build tools:

brew install cmake ninja dfu-util python3

ESP-IDF — this is the big one, roughly 2 GB. v5.5 is what this firmware is built and
tested against; the component manifest accepts 5.4 and newer:

mkdir -p ~/esp && cd ~/esp
git clone -b v5.5 --recursive https://github.com/espressif/esp-idf.git
cd esp-idf && ./install.sh esp32

Then, from the repository, load the toolchain into your shell and flash:

cd firmware
. $HOME/esp/esp-idf/export.sh
idf.py -p "$PORT" flash monitor

The export.sh line is per-shell and is not permanent; open a new terminal and you run
it again. The first build takes several minutes. If anything here goes wrong, Espressif's
own getting-started guide
is the authority.

Either way

The screen lights up and the board starts announcing itself over Bluetooth as
tamaclaude-3f7a — the last part comes from its MAC address, so you can tell two boards
apart. With idf.py monitor running you can watch it happen; press Ctrl+] to leave.

3. Install the Mac app

cd ../host
./Scripts/make-app.sh --install

This builds TamaClaude.app, copies it to /Applications, and launches it. macOS asks
for Bluetooth permission the first time — say yes, or the app can never see the board.

A small mascot icon appears in your menu bar. Click it for the quota panel; click the
gear for settings. The foot of the panel tells you whether the board is connected and
what each session is doing.

The badge next to the icon is your session usage, and it turns red when you are burning
through the window faster than the clock is.

4. Connect it to Claude Code

Everything below is in gear ▸ Settings… ▸ General:

  • Install hooks in settings.json — this is the one that matters. It teaches
    Claude Code to tell the app what it is doing. Nothing appears on the board without it.
    Your existing settings are kept, and a backup is written beside the file.
  • Board — pick your board by name, or leave it on Any board.
  • Brightness — the slider drives the screen's backlight.
  • Launch at login — so it is running before you start work.

Start a Claude Code session in any terminal. Within a second or two the mascot should
start moving.

5. Quota on the board

The bars at the bottom of the screen have two independent sources, both optional:

  • Read quota from the statusline (Settings ▸ General) installs a Claude Code statusline
    that hands the app your current usage. It needs no password, but it only updates while
    Claude Code is running.
  • Set session key… (Settings ▸ General) lets the app ask claude.ai directly, so the
    number keeps moving even with Claude Code closed. Refresh quota then chooses how
    often (Off / 60s / 5 min).

About the session key. It is the sessionKey cookie of a logged-in claude.ai
browser session, and it is a full-account credential — anyone holding it can act as
your account. The app stores it in ~/.tamaclaude/session-key with mode 600 and never
puts it in a command line, an environment variable, or a log. Take it out at any time
by deleting that file, and revoke it by logging out of claude.ai in the browser you
copied it from. If you would rather not, skip this — the statusline route above still
shows a number.

To get one: in your browser, open claude.ai while logged in → DevTools → Application →
Cookies → claude.ai → copy the value of sessionKey.

Taking over the statusline slot never changes what you see: your own statusline command is
handed the same input and its output is printed as is. If you never had one, the app draws
this instead — the same elements, colours, and ~/.claude/statusline-config.txt as the
statusline that ships with Claude Usage.

The statusline the app draws: directory, branch, model, changed lines, token count, then the 5-hour and weekly quota bars with a pace mark and a reset countdown

6. Wi-Fi, so the screen survives Bluetooth (optional)

Bluetooth is the main path and always wins. It also drops — you walk past the board, the
Mac half-sleeps — and until now that left a frozen screen. Put the board on your network
and the app keeps feeding it when Bluetooth has been quiet for ten seconds.

gear ▸ Settings… ▸ Wi-Fi, with the board in Bluetooth range:

  1. The list fills in as the board scans — not your Mac, so what you see is what the
    board can actually reach. It is 2.4 GHz only; a 5 GHz-only network will not appear.
  2. Pick a network, type the password, Connect. macOS pairs with the board the first
    time; there is no six-digit code to enter.
  3. It says Connected to <name> with the board's address. The board remembers up to five
    networks and comes back on its own after a power cut.

You do not have to configure anything on the Mac side. The snapshot is sealed with
AES-256-GCM under a key the app generates and pushes to the board over the same encrypted
channel as your Wi-Fi password, and the board is found over mDNS — the address box at the
bottom of the tab is only for networks that filter it.

The board still never talks to claude.ai; your session key never leaves the Mac.

Troubleshooting

No /dev/cu.usbserial-* when the board is plugged in.
Usually the cable — many micro-USB cables carry power only. Failing that, the board's
USB-serial chip (CH340) may need a driver on older macOS releases.

Flashing stops at "Connecting........".
Hold the BOOT button on the board, start idf.py flash, and release it once the log
says Connecting. Also close any serial monitor still holding the port.

The screen is on but the colours are wrong, or the image is mirrored.
Some batches of this board ship a different panel than the one this firmware was measured
against. Run the probe project in firmware/probe/ to read out what your panel actually
reports, then change the two constants it disagrees with in firmware/main/ct_lcd.c:
the 0x36 (MADCTL) value for orientation and mirroring, and 0x20 (inversion off) versus
0x21 (inversion on) for inverted colours.

The board never shows up in the Board menu.
Check that the app has Bluetooth permission in System Settings → Privacy & Security →
Bluetooth, that the board is powered, and that nothing else is connected to it — the
firmware accepts exactly one connection at a time.

macOS asks for Bluetooth permission again after every rebuild.
Expected. The app is signed ad-hoc, so each build is a new identity as far as macOS is
concerned. There is no way around it without an Apple Developer ID.

The mascot never moves.
The hooks are probably not installed — Settings ▸ General → Install hooks in
settings.json
. Sessions already open when you install them keep the old settings; start
a new one. Open log in the same tab shows what the app is receiving.

The Wi-Fi list stays empty, or the spinner never stops.
Wi-Fi is set up over Bluetooth, so the board has to be connected first — the tab says so
when it is not. The list only ever holds 2.4 GHz networks.

The board is on the network and pings, but the screen still freezes when Bluetooth
goes.

macOS 15 and newer ask for Local Network permission separately, and a refusal silences
both mDNS and direct connections with no error at all. System Settings ▸ Privacy &
Security ▸ Local Network.

Known limits

  • macOS only. The app that talks to Claude Code is a Swift menu bar app; there is no
    Linux or Windows build.
  • No over-the-air updates. New firmware means plugging the USB cable back in.
  • The touchscreen and speaker are unused. The panel is touch-capable and the board has
    a speaker pin; neither is wired up yet.
  • Ad-hoc signing. The app is not notarised, so it is built per-machine rather than
    handed around.

License

MIT — see LICENSE.

Reviews (0)

No results found