Skip to content

KetanSomvanshi/rocky

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

29 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🐾 Rocky

A floating pixel-cat desktop pet for Claude Code. Rocky sits on top of your screen as a single animated cat whose mood reflects what your Claude Code sessions are doing β€” click it to see every session and jump straight to the one that needs you.

Native Swift/AppKit. Single ~190 KB binary, no dependencies, near-zero CPU when idle. macOS only.

Rocky floating over a code editor: the pet reacts as a session needs permission, then expands into session tabs when clicked

Rocky floats on top of whatever you're working in. Its mood tracks your Claude Code sessions β€” click it to reveal them all and jump to the one that needs you.
πŸ”΄ needs permission Β· 🟒 your turn Β· πŸ”΅ working Β· βšͺ idle

It sits on top of your work

A single frosted, always-on-top widget β€” no window to manage, no tab to hunt for. Collapsed it's just the pet; click it and the sessions fan out.

Rocky collapsed β€” a small pet floating in the corner of a code editor with an alert badge Rocky expanded β€” floating over the editor, showing one tab per session

The widget, up close

collapsed pet with session-count badge Β Β Β Β  expanded: hero pet plus a tab per session

Even while you're away

Rocky ships an optional screen saver too: step away and your Mac shows the cat, a live clock, and every session's status β€” with a soft glow when one needs you. Glance across the room and know if a session is blocked, without unlocking.

Rocky screen saver: a centered card with a clock, the pet, and a list of sessions, glowing red because one needs permission

What it does

  • One hero pet (a ginger cat named Rocky) sits on your screen and animates with your overall mood β€” priority order: needs-permission β€Ί your-turn β€Ί working β€Ί idle. A small badge shows the session count, turning red/green when a session needs you.
  • Moods (hand-animated pixel art):
    • a walk cycle with a springy tail β€” and a tiny keyboard tapping away β€” while Claude is working
    • a happy bounce when a session finishes ("your turn")
    • a shake with a πŸ”’ padlock when a session needs permission
    • curls up breathing with a z when everything's idle, then stretches awake when work resumes
    • a sparkly all-clear celebration when the last busy session goes quiet
  • Click the pet to reveal the session tabs β€” they fan out with a staggered animation, one row per running session with a colour-coded status dot (πŸ”΄ needs permission Β· 🟒 your turn Β· πŸ”΅ working Β· βšͺ idle), its name, and status. Click a tab to jump straight to that session's terminal tab. Click the pet again to collapse.
  • Each tab tells the story, not just the state:
    • a transcript peek of what a session is actually doing or asking ("Finished the migration β€” want me to run the tests?") when it needs you,
    • an elapsed timer ("needs permission Β· 4m"), with a stronger pulse and a re-nudge when a session's been blocked too long (interval tunable from the right-click menu β€” "Re-nudge Interval" β€” default 2 minutes, or off),
    • and a tiny activity sparkline so busy-vs-idle is obvious at a glance.
  • Alerts when a session finishes or needs permission: a colored ring ripples out from the pet, its row pulses with a matching glow (green = done, red = needs permission), and a sound plays β€” all in Rocky itself, no macOS toast/banner. Nothing fires for routine tool calls. Rocky never dings for state it just discovered on launch β€” only for things that changed while it was watching (see Preferences to tune or silence this).
  • A tiny preferences layer, entirely in the right-click menu β€” no config file, no settings window (see Preferences).
  • Self-checks itself: the right-click menu always shows whether hooks are wired and whether Claude's session registry is readable, so a silent "why did the cat disappear" never happens without an answer.

Requirements

  • macOS (Apple Silicon or Intel), macOS 12+.
  • Xcode Command Line Tools for swiftc (xcode-select --install).
  • Claude Code installed.
  • Terminal: Warp, iTerm2, Terminal.app, kitty (with remote control), VS Code, Cursor, or tmux in any host for click-to-exact-tab focus (other terminals still show sessions; click activates the app, and the tab says so).

Install

Homebrew (recommended)

brew install ketansomvanshi/tap/rocky
rocky-setup                 # connect Rocky to Claude Code's hooks
brew services start rocky   # launch now + at login

Homebrew compiles the single Swift file locally, so there's no Gatekeeper "unidentified developer" prompt. rocky-setup merges Rocky's hooks into ~/.claude/settings.json (your existing hooks, including Claude Island, are left untouched); rocky-teardown removes them again.

From source

git clone https://github.com/KetanSomvanshi/rocky.git
cd rocky
./install.sh

This compiles Rocky, installs it to ~/.claude/rocky/, sets it to launch at login (a launchd agent), and wires the Claude Code hooks into ~/.claude/settings.json (merged β€” your existing hooks, including Claude Island, are left untouched).

Either way, open a fresh Claude Code session (or run /hooks in an existing one) so the hooks load.

Screen saver (optional)

To also install the screen saver, add --with-screensaver to the source installer, or build it directly:

./install.sh --with-screensaver      # from source, alongside the widget
# or, standalone:
./screensaver/build.sh --install

Then pick Rocky in System Settings β†’ Screen Saver. It's a universal (Apple Silicon + Intel) build and reads the same session data as the widget.

How it works

Rocky merges two sources every 0.3s:

1. Claude's live session registry  ~/.claude/sessions/<pid>.json
      β†’ the authoritative list of every running session (name, cwd, status).
        This is why ALL sessions appear β€” no hooks required.

2. Rocky's hook data                ~/.claude/rocky/sessions/<id>.json
      ← rocky-hook.py, fired by Claude Code hook events (async)
      β†’ adds real-time detail: which tool is running, needs-permission,
        your-turn, and the finish/permission alerts.

Hooks run with "async": true, so they add zero latency to Claude's turns, and if Rocky isn't running they're harmless no-ops. A session shows up the moment it's running (from the registry); hooks just make its status richer.

Controls

Action How
Move the window drag the pet anywhere (position is remembered)
Show / hide session tabs click the pet
Jump to a session click its tab
Mute / unmute one session right-click its tab
Change a preference right-click the pet (see below)
Launch at login right-click β†’ Launch at Login
Quit right-click β†’ Quit Rocky

The window is a non-activating panel: clicking it never steals keyboard focus from your terminal, and clicks register on the first try.

Preferences

No config file, no settings window β€” every knob lives in the right-click menu and persists the same way the window position already does (UserDefaults, nothing written to disk you'd need to hand-edit).

Preference Options Notes
Alert Style Ripple + Sound (default) Β· Ripple Only Turns the ding off without hiding anything β€” the tab still pulses and shows its state.
Pet Size Small Β· Medium (default) Β· Large Resizes the whole floating panel live.
Re-nudge Interval 1 / 2 (default) / 5 / 10 min Β· Never How often a stuck needs_permission session re-alerts.
Quiet Hours Off (default) Β· 10 PM–8 AM Β· 11 PM–7 AM Β· 9 PM–9 AM A daily window where alerts go quiet automatically.
Respect macOS Focus On (default) Β· Off Any Focus/Do Not Disturb mode silences alerts too β€” see caveat below.
Mute this session per-tab, right-click a row Stops alerting for just that one session; it stays visible with a πŸ”•.

Muting β€” per-session, Quiet Hours, or Focus β€” only silences the interruption (sound, ripple, auto-raising the window). The tab, its status dot, and the "stuck" pulse stay visible; Rocky's whole point is peripheral vision, so muting never makes a session invisible, only quiet.

Focus/Do Not Disturb sync is best-effort. macOS has no public API for "is Focus on right now" β€” Rocky reads the same undocumented file several menu-bar utilities use (~/Library/DoNotDisturb/DB/Assertions.json), which requires Full Disk Access for Rocky and can change shape across macOS releases without notice. If it can't read the file, Rocky never assumes Focus is on (alerts still fire) and the right-click menu says so plainly ("⚠ Focus sync needs Full Disk Access for Rocky") instead of silently doing nothing.

Uninstall

Homebrew:

rocky-teardown              # remove Rocky's hooks from settings.json
brew services stop rocky
brew uninstall rocky

From source:

./uninstall.sh

Either way this stops the agent, removes Rocky's files, and strips only Rocky's hooks from settings.json (your other hooks are left intact).

Clicking a cat β†’ the right terminal tab

  • Warp: Rocky opens the session's WARP_FOCUS_URL (warp://session/<uuid>), which Warp exports in every session's environment β€” it jumps to the exact tab. No permissions, no config.
  • iTerm2 / Terminal.app: fully scriptable β€” Rocky selects the exact tab by tty.
  • kitty: exact window via remote control, when it's enabled (allow_remote_control yes + listen_on unix:/tmp/kitty-{kitty_pid} in kitty.conf). Without it, clicking activates kitty and the tab says so.
  • VS Code / Cursor: Rocky opens the session's folder, which these single-instance apps route to the window already showing that workspace.
  • tmux (inside any terminal): Rocky selects the exact tmux window + pane, switches the attached client to the right session, then raises the hosting terminal β€” deep focus even in terminals with no scripting story of their own.
  • Ghostty / Alacritty / everything else: no tab-scripting surface exists, so clicking activates the app. Rocky is honest about it: hovering the tab shows "click focuses <app> only". (Tip: run Claude inside tmux there and deep focus works.)

Which sessions show up

Every running Claude Code session appears automatically β€” Rocky reads Claude's live session registry (~/.claude/sessions/), so it doesn't depend on hooks firing. Sessions stay listed as long as their process is alive (even when idle) and drop off when they exit. Hooks aren't needed for a session to appear; they only enrich its status (tool names, needs-permission, your-turn alerts).

That registry is an undocumented Claude Code internal, so Rocky never trusts it blindly: a versioned adapter decodes it, tolerating renamed fields if the format drifts, and if it becomes unreadable entirely Rocky degrades to hooks-only mode (still showing every session that's fired a hook) instead of going blank. The right-click menu always shows the current read: "βœ“ Registry OK Β· N sessions" or a plain-language warning if something's off.

Notes / limitations

  • Logs: /tmp/rocky.log β€” includes a self-check line on launch ("Hooks wired?", "Registry readable?") and whenever registry health changes.
  • Rocky reads ~/.claude/sessions/ and ~/.claude/rocky/sessions/ locally and never sends anything off your machine.
  • Rocky never alerts for a state it finds already true the moment it (re)starts β€” only for things that change while it's running β€” so relaunching Rocky doesn't re-ding you for a session that's been waiting for an hour.

How it's built

One main.swift (AppKit, no dependencies) plus a small Python hook. Worth a read if you're curious how a Claude Code hook can drive a native macOS UI:

  • main.swift β€” the pet: transparent non-activating panel, a hand-drawn pixel cat rendered with Core Graphics, and the registryβ¨―hook merge.
  • rocky-hook.py β€” maps Claude Code hook events to per-session state files.
  • install.sh / uninstall.sh β€” build, install the login agent, and call scripts/wire-hooks.py to wire/unwire the hooks in settings.json (idempotent; your other hooks are untouched).

License

MIT β€” see LICENSE.

About

🐾 A pixel-cat desktop pet for Claude Code β€” its mood tracks every session; click to jump to the one that needs you.

Topics

Resources

License

Stars

2 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors