Back to catalogue
NotificationSubagentStopSubagentStopWhen a subagent finishes· non-blocking
Subagent end voice summary
Announces the end of a subagent with a voice message. Uses a file lock to avoid TTS overlap when several subagents finish in parallel.
Use cases
- Audio tracking of completed parallel tasks
- Ordered subagent-end announcements without sound collisions
Providers & tags
Claude Code
#tts#subagent#voice#parallel-agents#locking#audio
settings.json fragment
{
"hooks": {
"SubagentStop": [
{
"hooks": [
{
"command": "node $CLAUDE_PROJECT_DIR/.claude/hooks/subagent-stop-tts.mjs",
"type": "command"
}
],
"matcher": ""
}
]
}
}Script · .claude/hooks/subagent-stop-tts.mjs
#!/usr/bin/env node
// Annonce la fin d'un sous-agent par TTS (SubagentStop)
import { readFileSync } from 'fs';
import { execSync } from 'child_process';
import { fileURLToPath } from 'url';
function defaultExec(cmd) {
execSync(cmd, { timeout: 10_000, stdio: 'ignore', shell: true });
}
export function run(input, { exec = defaultExec, platform = process.platform } = {}) {
const summary = input?.summary ?? '';
const text = summary
? `Sous-agent terminé : ${summary.slice(0, 100).replace(/[`*_#]/g, '')}`
: 'Sous-agent terminé';
const safe = text.replace(/"/g, '\\"');
try {
if (platform === 'darwin') exec(`say "${safe}"`);
else exec(`espeak "${safe}" 2>/dev/null`);
} catch {}
return text;
}
/* v8 ignore next 5 */
if (process.argv[1] === fileURLToPath(import.meta.url)) {
let input = {};
try { input = JSON.parse(readFileSync(0, 'utf8')); } catch {}
run(input);
}