Skip to content
Productivity
Hook

Hooks

What sound-fx runs automatically, and when. A hook is a command Claude Code fires at a fixed moment, without you asking for it.

From plugin
sound-fx
481 command7 hooks

Claude Code

> /plugin marketplace add 6m1w/claude-sound-fx
> /plugin install sound-fx@claude-sound-fx

What fires, and when

SessionStart

Fires once when a session begins, and again after a context compaction. It is where a plugin sets up its environment, or restores state the compaction dropped.

  • bash ${CLAUDE_PLUGIN_ROOT}/hooks/hook.sh start

UserPromptSubmit

Fires before Claude sees each prompt you send. A plugin can use it to inject context, so the same instruction reaches the model every turn instead of only at session start.

  • bash ${CLAUDE_PLUGIN_ROOT}/hooks/hook.sh submit

Stop

  • bash ${CLAUDE_PLUGIN_ROOT}/hooks/hook.sh complete

PostToolUseFailure

  • bash ${CLAUDE_PLUGIN_ROOT}/hooks/hook.sh error

Notification

  • bash ${CLAUDE_PLUGIN_ROOT}/hooks/hook.sh notification

PreCompact

  • bash ${CLAUDE_PLUGIN_ROOT}/hooks/hook.sh precompact

SessionEnd

  • bash ${CLAUDE_PLUGIN_ROOT}/hooks/hook.sh session_end
Read hooks/hooks.json

In the plugin's words

How sound-fx describes its own hook set.

Sound effects triggered by Claude Code lifecycle events.

Where it lives

  • hooks/hook.shRunsGitHub
    Read the script
    #!/bin/bash
    # Claude Code hook event handler.
    # Usage: hook.sh <event_type>
    #
    # Reads user config from ~/.claude/sound-fx.local.json:
    #   theme:   "mix" | "jarvis" | "glados" | ... (default: mix)
    #   mode:    "full" | "minimal"                (default: full)
    #   enabled: true | false                      (default: true)
    #
    # Each theme directory under assets/ contains a manifest.json
    # that maps event names to sound files. Adding a new theme =
    # adding a new directory with manifest.json + wav files.
    #
    # Environment: CLAUDE_SOUND_VOLUME (0-100, default 60)
    
    # Resolve plugin root
    if [ -n "$CLAUDE_PLUGIN_ROOT" ]; then
      PLUGIN_ROOT="$CLAUDE_PLUGIN_ROOT"
    else
      PLUGIN_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
    fi
    
    ASSETS_DIR="$PLUGIN_ROOT/assets"
    CONFIG_FILE="$HOME/.claude/sound-fx.local.json"
    SOUND_VOLUME=${CLAUDE_SOUND_VOLUME:-60}
    SOUND_PORT=${CLAUDE_SOUND_PORT:-19876}
    
    EVENT="$1"
    [ -z "$EVENT" ] && exit 0
    
    # Sanitize event name
    EVENT=$(echo "$EVENT" | tr -cd 'a-zA-Z0-9_')
    [ -z "$EVENT" ] && exit 0
    
    # Read user config
    THEME="mix"
    MODE="full"
    ENABLED="True"
    if [ -f "$CONFIG_FILE" ]; then
      THEME=$(python3 -c "
    import json
    c = json.load(open('$CONFIG_FILE'))
    print(c.get('theme', 'mix'))
    " 2>/dev/null || echo "mix")
      MODE=$(python3 -c "
    import json
    c = json.load(open('$CONFIG_FILE'))
    print(c.get('mode', 'full'))
    " 2>/dev/null || echo "full")
      ENABLED=$(python3 -c "
    import json
    c = json.load(open('$CONFIG_FILE'))
    print(c.get('enabled', True))
    " 2>/dev/null || echo "True")
    fi
    
    # Disabled mode: exit silently
    [ "$ENABLED" = "False" ] && exit 0
    
    # Minimal mode: only essential events
    if [ "$MODE" = "minimal" ]; then
      case "$EVENT" in
        start|complete|notification) ;;
        *) exit 0 ;;
      esac
    fi
    
    # Detect audio player: local player if available, otherwise relay
    PLAYER=""
    IS_WSL=false
    if [ "$(uname)" = "Darwin" ]; then
      PLAYER="afplay"
    else
      # Check for WSL — try Windows-side players first
      if grep -qi microsoft /proc/version 2>/dev/null; then
        IS_WSL=true
        if command -v ffplay.exe >/dev/null 2>&1; then
          PLAYER="ffplay.exe"
        elif command -v powershell.exe >/dev/null 2>&1; then
          PLAYER="powershell.exe"
        fi
      fi
      # Linux native players (also works if WSL has PulseAudio via WSLg)
      if [ -z "$PLAYER" ]; then
        for cmd in paplay ffplay aplay; do
          if command -v "$cmd" >/dev/null 2>&1; then
            PLAYER="$cmd"
            break
          fi
        done
      fi
    fi
    
    # No local player found — forward to relay (remote SSH / headless)
    if [ -z "$PLAYER" ]; then
      curl -s --connect-timeout 1 "http://127.0.0.1:${SOUND_PORT}/${EVENT}" &>/dev/null &
      exit 0
    fi
    
    # Collect candidates from manifest.json files
    # If theme=mix, scan all directories; otherwise only the matching one
    CANDIDATES=$(python3 -c "
    import json, os, sys
    
    assets_dir = '$ASSETS_DIR'
    theme = '$THEME'
    event = '$EVENT'
    
    candidates = []
    for d in sorted(os.listdir(assets_dir)):
        theme_dir = os.path.join(assets_dir, d)
        manifest = os.path.join(theme_dir, 'manifest.json')
        if not os.path.isfile(manifest):
            continue
        # Filter by theme: 'mix' uses all, otherwise match directory name
        if theme != 'mix' and d != theme:
            continue
        try:
            m = json.load(open(manifest))
            for f in m.get(event, []):
                path = os.path.join(theme_dir, f)
                if os.path.exists(path):
                    candidates.append(path)
        except (json.JSONDecodeError, IOError):
            continue
    
    for c in candidates:
        print(c)
    " 2>/dev/null)
    
    [ -z "$CANDIDATES" ] && exit 0
    
    # Pick random candidate (compatible with bash 3.x on macOS)
    IFS=$'\n' read -r -d '' -a FILES <<< "$CANDIDATES" || true
    COUNT=${#FILES[@]}
    [ "$COUNT" -eq 0 ] && exit 0
    FILE="${FILES[$((RANDOM % COUNT))]}"
    
    [ -z "$FILE" ] && exit 0
    
    # Convert path for WSL players that need Windows paths
    PLAY_FILE="$FILE"
    if [ "$IS_WSL" = true ] && [ "$PLAYER" = "ffplay.exe" -o "$PLAYER" = "powershell.exe" ]; then
      PLAY_FILE=$(wslpath -w "$FILE" 2>/dev/null || echo "$FILE")
    fi
    
    # Play with volume control (cross-platform)
    case "$PLAYER" in
      afplay)
        VOL=$(printf '%.2f' "$(echo "$SOUND_VOLUME / 100" | bc -l)")
        afplay -v "$VOL" "$FILE" &
        ;;
      paplay)
        PA_VOL=$((SOUND_VOLUME * 65536 / 100))
        paplay --volume="$PA_VOL" "$FILE" &
        ;;
      ffplay)
        ffplay -nodisp -autoexit -loglevel quiet -volume "$SOUND_VOLUME" "$FILE" &
        ;;
      ffplay.exe)
        ffplay.exe -nodisp -autoexit -loglevel quiet -volume "$SOUND_VOLUME" "$PLAY_FILE" &>/dev/null &
        ;;
      powershell.exe)
        powershell.exe -NoProfile -Command "\$w=New-Object -ComObject WMPlayer.OCX;\$w.settings.volume=$SOUND_VOLUME;\$w.URL='${PLAY_FILE}';\$null=\$w.controls;Start-Sleep 4;\$w.close()" &>/dev/null &
        ;;
      aplay)
        aplay -q "$FILE" &
        ;;
    esac
    exit 0
    

Read the script before you install anything that runs on your machine. This is the one part of a plugin that acts without being asked.

@6m1w
Ships withsound-fx

Themed sound effects for Claude Code / Open Code — JARVIS, GLaDOS, Pikachu, and 9 more themes for your terminal

Stars on GitHub

Momentum

stars in total
48
Star history of 6m1w/claude-sound-fx on GitHub, a chart by star-history.com

More plugins that ship hooks.

i-have-adhd

i-have-adhd

A skill that shapes Claude Code's output for readers with ADHD: it leads with the next action, numbers multi-step work, restates state across turns, drops tangents, gives specific time estimates, and makes progress visible. Invoke it with /i-h.

1 skill1 hook60k
@ayghri@ayghri
Install Plugin
pua

pua

A Claude Code plugin that makes the assistant work harder when it stalls or repeats failures. It adds pressure-style coaching, plus skills for workplace reminders and senior engineer, CTO and team-lead modes for planning and execution.

12 skills+320k
@tanweai@tanweai
Install Plugin
claude-obsidian

claude-obsidian

Turns the sources you read, such as papers, articles and transcripts, into a linked wiki of Markdown notes in Obsidian. Claude keeps sources and citations so every summary can be traced back to its origin.

15 skills+216k
@agricidaniel@agricidaniel
Install Plugin
obsidian-second-brain

obsidian-second-brain

Gives Claude Code a persistent second brain stored as plain markdown in an Obsidian vault. Notes rewrite themselves as new sources arrive, and scheduled agents handle research synthesis and note capture.

1 skill+25.3k
@eugeniughelbur@eugeniughelbur
Install Plugin
arscontexta

arscontexta

A Claude Code plugin that builds a personal knowledge system through conversation, with skills for adding knowledge domains, checking vault health, getting methodology guidance, and evolving the system over time.

10 skills+23.5k
@agenticnotetaking@agenticnotetaking
Install Plugin
pro-workflow

pro-workflow

A Claude Code workflow plugin that learns from your corrections and keeps a self-correcting memory across sessions. It adds skills for agent teams, parallel worktree batch changes, bug capture as GitHub issues, project auto-setup and context compaction.

41 skills+32.9k
@rohitg00@rohitg00
Install Plugin
engram

engram

Helps you learn any topic with a first-principles curriculum, guided tutoring, and spaced review that schedules free-recall practice. Includes coaching for retention stats and study strategy.

3 skills+21.5k
@nagisanzenin@nagisanzenin
Install Plugin
hey

hey

A command line tool for HEY that lets you read and send email, manage contacts, labels, calendars, todos, habits, time tracking and journal entries from the terminal or from your coding agent.

1 skill1 hook423
@basecamp@basecamp
Install Plugin

Questions about the hooks in sound-fx.

Which coding agents can use the hooks in sound-fx?
The hooks in sound-fx install in Claude Code and Cursor: each runs Claude Code hooks from .claude/settings.json, so copy the hooks there.