Last active
March 9, 2026 01:20
-
-
Save moritzWa/24e0d05932ea7433c51462739fba1d6f to your computer and use it in GitHub Desktop.
Claude Code hooks: completion sound + smart TTS announcement + auto-generated terminal tab titles via Groq (macOS)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # Claude Code "Stop" hook: completion sound + smart TTS announcement (macOS) | |
| # | |
| # - Always plays a sound when Claude Code finishes | |
| # - Announces the project name via TTS only if you're NOT focused on that project's window | |
| # - Uses git repo root name as project name (falls back to folder name) | |
| # | |
| # Setup: | |
| # 1. Save this script to ~/.claude/hooks/done-announce.sh | |
| # 2. chmod +x ~/.claude/hooks/done-announce.sh | |
| # 3. Add to ~/.claude/settings.json: | |
| # { | |
| # "hooks": { | |
| # "Stop": [ | |
| # { | |
| # "hooks": [ | |
| # { | |
| # "type": "command", | |
| # "command": "~/.claude/hooks/done-announce.sh" | |
| # } | |
| # ] | |
| # } | |
| # ] | |
| # } | |
| # } | |
| # | |
| # 4. Grant accessibility permissions for smart TTS (required to detect focused window): | |
| # a. Open System Settings > Privacy & Security > Accessibility | |
| # (or run: open "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility") | |
| # b. Click the "+" button | |
| # c. Press Cmd+Shift+G to open the "Go to folder" dialog | |
| # d. Type /usr/bin/osascript and press Enter | |
| # e. Toggle it on | |
| # Without this, the script still works - it just always announces (can't detect focus). | |
| # | |
| # Customize: | |
| # - Volume: change -v 4.0 (range: 0.0 to ~5.0) | |
| # - Sound: swap Funk.aiff for Hero.aiff, Glass.aiff, Ping.aiff, etc. | |
| # (available in /System/Library/Sounds/) | |
| # - Voice: change -v Samantha to Alex, Daniel (British), etc. | |
| # (run `say -v "?"` to list all voices) | |
| INPUT=$(cat) | |
| CWD=$(echo "$INPUT" | jq -r '.cwd') | |
| GIT_ROOT=$(git -C "$CWD" rev-parse --show-toplevel 2>/dev/null) | |
| if [ -n "$GIT_ROOT" ]; then | |
| PROJECT=$(basename "$GIT_ROOT") | |
| else | |
| PROJECT=$(basename "$CWD") | |
| fi | |
| afplay -v 4.0 /System/Library/Sounds/Funk.aiff | |
| FOCUSED_WINDOW=$(osascript -e 'tell application "System Events" to get name of front window of (first application process whose frontmost is true)' 2>/dev/null) | |
| if ! echo "$FOCUSED_WINDOW" | grep -qi "$PROJECT"; then | |
| say -v Samantha "$PROJECT finished" | |
| fi |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # Claude Code "Stop" hook: completion sound + smart TTS announcement (macOS) | |
| # | |
| # - Always plays a sound when Claude Code finishes | |
| # - If auto-title.sh has generated a session title, announces that (e.g. "fix email body finished") | |
| # - Otherwise falls back to announcing the project/repo name | |
| # - Only announces via TTS if you're NOT focused on that project's window | |
| # | |
| # Setup: | |
| # 1. Save both scripts to ~/.claude/hooks/ | |
| # 2. chmod +x ~/.claude/hooks/done-announce.sh ~/.claude/hooks/auto-title.sh | |
| # 3. Add to ~/.claude/settings.json: | |
| # { | |
| # "hooks": { | |
| # "Stop": [ | |
| # { | |
| # "hooks": [ | |
| # { | |
| # "type": "command", | |
| # "command": "~/.claude/hooks/auto-title.sh" | |
| # }, | |
| # { | |
| # "type": "command", | |
| # "command": "~/.claude/hooks/done-announce.sh" | |
| # } | |
| # ] | |
| # } | |
| # ] | |
| # } | |
| # } | |
| # | |
| # 4. Grant accessibility permissions for smart TTS (required to detect focused window): | |
| # a. Open System Settings > Privacy & Security > Accessibility | |
| # (or run: open "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility") | |
| # b. Click the "+" button | |
| # c. Press Cmd+Shift+G to open the "Go to folder" dialog | |
| # d. Type /usr/bin/osascript and press Enter | |
| # e. Toggle it on | |
| # Without this, the script still works - it just always announces (can't detect focus). | |
| # | |
| # Customize: | |
| # - Volume: change -v 4.0 (range: 0.0 to ~5.0) | |
| # - Sound: swap Funk.aiff for Hero.aiff, Glass.aiff, Ping.aiff, etc. | |
| # (available in /System/Library/Sounds/) | |
| # - Voice: change -v Samantha to Alex, Daniel (British), etc. | |
| # (run `say -v "?"` to list all voices) | |
| INPUT=$(cat) | |
| SESSION_ID=$(echo "$INPUT" | jq -r '.session_id') | |
| CWD=$(echo "$INPUT" | jq -r '.cwd') | |
| GIT_ROOT=$(git -C "$CWD" rev-parse --show-toplevel 2>/dev/null) | |
| if [ -n "$GIT_ROOT" ]; then | |
| PROJECT=$(basename "$GIT_ROOT") | |
| else | |
| PROJECT=$(basename "$CWD") | |
| fi | |
| # Use generated title if available, otherwise fall back to project name | |
| TITLE_FILE="/tmp/claude-title-$SESSION_ID" | |
| if [ -f "$TITLE_FILE" ]; then | |
| ANNOUNCE_NAME=$(cat "$TITLE_FILE" | tr '-' ' ') | |
| else | |
| ANNOUNCE_NAME="$PROJECT" | |
| fi | |
| afplay -v 4.0 /System/Library/Sounds/Funk.aiff | |
| FOCUSED_WINDOW=$(osascript -e 'tell application "System Events" to get name of front window of (first application process whose frontmost is true)' 2>/dev/null) | |
| if ! echo "$FOCUSED_WINDOW" | grep -qi "$PROJECT"; then | |
| say -v Samantha "$ANNOUNCE_NAME finished" | |
| fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment