8.1 KiB
8.1 KiB
Automation Guide [Claude Code only]
This guide explains how automation works for Claude Code and how to extend it for your needs.
🔄 How Automation Works
The Hook System
Claude Code supports hooks that trigger actions based on events:
{
"hooks": {
"EventName": [
{
"matcher": "pattern",
"hooks": [
{
"type": "command",
"command": "script-to-run.sh"
}
]
}
]
}
}
Current Automations
1. Automatic Quality Checks
- Trigger: After any file edit/write
- Script:
.claude/tools/make-check.sh
- What it does:
- Finds the nearest Makefile
- Runs
make check
- Reports results
- Works with monorepos
2. Desktop Notifications
- Trigger: Any Claude Code notification event
- Script:
.claude/tools/notify.sh
- Features:
- Native notifications on all platforms
- Shows project context
- Non-intrusive fallbacks
🛠️ The Make Check System
How It Works
The make-check.sh
script is intelligent:
# 1. Detects what file was edited
/path/to/project/src/component.tsx
# 2. Looks for Makefile in order:
/path/to/project/src/Makefile # Local directory
/path/to/project/Makefile # Project root
/path/to/Makefile # Parent directories
# 3. Runs make check from appropriate location
cd /path/to/project && make check
Setting Up Your Makefile
Create a Makefile
in your project root:
.PHONY: check
check: format lint typecheck test
.PHONY: format
format:
@echo "Formatting code..."
# Python
black . || true
isort . || true
# JavaScript/TypeScript
prettier --write . || true
.PHONY: lint
lint:
@echo "Linting code..."
# Python
ruff check . || true
# JavaScript/TypeScript
eslint . --fix || true
.PHONY: typecheck
typecheck:
@echo "Type checking..."
# Python
mypy . || true
# TypeScript
tsc --noEmit || true
.PHONY: test
test:
@echo "Running tests..."
# Python
pytest || true
# JavaScript
npm test || true
Customizing Quality Checks
For different languages/frameworks:
Python Project:
check: format lint typecheck test
format:
uv run black .
uv run isort .
lint:
uv run ruff check .
typecheck:
uv run mypy .
test:
uv run pytest
Node.js Project:
check: format lint typecheck test
format:
npm run format
lint:
npm run lint
typecheck:
npm run typecheck
test:
npm test
Go Project:
check: format lint test
format:
go fmt ./...
lint:
golangci-lint run
test:
go test ./...
🔔 Notification System
How Notifications Work
- Event Occurs: Claude Code needs attention
- Hook Triggered: Notification hook activates
- Context Gathered: Project name, session ID extracted
- Platform Detection: Appropriate notification method chosen
- Notification Sent: Native notification appears
Customizing Notifications
Edit .claude/tools/notify.sh
:
# Add custom notification categories
case "$MESSAGE" in
*"error"*)
URGENCY="critical"
ICON="error.png"
;;
*"success"*)
URGENCY="normal"
ICON="success.png"
;;
*)
URGENCY="low"
ICON="info.png"
;;
esac
Adding Sound Alerts
macOS:
# Add to notify.sh
afplay /System/Library/Sounds/Glass.aiff
Linux:
# Add to notify.sh
paplay /usr/share/sounds/freedesktop/stereo/complete.oga
Windows/WSL:
# Add to PowerShell section
[System.Media.SystemSounds]::Exclamation.Play()
🎯 Creating Custom Automations
Example: Auto-Format on Save
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": ".claude/tools/auto-format.sh"
}
]
}
]
}
}
Create .claude/tools/auto-format.sh
:
#!/usr/bin/env bash
set -euo pipefail
# Read JSON input
JSON_INPUT=$(cat)
# Extract file path
FILE_PATH=$(echo "$JSON_INPUT" | grep -o '"file_path"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*"file_path"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/')
# Format based on file extension
case "$FILE_PATH" in
*.py)
black "$FILE_PATH"
;;
*.js|*.jsx|*.ts|*.tsx)
prettier --write "$FILE_PATH"
;;
*.go)
gofmt -w "$FILE_PATH"
;;
esac
Example: Git Auto-Commit
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": ".claude/tools/auto-commit.sh"
}
]
}
]
}
}
Create .claude/tools/auto-commit.sh
:
#!/usr/bin/env bash
# Auto-commit changes with descriptive messages
# ... parse JSON and get file path ...
# Generate commit message
COMMIT_MSG="Auto-update: $(basename "$FILE_PATH")"
# Stage and commit
git add "$FILE_PATH"
git commit -m "$COMMIT_MSG" --no-verify || true
Example: Test Runner
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": ".claude/tools/run-tests.sh"
}
]
}
]
}
}
🏗️ Advanced Automation Patterns
Conditional Execution
#!/usr/bin/env bash
# Only run on specific files
FILE_PATH=$(extract_file_path_from_json)
# Only check Python files
if [[ "$FILE_PATH" == *.py ]]; then
python -m py_compile "$FILE_PATH"
fi
# Only test when source files change
if [[ "$FILE_PATH" == */src/* ]]; then
npm test
fi
Parallel Execution
#!/usr/bin/env bash
# Run multiple checks in parallel
{
echo "Starting parallel checks..."
# Run all checks in background
make format &
PID1=$!
make lint &
PID2=$!
make typecheck &
PID3=$!
# Wait for all to complete
wait $PID1 $PID2 $PID3
echo "All checks complete!"
}
Error Handling
#!/usr/bin/env bash
# Graceful error handling
set -euo pipefail
# Trap errors
trap 'echo "Check failed at line $LINENO"' ERR
# Run with error collection
ERRORS=0
make format || ((ERRORS++))
make lint || ((ERRORS++))
make test || ((ERRORS++))
if [ $ERRORS -gt 0 ]; then
echo "⚠️ $ERRORS check(s) failed"
exit 1
else
echo "✅ All checks passed!"
fi
🔧 Debugging Automations
Enable Debug Logging
# Add to any automation script
DEBUG_LOG="/tmp/claude-automation-debug.log"
echo "[$(date)] Script started" >> "$DEBUG_LOG"
echo "Input: $JSON_INPUT" >> "$DEBUG_LOG"
Test Scripts Manually
# Test with sample input
echo '{"file_path": "/path/to/test.py", "success": true}' | .claude/tools/make-check.sh
Common Issues
-
Script Not Executing
- Check file permissions:
chmod +x .claude/tools/*.sh
- Verify path in settings.json
- Check file permissions:
-
No Output
- Check if script outputs to stdout
- Look for error logs in /tmp/
-
Platform-Specific Issues
- Test platform detection logic
- Ensure fallbacks work
🚀 Best Practices
- Fast Execution: Keep automations under 5 seconds
- Fail Gracefully: Don't break Claude Code workflow
- User Feedback: Provide clear success/failure messages
- Cross-Platform: Test on Mac, Linux, Windows, WSL
- Configurable: Allow users to customize behavior
📊 Performance Optimization
Caching Results
# Cache expensive operations
CACHE_FILE="/tmp/claude-check-cache"
CACHE_AGE=$(($(date +%s) - $(stat -f %m "$CACHE_FILE" 2>/dev/null || echo 0)))
if [ $CACHE_AGE -lt 300 ]; then # 5 minutes
cat "$CACHE_FILE"
else
make check | tee "$CACHE_FILE"
fi
Incremental Checks
# Only check changed files
CHANGED_FILES=$(git diff --name-only HEAD)
for file in $CHANGED_FILES; do
case "$file" in
*.py) pylint "$file" ;;
*.js) eslint "$file" ;;
esac
done
🔗 Related Documentation
- Command Reference - Available commands
- Notifications Guide - Desktop alerts