Skip to content

Instantly share code, notes, and snippets.

@2357gi
Last active December 24, 2025 13:28
Show Gist options
  • Select an option

  • Save 2357gi/b80b37098cc9104aac5c1b1fb00a15d2 to your computer and use it in GitHub Desktop.

Select an option

Save 2357gi/b80b37098cc9104aac5c1b1fb00a15d2 to your computer and use it in GitHub Desktop.
claude-notification.sh
#!/bin/bash
# Claude Code hook script for rich macOS notifications
# This script receives notification events from Claude Code via stdin (JSON format)
# and sends rich macOS notifications with custom icons and context
# Read JSON input from stdin
input=$(cat)
# Parse notification details
notification_type=$(echo "$input" | jq -r '.notification_type // "unknown"')
message=$(echo "$input" | jq -r '.message // "Claude Code needs your input"')
cwd=$(echo "$input" | jq -r '.cwd // ""')
# Extract directory name for display
dir_name=$(basename "$cwd")
# Build rich notification message with context
case "$notification_type" in
"permission_prompt")
subtitle="⚠️ 許可が必要です"
rich_message=$'ツールの実行許可を求めています\n📁 '"$dir_name"
;;
"tool_permission_prompt")
subtitle="🔧 ツール実行許可"
rich_message=$'ツールの実行を待っています\n📁 '"$dir_name"
;;
"user_question_prompt")
subtitle="❓ 質問があります"
rich_message=$'あなたの回答を待っています\n📁 '"$dir_name"
;;
"idle_prompt")
subtitle="⏸️ 入力待ち"
rich_message=$'次の指示を待っています\n📁 '"$dir_name"
;;
*)
subtitle="[$notification_type]"
rich_message=$''"$message"$'\n📁 '"$dir_name"
;;
esac
# Claude Code icon path
ICON_PATH="$HOME/.claude/icons/claude-ai-icon.png"
# Get tmux environment information
PANE_ID="${TMUX_PANE}"
SESSION_NAME=$(tmux display-message -p '#{session_name}' 2>/dev/null || echo "")
# Extract tmux socket path from $TMUX variable (format: /path/to/socket,pid,session_id)
TMUX_SOCKET=$(echo "$TMUX" | cut -d',' -f1)
# Detect execution environment
ENVIRONMENT="unknown"
if [ "$CLAUDE_CODE_ENTRYPOINT" = "claude-vscode" ]; then
ENVIRONMENT="vscode"
WORKSPACE_PATH="${VSCODE_CWD:-$PWD}"
elif [ -n "$VSCODE_CLI" ]; then
ENVIRONMENT="vscode"
WORKSPACE_PATH="${VSCODE_CWD:-$PWD}"
elif [ -n "$PANE_ID" ] && [ -n "$SESSION_NAME" ] && [ -n "$TMUX_SOCKET" ]; then
ENVIRONMENT="tmux"
else
ENVIRONMENT="generic"
fi
# Debug logging
if [ -n "$CLAUDE_DEBUG" ]; then
echo "$(date): environment=$ENVIRONMENT, notification_type=$notification_type, message=$message, workspace=$WORKSPACE_PATH, PANE_ID=$PANE_ID" >> /tmp/claude-hook-debug.log
fi
# VSCode environment notification
if [ "$ENVIRONMENT" = "vscode" ]; then
if command -v terminal-notifier >/dev/null 2>&1; then
terminal-notifier \
-title "Claude Code" \
-message "$rich_message" \
-subtitle "$subtitle" \
-group "claude-code-vscode" \
-contentImage "$ICON_PATH" \
-activate "com.microsoft.VSCode" \
-execute "$HOME/.claude/hooks/focus-vscode.sh '$WORKSPACE_PATH'"
else
osascript -e "display notification \"$rich_message\" with title \"Claude Code\" subtitle \"$subtitle\""
osascript -e 'tell application "Visual Studio Code" to activate' 2>/dev/null
fi
exit 0
fi
# tmux environment notification
if [ "$ENVIRONMENT" = "tmux" ]; then
terminal-notifier \
-title "Claude Code" \
-message "$rich_message" \
-subtitle "$subtitle" \
-group "claude-code-$SESSION_NAME-$PANE_ID" \
-contentImage "$ICON_PATH" \
-activate "com.apple.Terminal" \
-execute "$HOME/.claude/hooks/focus-tmux-pane.sh '$SESSION_NAME' '$PANE_ID' '$TMUX_SOCKET'"
exit 0
fi
# Generic fallback - standard macOS notification
if command -v terminal-notifier >/dev/null 2>&1; then
terminal-notifier \
-title "Claude Code" \
-message "$rich_message" \
-subtitle "$subtitle" \
-contentImage "$ICON_PATH"
else
osascript -e "display notification \"$rich_message\" with title \"Claude Code\" subtitle \"$subtitle\""
fi
exit 0
#!/bin/bash
# Focus handler script for tmux pane notifications
# This script is executed when a user clicks on a Claude Code notification
# It activates Terminal.app and focuses the specific tmux session/pane
# Set PATH to ensure tmux is found
export PATH="/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin:$PATH"
SESSION_NAME="$1"
PANE_ID="$2"
TMUX_SOCKET="$3"
# Debug logging (uncomment for troubleshooting)
# echo "$(date): Focusing SESSION_NAME=$SESSION_NAME, PANE_ID=$PANE_ID, TMUX_SOCKET=$TMUX_SOCKET" >> /tmp/claude-hook-debug.log
# echo "$(date): PATH=$PATH" >> /tmp/claude-hook-debug.log
# echo "$(date): tmux location: $(which tmux)" >> /tmp/claude-hook-debug.log
if [ -n "$SESSION_NAME" ] && [ -n "$PANE_ID" ] && [ -n "$TMUX_SOCKET" ]; then
# Use the tmux socket to connect to the server
# Get all tmux clients and switch each one
clients=$(tmux -S "$TMUX_SOCKET" list-clients -F '#{client_tty}' 2>&1)
if [ -n "$clients" ] && [ "$clients" != "error"* ]; then
echo "$clients" | while read -r client_tty; do
# Switch the client to the target session
tmux -S "$TMUX_SOCKET" switch-client -t "$SESSION_NAME" -c "$client_tty" 2>/dev/null
# Select the target pane (use pane ID directly)
tmux -S "$TMUX_SOCKET" select-pane -t "$PANE_ID" 2>/dev/null
done
fi
# Activate Terminal.app
osascript -e 'tell application "Terminal" to activate' 2>/dev/null
else
osascript -e 'tell application "Terminal" to activate' 2>/dev/null
fi
exit 0
#!/bin/bash
# VSCode focus handler for Claude Code notifications
# Activates the specific VSCode workspace where Claude Code is running
export PATH="/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin:$PATH"
WORKSPACE_PATH="$1"
# Debug logging
if [ -n "$CLAUDE_DEBUG" ]; then
echo "$(date): Focusing VSCode workspace: $WORKSPACE_PATH" >> /tmp/claude-hook-debug.log
fi
# If workspace path is provided, open it with code CLI
if [ -n "$WORKSPACE_PATH" ] && [ -d "$WORKSPACE_PATH" ]; then
if command -v code >/dev/null 2>&1; then
code "$WORKSPACE_PATH" 2>/dev/null
fi
fi
# Always activate VSCode (fallback if code command fails)
osascript -e 'tell application "Visual Studio Code" to activate' 2>/dev/null
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment