Published: January 29, 2025
Ever wanted instant visual celebration when your AI assistant completes a task? Today I'll walk you through implementing Claude Code hooks to trigger Raycast confetti whenever markdown files are written to specific directories - perfect for celebrating successful YouTube video summarizations!
The Problem: Silent Success
When using Claude Code for batch operations like summarizing YouTube videos, the process can take several minutes. Without visual feedback, it's hard to know when the task completes, especially when working across multiple applications or windows.
What I wanted:
- Instant notification when summary files are created
- System-wide visibility (works regardless of active window)
- Celebratory feedback for successful workflows
The Solution: Claude Code Hooks + Raycast
Claude Code provides a powerful hooks system that can execute shell commands in response to tool usage events. Combined with Raycast's confetti extension, we can create delightful visual feedback.
Implementation Journey
Step 1: Understanding Claude Code Hooks
Claude Code hooks are configured in ~/.claude/settings.json and support several event types:
PreToolUse - Before tool execution
PostToolUse - After tool completion
UserPromptSubmit - When user submits a prompt
SessionStart/End - Session lifecycle events
For our use case, PostToolUse is perfect since we want to celebrate after successful file creation.
Step 2: Basic Hook Configuration
The initial configuration was straightforward:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "open \"raycast://extensions/raycast/raycast/confetti\""
}
]
}
]
}
}
This triggers confetti on ANY Write operation - great for testing, but too noisy for production use.
Step 3: The Debugging Challenge
Adding path filtering proved more complex than expected. Initial attempts using environment variables failed:
echo '$HOOK_INPUT' | jq -r '.tool_input.file_path'
The breakthrough: Hook data comes through stdin, not environment variables!
Step 4: Discovering the Data Structure
By capturing stdin data, I discovered the exact JSON structure:
{
"session_id": "44d2a57c-ea8a-402d-b298-cd3f2041d713",
"transcript_path": "/Users/omathalye/.claude/projects/.../transcript.jsonl",
"cwd": "/Users/omathalye/fun/mcp-servers/youtube-transcript",
"hook_event_name": "PostToolUse",
"tool_name": "Write",
"tool_input": {
"file_path": "/Users/omathalye/fun/second-brain/docs/miscellaneous/test.md",
"content": "..."
},
"tool_response": {
"type": "create",
"filePath": "/Users/omathalye/fun/second-brain/docs/miscellaneous/test.md",
"content": "...",
"structuredPatch": []
}
}
The key insight: tool_input.file_path contains the target file path!
Step 5: Perfect Path Filtering
With the correct data structure, the final hook became elegant:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "case \"$(jq -r '.tool_input.file_path' 2>/dev/null)\" in *second-brain/docs/*.md) open \"raycast://extensions/raycast/raycast/confetti\" ;; esac"
}
]
}
]
}
}
This command:
- Reads JSON from stdin
- Extracts the file path using
jq
- Uses shell pattern matching to check if it matches
*second-brain/docs/*.md
- Triggers Raycast confetti only for matching files
Key Technical Insights
Hook Data Flow
- Input: JSON via stdin (not environment variables)
- Processing: Shell commands can process this JSON
- Output: Commands run asynchronously, don't block Claude Code
Error Handling
The 2>/dev/null ensures jq parsing errors don't break the hook. The case statement gracefully handles any parsing failures.
Pattern Matching Strategy
Using shell glob patterns (*second-brain/docs/*.md) is more reliable than regex for path matching in this context.
Real-World Impact
This setup now provides:
✅ Instant feedback when YouTube summaries complete
✅ System-wide visibility - works regardless of active application
✅ Selective triggering - only for relevant content files
✅ Reliable operation - graceful error handling
✅ Delightful UX - celebratory confetti animation
Use Cases Beyond YouTube Summaries
This pattern works for any file-based workflows:
- Documentation generation - Celebrate when docs are updated
- Code generation - Visual feedback for AI-generated code files
- Report creation - Notification when analysis reports complete
- Content publishing - Celebrate when blog posts are written
Configuration Tips
Multiple Path Patterns
You can match multiple directories by extending the pattern:
case "$(jq -r '.tool_input.file_path')" in
*second-brain/docs/*.md|*projects/*/README.md)
open "raycast://extensions/raycast/raycast/confetti"
;;
esac
Hooks can match different tools beyond Write:
{
"matcher": "Edit",
"hooks": [...]
}
Custom Notifications
Replace Raycast confetti with any notification system:
osascript -e 'display notification "File created!" with title "Claude Code"'
terminal-notifier -message "File created!" -title "Claude Code" -activate com.googlecode.iterm2
afplay /System/Library/Sounds/Glass.aiff
Advanced Power User Applications
While celebratory notifications are fun, Claude Code hooks unlock far more sophisticated automation possibilities for power users:
Automated Deployment Pipelines
case "$(jq -r '.tool_input.file_path')" in
*/docs/*.md)
cd "$(jq -r '.cwd')" && git add . && git commit -m "Update docs" && git push
;;
esac
Intelligent File Organization
content="$(jq -r '.tool_input.content')"
if echo "$content" | grep -q "TODO\|FIXME"; then
mv "$(jq -r '.tool_input.file_path')" ./pending-review/
fi
Integration with External Systems
case "$(jq -r '.tool_name')" in
"Write")
curl -X POST "https://api.notion.so/v1/pages" \
-H "Authorization: Bearer $NOTION_TOKEN" \
-d @payload.json
;;
"Bash")
echo "$(jq -r '.tool_input.command')" | logger -t claude-code
;;
esac
Quality Assurance Automation
if [[ "$(jq -r '.tool_input.file_path')" == *.js ]]; then
eslint "$(jq -r '.tool_input.file_path')" --fix
elif [[ "$(jq -r '.tool_input.file_path')" == *.md ]]; then
markdownlint "$(jq -r '.tool_input.file_path')" --fix
fi
Security and Compliance
if grep -q "password\|api_key\|token" "$(jq -r '.tool_input.file_path')"; then
slack-notify "#security" "Potential secrets detected in $(jq -r '.tool_input.file_path')"
git filter-branch --force --index-filter "git rm --cached --ignore-unmatch $(jq -r '.tool_input.file_path')"
fi
Workflow Orchestration
file_path="$(jq -r '.tool_input.file_path')"
case "$file_path" in
*/requirements.txt)
pip install -r "$file_path"
;;
*/Dockerfile)
docker build -t "$(basename $(dirname $file_path))" "$(dirname $file_path)"
;;
*/.github/workflows/*.yml)
act --dry-run
;;
esac
Advanced Monitoring and Analytics
{
echo "timestamp: $(date -Iseconds)"
echo "tool: $(jq -r '.tool_name')"
echo "session: $(jq -r '.session_id')"
echo "file_type: $(jq -r '.tool_input.file_path' | sed 's/.*\.//')"
echo "content_length: $(jq -r '.tool_input.content | length')"
} >> ~/.claude/productivity_metrics.log
if [[ $(date +%w) == 0 ]]; then
generate_weekly_report.py ~/.claude/productivity_metrics.log
fi
Context-Aware Development Environment
cwd="$(jq -r '.cwd')"
if [[ -f "$cwd/package.json" ]]; then
nvm use
npm install
elif [[ -f "$cwd/requirements.txt" ]]; then
pyenv local $(cat .python-version 2>/dev/null || echo "3.11")
pip install -r requirements.txt
elif [[ -f "$cwd/Cargo.toml" ]]; then
rustup update
cargo check
fi
These advanced use cases transform Claude Code hooks from simple notifications into a comprehensive automation framework that can integrate AI assistance seamlessly into existing development workflows, CI/CD pipelines, and productivity systems.
Troubleshooting Common Issues
Hook Not Triggering
- Restart Claude Code after configuration changes
- Check JSON syntax in settings.json
- Test with simplified command (remove path filtering initially)
Path Matching Issues
- Capture actual paths with debugging commands
- Use absolute paths in patterns when needed
- Test patterns in terminal before using in hooks
JSON Parsing Errors
- Add error handling with
2>/dev/null
- Validate jq syntax separately
- Use fallback values with
|| echo ''
Conclusion
Claude Code hooks provide a powerful way to integrate AI workflows with system-level automation. While we started with celebratory confetti, the same foundational pattern enables sophisticated deployment pipelines, quality assurance automation, and intelligent workflow orchestration.
By understanding the data flow and properly handling the JSON input, you can create comprehensive automation that makes AI assistance not just more delightful, but deeply integrated into professional development workflows.
The combination of Claude Code's flexibility and creative hook implementations can transform how AI assistants integrate with existing tools, systems, and processes - moving beyond simple task completion to intelligent, context-aware automation.
Resources
This blog post was written with assistance from Claude Code, which also triggers confetti upon completion! 🎉