Customizing Hook Responses
Relevant source files
The following files were used as context for generating this wiki page:
The voice-elevenlabs plugin leverages Claude Code's hook system to provide automatic, audible notifications for key events. This creates a hands-free experience, announcing when tasks are complete or when user input is required. The system is configured through a central JSON file and executed via shell scripts that generate and speak context-aware messages.
This functionality is designed to provide ambient feedback, such as announcing the completion of a subagent task or when Claude has finished generating a response. The voice notifications are handled by the external claude-voice-notifications CLI tool, which is a required dependency.
Sources: README.md:65-71, hooks/hooks.json, skills/voice-responses.md:12-13
Hook Configuration
The core of the system is hooks/hooks.json, which defines which events trigger a voice response. Each hook is an object specifying the event, the type of action (always command), and the command to execute.
Sources: hooks/hooks.json
Registered Hooks
The plugin registers three hooks to automatically trigger voice notifications.
| Event | Command | Description |
|---|---|---|
Stop | ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/stop-voice.sh | Announces "[project]: done" when Claude finishes responding. |
SubagentStop | ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/subagent-voice.sh | Announces "[project]: [task]" when a subagent completes its task. |
Notification | claude-voice-notifications | Announces when Claude needs permission or input. |
Sources: hooks/hooks.json:2-18, README.md:65-71
Configuration Snippet
The following JSON from hooks/hooks.json defines the event-to-command mappings. The ${CLAUDE_PLUGIN_ROOT} variable ensures the scripts are located correctly within the plugin's directory.
{
"hooks": [
{
"event": "Stop",
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/scripts/stop-voice.sh",
"description": "Announce '[project]: done' when Claude finishes"
},
{
"event": "SubagentStop",
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/scripts/subagent-voice.sh",
"description": "Announce '[project]: [task]' when subagent completes"
},
{
"event": "Notification",
"type": "command",
"command": "claude-voice-notifications",
"description": "Announce when Claude needs permission or input"
}
]
}
Sources: hooks/hooks.json:1-19
Notification Mechanism
All hook scripts use a unified mechanism to trigger text-to-speech. They construct a JSON payload and pipe it to the claude-voice-notifications CLI tool. This tool is responsible for communicating with the ElevenLabs API to generate and play the audio.
This diagram illustrates the general flow from a Claude Code event to the final audio output.
Hook Implementations
Stop Event Hook
This hook provides a simple notification that Claude has finished its work. The script stop-voice.sh is executed.
Logic Flow:
- Reads JSON input from
stdin. - Extracts the current working directory (
cwd). - Determines the project name by taking the
basenameof thecwd. - Constructs a message:
"[project]: done"if a project name is found, otherwise"Claude done". - Pipes the final message to
claude-voice-notifications.
This diagram shows the logic within stop-voice.sh.
Sources: hooks/scripts/stop-voice.sh:5-19
SubagentStop Event Hook
This hook provides a more detailed notification about the completion of a subagent task. The script subagent-voice.sh is more complex, attempting to extract task details from the conversation transcript.
Logic Flow:
- Reads JSON input from
stdin. - Extracts
cwdandtranscript_path. - Gets the project name from
cwd. - If a
transcript_pathexists, it usesjqto parse the transcript file and find thedescriptionfrom the last "Task" tool use. - Constructs a message based on the available information:
- If project and description exist:
"[project]: [first 30 chars of description]" - If only description exists:
"Done: [first 40 chars of description]" - If only project exists:
"[project] task done" - If neither exists:
"Task completed"
- If project and description exist:
- Pipes the final message to
claude-voice-notifications.
This diagram shows the decision logic for message construction in subagent-voice.sh.
Sources: hooks/scripts/subagent-voice.sh:5-36
Notification Event Hook
This hook is the simplest. It directly invokes the claude-voice-notifications command without a wrapper script. According to the documentation, its purpose is to "Announce when Claude needs permission or input," providing an audible cue for user interaction prompts.
Sources: hooks/hooks.json:15-18, README.md:70-71