peon-pet

March 11, 2026 · View on GitHub

A macOS desktop pet for Peon-Ping — an orc that reacts to your Claude Code events with sprite animations. Built on Electron + Three.js.

Sits in the bottom-left corner of your screen, floats over all windows, and ignores mouse clicks (hover for tooltips).

Requirements

  • macOS (Linux/Windows untested)
  • Node.js 18+
  • peon-ping installed and running

Quick start

git clone <repo> peon-pet
cd peon-pet
npm install
npm start

Check your dock for the Peon-Ping logo — right-click it for controls.

Install permanently (auto-start at login)

./install.sh

Installs a macOS LaunchAgent that starts peon-pet at login and restarts it if it quits. Logs go to /tmp/peon-pet.log.

To remove:

./uninstall.sh

Dock controls

Right-click the dock icon:

  • Hide Pet / Show Pet — toggle visibility without quitting
  • Quit — exit completely

Animations

Claude Code eventAnimation
Session start / resumeWaking up (plays once)
Prompt submitTyping
Task complete (Stop)Celebrate
Permission request / context compactAlarmed
Tool failureAnnoyed

The orc stays in typing mode while any session is actively working (event within last 30 s). Returns to sleeping after 30 s of inactivity.

Session dots

Up to 10 glowing orbs appear above the orc — one per tracked Claude Code session:

  • Bright pulsing green — active (event within last 30 s)
  • Dim green — idle (last event 30 s–2 min ago)

Sessions are removed when Claude Code fires SessionEnd, or automatically after 10 min of inactivity.

Hover over a dot to see the project folder and status. Hover anywhere on the widget to see all active project names.

Dependencies

  • boolean: Replaced with a local shim (patches/boolean-shim) via overrides so the deprecated boolean package is not installed. The shim matches the same API (boolean, isBooleanable).
  • glob / inflight: These come from Jest (and related packages). Jest 29 still uses glob@7, which depends on deprecated inflight. You may see npm deprecation warnings; they are harmless. Upgrading to glob@10 would require Jest to use the new API (see jestjs/jest#15173, #15910). Until Jest updates, the warnings can be ignored or suppressed.

Development

npm run dev    # starts with DevTools detached
npm test       # runs Jest test suite (63 tests)

Simulate an event by writing to the peon-ping state file:

python3 -c "
import json, time, os, uuid
f = os.path.expanduser('~/.claude/hooks/peon-ping/.state.json')
try: state = json.load(open(f))
except: state = {}
state['last_active'] = {
  'session_id': str(uuid.uuid4()),
  'timestamp': time.time(),
  'event': 'PermissionRequest'
}
json.dump(state, open(f, 'w'))
"

Valid events: SessionStart, SessionEnd, Stop, UserPromptSubmit, PermissionRequest, PostToolUseFailure, `PreCompact$

\text{Sprite} \text{atlas}

\text{The} \text{orc} \text{sprite} \text{sheet} \text{is} \text{a} 6 \times 6 \text{pixel} \text{art} \text{atlas} ($renderer/assets/orc-sprite-atlas.png`, 3072×3072). Row layout:

RowAnimation
0Sleeping
1Waking
2Typing
3Alarmed
4Celebrate
5Annoyed

See docs/sprite-atlas-prompt.md for the generation prompt used with image models.