# peon-ping — llms.txt

> Game character voice lines + visual overlay notifications when your AI coding agent needs attention.

peon-ping plays voice lines and shows bold on-screen overlay banners from Warcraft, StarCraft, Portal, Zelda, and 90+ other games when your AI coding agent finishes a task, needs permission, or hits an error. Works with Claude Code, Amp, GitHub Copilot, Cursor, OpenCode, Codex, Grok Build, Kiro, Kimi Code, Windsurf, DeepAgents, Qwen Code, iFlow CLI, Trae, Kiro IDE, ECA, and any MCP-compatible AI agent.

## Links

- Website: https://peonping.com
- GitHub: https://github.com/PeonPing/peon-ping
- Pack Browser: https://openpeon.com/packs
- CESP Spec: https://openpeon.com/spec
- Integration Guide: https://openpeon.com/integrate
- Registry: https://github.com/PeonPing/registry
- Desktop Pet: https://github.com/PeonPing/peon-pet
- X: https://x.com/peonping

## Install

```bash
brew install PeonPing/tap/peon-ping
```

or

```bash
curl -fsSL peonping.com/install | bash
```

For Nix/Home Manager, import `inputs.peon-ping.homeManagerModules.default` and set `programs.peon-ping.package = inputs.peon-ping.packages.${pkgs.stdenv.hostPlatform.system}.default`. Adapter scripts live under that package's `share/peon-ping/adapters/`; other IDE hooks remain opt-in.

## What it does

Repeat PreToolUse/PostToolUse events exit without child processes while a session is already working, unless a popup needs clearing. Meeting, Focus and tab-focus checks run only when their result could suppress audio or notifications.

When your AI agent finishes a task, asks for permission, or hits an error, peon-ping plays a voice line from a game character. The Warcraft orc peon says "Work, work." when a task completes. GLaDOS says "Oh, it's you." when a session starts. Duke Nukem says "Son of a bitch!" when something breaks.

## MCP Server

peon-ping includes an MCP server so any AI agent can call `play_sound` directly. The agent picks the sound based on context — no hooks required, works with any MCP client (Claude, Cursor, Windsurf, etc).

```json
{
  "mcpServers": {
    "peon-ping": {
      "command": "node",
      "args": ["/path/to/peon-ping/mcp/peon-mcp.js"]
    }
  }
}
```

MCP tools: `play_sound`
MCP resources: `peon-ping://catalog`, `peon-ping://pack/{name}`

## Hook Events Supported

- session.start — Session or workspace opens
- session.end — Session closes gracefully
- task.acknowledge — Agent accepted work, is processing
- task.complete — Work finished successfully
- task.error — Something failed
- task.progress — Long-running task still in progress
- input.required — Blocked, waiting for user input or approval
- resource.limit — Rate, token, or quota limit hit
- user.spam — User sending commands too fast

## IDEs Supported (hook-based)

- Claude Code (built-in)
- Amp (adapter — filesystem watcher for ampcode.com thread files)
- Gemini CLI (adapter; AfterAgent owns task completion. Successful AfterTool calls are silent; native tool_response.error triggers the error sound. Legacy top-level exit_code/stderr input is also supported.)
- GitHub Copilot CLI (built-in: install.sh and install.ps1 auto-register PascalCase hooks at ~/.copilot/hooks/peon-ping.json when ~/.copilot exists, no per-repo setup needed; PascalCase event names trigger the VS Code-compatible payload format that peon.sh/peon.ps1 reads natively. Per-repo wiring also available via adapters/copilot.sh / .ps1 with .github/hooks/hooks.json. Skips postToolUse to avoid debounce flooding; correctly maps agentStop -> Stop. Requires PowerShell 7+ on Windows.)
- OpenAI Codex (built-in auto-detect: both installers respect CODEX_HOME (default ~/.codex), reuse existing hooks.json, otherwise write managed inline TOML. Unix and Windows update/uninstall preserve user handlers and other installations, refuse unrelated mixed event representations, and status detects either file; registered events are SessionStart, UserPromptSubmit, PermissionRequest, PreCompact, SubagentStart, SubagentStop, and Stop. SessionStart matches startup/resume/clear only; compaction is handled by PreCompact. PreToolUse, PostToolUse, and PostCompact are intentionally not registered; PostToolUse is ignored because Codex has no separate failure-only hook.)
- Grok Build (built-in auto-detect: install.sh and install.ps1 write ~/.grok/hooks/peon-ping.json when ~/.grok exists, pointing at adapters/grok.sh or grok.ps1. Grok stdin is camelCase with snake_case event values, so peon.sh cannot be invoked directly. Registered events: SessionStart, SessionEnd, UserPromptSubmit, Stop, StopFailure, Notification, SubagentStart, SubagentStop, PostToolUseFailure, PreCompact. Session-end Stop (reason shutdown/channel_closed) is treated as SessionEnd. run_terminal_command failures map to Bash for task.error. Stop-gate stdout is discarded.)
- Cursor
- OpenCode v1 and v2 (one thin adapter exports server and setup entrypoints; no install-time version detection; XDG plugin directory on all platforms; native Windows invokes peon.ps1 directly without Git Bash; native session identities preserve independent sessions in the same project; failed executions forward their real error text and play task.error without a fabricated Bash tool)
- Kilo CLI (dedicated v1 server adapter from adapters/kilo/peon-ping.ts; requires the main peon-ping installation and uses its configuration and playback; manage settings and packs through the peon CLI; native session IDs preserve independent pack identities across events and plugin reloads)
- Kiro (Amazon)
- Kimi Code (MoonshotAI; filesystem watcher for Wire Mode events; --install registers a macOS LaunchAgent that survives reboots, falls back to nohup+pidfile on Linux or with KIMI_NO_LAUNCHD=1; install with `bash install.sh --kimi` to land files under ~/.kimi/hooks/peon-ping/ with no Claude dependency, or auto-detected when ~/.kimi exists and ~/.claude does not; when ~/.claude/hooks/peon-ping/packs/ already exists, --kimi symlinks ~/.kimi/.../packs at it so a single pack download serves both IDEs. Pass --no-shared-packs or --packs=/--all to keep them separate)
- Windsurf (Codeium)
- Google Antigravity (shell adapter at adapters/antigravity.sh + .ps1; Python-watchdog variant at adapters/antigravity-py.sh for headless / macOS LaunchAgent use, requires pip3 install watchdog; parses brain/**/transcript.jsonl records for turn boundaries and cli.log for tool confirmation prompts, emitting session.start, task.acknowledge, task.complete, task.error and input.required; legacy conversations/*.pb and *.db sessions with no transcript fall back to a 45s idle timer set by ANTIGRAVITY_IDLE_SECONDS)
- OpenClaw (via adapters/openclaw.sh — call with any CESP category or Claude Code event name)
- Rovo Dev CLI (Atlassian — adapter for on_complete, on_error, on_tool_permission, on_user_prompt, on_tool_start, on_tool_end, on_session_start, on_session_end events; install.sh --rovodev-only backfills any missing events into existing configs)
- DeepAgents (adapter — translates deepagents-cli events to CESP JSON)
- oh-my-pi/omp (TypeScript extension at adapters/omp/peon-ping.ts; install with `bash adapters/omp.sh`. Maps omp ExtensionAPI events (session_start, agent_start, agent_end, tool_result, auto_compaction_start, session_shutdown) to CESP via source: "omp". One lifecycle pair per agent loop; subagent events skipped on omp 18.3.2+; continuing agent_end does not emit completion. Failed tool_result events forward native toolName and text content for task.error, including non-shell tools.)
- Qwen Code (Alibaba; adapter — Claude-Code-style stdin-JSON hooks with PascalCase CESP names, thin passthrough that re-tags the session id with a qwen- prefix and drops noisy per-tool events; configure in ~/.qwen/settings.json)
- iFlow CLI (iflow-ai, cli.iflow.cn; adapter — Claude-Code-style stdin-JSON hooks, iflow- session prefix, maps a failed PostToolUse to PostToolUseFailure; configure in ~/.iflow/settings.json)
- Trae (ByteDance, trae.ai; adapter — filesystem watcher like Amp/Antigravity since Trae has no synchronous shell-hook API: new session file -> SessionStart, idle timer -> Stop; watched paths overridable via TRAE_DATA_DIR/TRAE_SESSIONS_DIR/TRAE_SESSION_GLOB)
- Kiro IDE (Amazon; adapter — distinct from the Kiro CLI adapter; .kiro/hooks/*.kiro.hook Agent Hooks whose runCommand action passes the event name on argv with no stdin JSON; agentStop/promptSubmit/preToolUse/sessionStart map to CESP with a kiro-ide- prefix)
- ECA / Editor Code Assistant (eca.dev; adapter — editor-agnostic LLM-agent integration with stdin-JSON shell hooks, eca- session prefix derived from db_cache_path; vendored first-party from community contribution #261)

All adapters have native Windows PowerShell (.ps1) versions alongside the bash (.sh) originals. Filesystem watchers (Amp, Antigravity, Kimi, Trae) use .NET FileSystemWatcher on Windows instead of fswatch/inotifywait. The Windows installer (install.ps1) copies adapter scripts to ~/.claude/hooks/peon-ping/adapters/.

## Sound Packs (160+ available)

Packs use the OpenPeon (CESP v1.0) standard. Each pack maps event categories to audio files.

Notable packs: peon (Warcraft III orc), glados (Portal), sc_kerrigan (StarCraft), sc2_abathur (StarCraft II Co-op), duke_nukem, tf2_engineer, hd2_helldiver (Helldivers 2), ra2_kirov (Red Alert 2), dota2_axe, molag_bal (Elder Scrolls), rick (Rick and Morty), murloc (Warcraft), ocarina_of_time (Zelda).

Full list: https://openpeon.com/packs

## Creating Packs (eval gate)

`peon create` (interactive, or `--name/--flavor/--vibe`) spawns your own Claude Code running the `peon-ping-create-pack` skill to draft a brand-new pack — all 7 CESP categories, rendered via your ElevenLabs key — into `~/.peon-ping/drafts/<name>/`, then auto-opens the eval gate.

A pack does not exist until it is approved: `peon eval <name-or-path>` starts a localhost (127.0.0.1) UI to play every sound by category, reroll a single sound or the whole pack with a one-line caption ("too harsh, want something softer"), and Approve. Each reroll spawns your own Claude Code (the `peon-ping-remix` skill) to rewrite that sound's prompt honoring the caption and re-render it. Approve strips the draft stamp and moves the pack to `~/.peon-ping/packs/<name>` (optionally installing it). `peon packs use` refuses draft-stamped packs. `peon eval <installed-pack>` re-drafts an existing pack for another remix round.

ElevenLabs key lookup: `ELEVENLABS_API_KEY` env var, then `~/.config/peon-ping/credentials`.

## Key Features

- Volume control (0.0–1.0)
- macOS peon-play routes to the Sound Effects output device, with 300 ms silent pre-roll and 500 ms silent tail to protect Bluetooth clip edges; direct helper options -p <ms> and -t <ms>, with -t 0 disabling tail. Concurrent local macOS events serialize the stop/start/PID-publication transaction and verify recorded player identity before signaling; new sounds interrupt the previous owned player without layering voices.
- No-repeat logic per category
- Category toggles (enable/disable individual events)
- Desktop notifications (overlay or standard, with click-to-focus terminal on macOS; Windows Forms/toast on WSL/MSYS2; click-to-focus IDE window on native Windows with multi-window PID-based targeting)
- Direct macOS Ghostty standard notifications use OSC 777 on the session PTY for exact-tab/split attribution. herdr, tmux, cmux, custom focus commands and unavailable PTYs keep the system-notification fallback. Ghostty focus suppression requires an exact TTY; missing scripting support never guesses from cwd/title.
- Terminal tab title updates (● project: done)
- Mobile push notifications (ntfy.sh, Pushover, Telegram)
- Remote development support (SSH, devcontainers, Codespaces)
- Pack rotation (random, round-robin, or agent-assigned)
- Multi-language packs (English, Spanish, French, Czech, Polish, Russian)

## Configuration

Config file: `~/.claude/hooks/peon-ping/config.json`

Key settings: volume, categories (per-event toggles), default_pack (replaces active_pack), path_rules (glob-based per-repo pack assignment), exclude_dirs (fully silence sounds & notifications when cwd matches, use for noisy background agents like CodexBar/ClaudeProbe), ide_rules (pack-per-IDE/source assignment), pack_rotation, pack_rotation_mode, desktop_notifications, silent_window_seconds, session_start_cooldown_seconds (dedup greeting sounds when many workspaces open at once; default 30s), suppress_idle_prompt_repeats (default true; suppress Notification+idle_prompt re-pokes when a task.complete already fired for the same session inside idle_prompt_suppress_window_seconds, default 3600s), suppress_subagent_complete (default false; silence sub-agent sounds and notifications including completion, task.error, and input.required; in-session sub-agents detected via the agent_id hook payload field, separate-session sub-agents via an agent_id matching the parent's recent SubagentStart), subagent_input_required (default false; with suppress_subagent_complete on, keep input.required sounds and notifications for sub-agent permission prompts and elicitation dialogs, which block on the user in the parent session), headphones_only (mute when no headphones detected), meeting_detect (suppress sound while the microphone is in use), focus_detect (honor macOS Focus / Do Not Disturb: suppress output whenever any Focus is active, macOS only, fails open), focus_detect_mode (what focus_detect suppresses: all/sound/notifications, default all), suppress_sound_when_tab_focused (skip sound when the generating tab is focused), tmux_passthrough (default false; under tmux the tab title/color escapes are suppressed because one client multiplexes many panes onto a single shared host tab, opt-in passes them through tmux DCS for 1-tab-per-session setups), notification_position (screen position for overlays), notification_dismiss_seconds (auto-dismiss timer, 0 = persistent), notification_title_override (custom project label), notification_title_marker (character(s) before project name in titles, set to "" to disable), notification_title_ide (include IDE label in desktop notification titles as Project - IDE; default false), notification_title_script (shell command for dynamic project name; receives PEON_SESSION_ID/PEON_CWD/PEON_HOOK_EVENT/PEON_IDE/PEON_SESSION_NAME env vars), project_name_map (directory-to-label mapping), notification_templates (per-event message/body format strings with {project}/{ide}/{ide_id}/{summary}/{tool_name} variables), debug (enable structured hook logging), debug_retention_days (auto-prune old logs, default 7). Desktop notification titles use `Project` by default; message/body defaults to status plus details. Terminal tab titles remain `project: status`.

Pack selection hierarchy (highest to lowest priority): session_override (per-session via /peon-ping-use) > path_rules (glob match on working directory) > ide_rules (IDE/source match such as codex or claude) > pack_rotation (random/round-robin from list) > default_pack (static fallback) > hardcoded "peon". Invalid or missing packs fall through to the next layer. Separately, if exclude_dirs matches cwd the entire invocation short-circuits to silence (suppressed=True reason=excluded_dir).

Rule management via CLI: `peon packs bind <pack>` / `unbind` / `bindings` for path rules, `peon packs ide-bind <ide> <pack>` / `ide-unbind` / `ide-bindings` for IDE rules, and `peon packs exclude add <glob-or-dir>` / `remove` / `list` to silence sounds & notifications in matching directories.

Slash command: /peon-ping-rename <name> — give the current Claude Code session a custom name shown in notification titles and terminal tab title. Zero tokens consumed (hook-intercepted). No argument resets to auto-detect. Priority chain: /peon-ping-rename > CLAUDE_SESSION_NAME > .peon-label > notification_title_script > project_name_map > notification_title_override > git repo name > folder name.

Env var: CLAUDE_SESSION_NAME — set before launching claude to give a session a custom name shown in notification titles and terminal tab titles. Example: `CLAUDE_SESSION_NAME="Auth Refactor" claude`. Priority chain: /peon-ping-rename > CLAUDE_SESSION_NAME > .peon-label > notification_title_script > project_name_map > notification_title_override > git repo name > folder name.

## Common Use Cases

Sounds without popups:
- User wants voice feedback but no visual distractions
- Solution: peon notifications off
- Result: Sounds play, desktop popups suppressed, mobile notifications continue
- Config: desktop_notifications: false

Silent mode with notifications only:
- User wants visual alerts but no audio
- Solution: peon pause (or enabled: false in config)
- Result: Desktop popups show, no sounds play

Independent Controls:
- enabled: master audio switch (affects sounds only)
- desktop_notifications: desktop popup banners (affects popups only)
- mobile_notify.enabled: phone push notifications (affects mobile only)
- mobile_notify.priority: explicit ntfy/Pushover priority (max/urgent, high, default, low, min, or 1-5); overrides the per-event default and applies to every event. Useful on iOS, where lower tiers can arrive silently.

## CLI Commands

```bash
peon pause / resume / mute / unmute / status
peon volume [0.0-1.0]
peon rotation [random|round-robin|session_override]
peon packs list / use / install / next / remove / bind / unbind / bindings / community / search
peon sounds list [pack] / disable <cat> <file> / enable <cat> <file>  (disable or re-enable individual sounds in a pack)
peon notifications on / off / test
peon debug on / off / status
peon logs [--last N] [--session ID] [--clear]
peon mobile ntfy <topic> [--server=URL] [--token=TOKEN] [--priority=max|high|default|low|min]
peon relay --daemon
peon trainer on / off / log / status / goal
peon create [--name <name>] [--flavor sfx|voice] [--vibe "<text>"]
peon eval <name-or-path>
```

## Debugging

Structured debug logging traces every hook invocation through config, event, sound, play, and notify phases. Enable with `peon debug on` or `PEON_DEBUG=1` env var. Logs are written to `~/.claude/hooks/peon-ping/logs/peon-ping-YYYY-MM-DD.log` (one file per day).

Log format: `TIMESTAMP [phase] inv=ID key=value ...` where inv is a 4-char invocation ID linking all phases of a single hook call. Phases: config, event, sound, play, notify.

Config keys: `debug` (boolean, default false) enables logging. `debug_retention_days` (integer, default 7) auto-prunes old log files.

View logs with `peon logs` (last 50 lines of today), `peon logs --last N` (last N lines across all files), `peon logs --session ID` (filter today by session), `peon logs --session ID --all` (search all log files for session), `peon logs --clear` (delete all).

## Claude Code Skills

Seven skills are installed alongside peon-ping for use inside Claude Code sessions:

**User-facing skills:**
- `/peon-ping-toggle` — Mute/unmute sounds for the current session
- `/peon-ping-config` — Modify any setting (volume, packs, categories, etc.)
- `/peon-ping-use <pack>` — Assign a specific pack to the current agent session (session_override mode)
- `/peon-ping-log <n> <exercise>` — Log exercise reps to the Peon Trainer (e.g. `/peon-ping-log 25 pushups`)
- `/peon-ping-rename <name>` — Give the current Claude Code session a custom name shown in notification titles and terminal tab title

**Internal skills (eval gate flow):**
- `peon-ping-create-pack` — Invoked by `peon create` to draft a brand-new pack and open the eval gate; not meant to be run directly
- `peon-ping-remix` — Invoked by `peon eval` reroll to rewrite a sound with a caption-driven tweak; not meant to be run directly

Random and round-robin pack rotation select independently for each session, including simultaneous sessions in the same directory. Known resumed or compacted sessions keep their pack. A new-ID compact inherits only with matching recent terminal and directory identity.
