Inspiration

I'm not a programmer — I run my projects entirely through AI coding agents (Claude Code). That's great for speed, but it means I can't personally judge whether a command an AI is about to run is safe. A single unreviewed rm -rf or force-push could wipe out real work, and I'd have no way to know until it was too late. I wanted a guardian that didn't require me to understand code — one that watches the AI on my behalf, in a way that's impossible to ignore and doesn't read like a compliance dialog.

The idea landed on a desktop pet: a cat that lives on screen, blocks danger in real time, and — instead of a boring system alert — roasts my bad habits in a speech bubble once the session ends, like a blunt senior engineer looking over my shoulder.

How I built it

The safety logic runs as two Claude Code hooks, both pure stdlib Python so they have zero dependency on the pet's UI:

  • A PreToolUse guard that pattern-matches every Bash command before it executes and hard-blocks a fixed set of destructive patterns — force pushes, hard resets, unscoped deletes, DROP TABLE/TRUNCATE, --no-verify, recursive chmod 777, fork bombs, raw writes to block devices.
  • A Stop hook that runs after each session and scans for four anti-patterns, reporting the first one it finds: the same command retried 3+ times without reading the error, the same file re-read 3+ times, an unscoped full-disk find/grep, or a long session (400+ lines) that never wrote a handoff doc.

Both write into a shared status queue that the desktop pet reads to display as a speech bubble next to the cat, instead of a plain OS notification.

For the pet itself, I first tried building it from scratch in Python/Tkinter. I later switched the rendering to an open-source Electron project ("Clawd on Desk") with genuine transparency support, and I'm patching it to add a POST /say endpoint that calls its existing bubble-rendering function so the supervisor's roasts show up right next to the cat, with custom art for its different moods.

Challenges I ran into

The hardest problem was transparency, not logic. On this machine, tcl-tk 9.0.4 flattens every RGBA image's alpha channel to opaque black when rendering — true even when bypassing Tk entirely and drawing straight into an AppKit NSImageView. I verified this at the pixel level twice before accepting it wasn't fixable at the app-code level.

Along the way I did solve a real fullscreen click-through bug: on macOS, overrideredirect(True) alone doesn't clear the underlying NSWindowStyleMaskTitled bit — you have to reach into the native NSWindow via PyObjC and force NSWindowStyleMaskBorderless, and switch the whole app's activation policy to NSApplicationActivationPolicyAccessory to sit above fullscreen Spaces, and only call overrideredirect after the window's first update() — get any one of the three wrong and the window either shows a title bar, hides behind fullscreen apps, or never renders at all.

Even with that fixed, the result still looked like a "boxed" window rather than a real floating character, and the macOS notification fallback I built as a stopgap has a color-contrast bug I can't control from script level (light text on light background in some system themes). Both pushed the decision to stop fighting the rendering layer and build on top of an existing, real transparent-window implementation instead — the lesson being: know when a platform limitation isn't a bug to debug further, but a signal to change tools.

Built With

Share this project:

Updates