# 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: ```json { "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: ```bash # 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: ```makefile .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**: ```makefile 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**: ```makefile check: format lint typecheck test format: npm run format lint: npm run lint typecheck: npm run typecheck test: npm test ``` **Go Project**: ```makefile check: format lint test format: go fmt ./... lint: golangci-lint run test: go test ./... ``` ## 🔔 Notification System ### How Notifications Work 1. **Event Occurs**: Claude Code needs attention 2. **Hook Triggered**: Notification hook activates 3. **Context Gathered**: Project name, session ID extracted 4. **Platform Detection**: Appropriate notification method chosen 5. **Notification Sent**: Native notification appears ### Customizing Notifications Edit `.claude/tools/notify.sh`: ```bash # 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**: ```bash # Add to notify.sh afplay /System/Library/Sounds/Glass.aiff ``` **Linux**: ```bash # Add to notify.sh paplay /usr/share/sounds/freedesktop/stereo/complete.oga ``` **Windows/WSL**: ```powershell # Add to PowerShell section [System.Media.SystemSounds]::Exclamation.Play() ``` ## 🎯 Creating Custom Automations ### Example: Auto-Format on Save ```json { "hooks": { "PostToolUse": [ { "matcher": "Write|Edit", "hooks": [ { "type": "command", "command": ".claude/tools/auto-format.sh" } ] } ] } } ``` Create `.claude/tools/auto-format.sh`: ```bash #!/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 ```json { "hooks": { "PostToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": ".claude/tools/auto-commit.sh" } ] } ] } } ``` Create `.claude/tools/auto-commit.sh`: ```bash #!/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 ```json { "hooks": { "PostToolUse": [ { "matcher": "Write", "hooks": [ { "type": "command", "command": ".claude/tools/run-tests.sh" } ] } ] } } ``` ## 🏗️ Advanced Automation Patterns ### Conditional Execution ```bash #!/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 ```bash #!/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 ```bash #!/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 ```bash # 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 ```bash # Test with sample input echo '{"file_path": "/path/to/test.py", "success": true}' | .claude/tools/make-check.sh ``` ### Common Issues 1. **Script Not Executing** - Check file permissions: `chmod +x .claude/tools/*.sh` - Verify path in settings.json 2. **No Output** - Check if script outputs to stdout - Look for error logs in /tmp/ 3. **Platform-Specific Issues** - Test platform detection logic - Ensure fallbacks work ## 🚀 Best Practices 1. **Fast Execution**: Keep automations under 5 seconds 2. **Fail Gracefully**: Don't break Claude Code workflow 3. **User Feedback**: Provide clear success/failure messages 4. **Cross-Platform**: Test on Mac, Linux, Windows, WSL 5. **Configurable**: Allow users to customize behavior ## 📊 Performance Optimization ### Caching Results ```bash # 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 ```bash # 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](commands.md) - Available commands - [Notifications Guide](notifications.md) - Desktop alerts