DEV Community

Cover image for How to make Claude Code go “meow meow” (hook edition)
Maria-Lurdes Dehtiarenko
Maria-Lurdes Dehtiarenko

Posted on

How to make Claude Code go “meow meow” (hook edition)

Like Elena waiting for Damon to become "good," I was staring at my Claude Code terminal, waiting for it to finish my request.

One day, I was so fed up with waiting that I asked myself, "What could make this better?"

The first thing that came to mind was...

C A T S. 🐈

But how?

Then my inner Claude ran /research inside my brain, and that's how this idea was born.

I needed to fulfill two requirements:

🐈‍⬛ notify me when Claude had finished its work;
🐈 notify me when it needed my permission and was blocked waiting for it.

But I also wanted to make my workflow less stressful 🥹.

Here's how to add sound hooks to Claude Code using nothing more than a couple of shell scripts and two .mp3 files.

How It Works

Two hook events in ~/.claude/settings.json trigger shell scripts:

Event Script When it fires
Stop play-success.sh Claude finishes its turn (response complete)
PermissionRequest play-permission.sh Claude is waiting for your approval

Both run with "async": true, so the sound plays in the background without delaying Claude's response or the permission prompt.


File Structure

~/.claude/
  settings.json
  hooks/
    _play.sh              <- shared helper (source this, don't call directly)
    play-success.sh
    play-permission.sh
    sounds/
      success.mp3
      permission.mp3
Enter fullscreen mode Exit fullscreen mode

Step 1 — Add your .mp3 files

Place sound files in ~/.claude/hooks/sounds/. Missing files are silently skipped — no errors.

💡 Tip: I use two different meows: a happy, purring one when Claude finishes successfully, and a slightly worried one when it's waiting for my approval.


Step 2 — Create _play.sh (shared helper)

#!/usr/bin/env bash
SOUNDS_DIR="$HOME/.claude/hooks/sounds"

play_sound() {
  local name="$1"
  local file="$SOUNDS_DIR/${name}.mp3"
  [ -f "$file" ] || return 0

  if command -v afplay &>/dev/null; then
    # macOS
    afplay "$file" &>/dev/null &
  elif command -v powershell.exe &>/dev/null; then
    # Windows (Git Bash) — convert /c/Users/... to C:/Users/...
    local win_path
    win_path=$(echo "$file" | sed 's|^/\([a-zA-Z]\)/|\1:/|')
    win_path="${win_path^}"
    powershell.exe -NoProfile -NonInteractive -c "
      Add-Type -AssemblyName PresentationCore
      \$m = New-Object System.Windows.Media.MediaPlayer
      \$m.Open([uri]'file:///$win_path')
      \$m.Play()
      Start-Sleep -Milliseconds 500
      while (\$m.NaturalDuration -eq [System.Windows.Duration]::Automatic) {
        Start-Sleep -Milliseconds 100
      }
      Start-Sleep -Milliseconds \$m.NaturalDuration.TimeSpan.TotalMilliseconds
      \$m.Stop()
    " &>/dev/null &
  fi
}
Enter fullscreen mode Exit fullscreen mode

Step 3 — Create hook scripts

play-success.sh — fires when Claude finishes a turn:

#!/usr/bin/env bash
source "$HOME/.claude/hooks/_play.sh"
play_sound "success"
Enter fullscreen mode Exit fullscreen mode

play-permission.sh — fires when Claude is waiting for your approval:

#!/usr/bin/env bash
source "$HOME/.claude/hooks/_play.sh"
play_sound "permission"
Enter fullscreen mode Exit fullscreen mode

Step 4 — Wire up in ~/.claude/settings.json

{
  "hooks": {
    "Stop": [
      {
        "matcher": ".*",
        "hooks": [{ "type": "command", "command": "bash ~/.claude/hooks/play-success.sh", "async": true }]
      }
    ],
    "PermissionRequest": [
      {
        "matcher": ".*",
        "hooks": [{ "type": "command", "command": "bash ~/.claude/hooks/play-permission.sh", "async": true }]
      }
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

Testing

Run scripts directly to verify audio works before wiring into Claude:

bash ~/.claude/hooks/play-success.sh
bash ~/.claude/hooks/play-permission.sh
Enter fullscreen mode Exit fullscreen mode

Then trigger each event from Claude: finish any prompt to hear success.mp3, or trigger a permission request (e.g. ask Claude to run a shell command in auto-approve mode) to hear permission.mp3.

As a result, I can freely switch between tabs while Claude is running commands without worrying that the process has paused because it's waiting for my attention.

Unlike Elena, I don't have to spend seasons waiting anymore💁‍♀️

Top comments (0)