Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

139 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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.

About

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

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages