Claude Code Hooks完全実装ガイド:プロダクション環境でのハンズオン運用術【2025年8月最新】¶
はじめに¶
Claude Code Hooks革命記事で概要をお伝えしたClaude Code Hooksですが、実際のプロダクション環境での導入には多くの実装上の課題があります。
本記事では、実際に動作するコード例とプロダクション運用での注意点にフォーカスして、Claude Code Hooksを確実に導入・運用するための完全実装ガイドを提供します。
この記事のポイント¶
ゼロダウンタイム導入
既存プロジェクトへの段階的導入でリスク最小化
実践的な設定集
コピー&ペーストで使える実証済み設定ファイル
エラーハンドリング
プロダクション環境での確実な障害対応
パフォーマンス最適化
大規模プロジェクトでの実行効率向上
🛠️ プロダクション準備:環境構築編¶
1. ディレクトリ構造の準備¶
まず、Claude Code Hooksの設定を組織的に管理するためのディレクトリ構造を構築します:
# プロジェクトルートでの実行
mkdir -p .claude/{hooks,scripts,logs,configs}
# Claude Code設定ディレクトリ準備
mkdir -p ~/.claude/{hooks,templates,backups}
# ログローテーション設定
sudo mkdir -p /var/log/claude-hooks
sudo chown $USER:$USER /var/log/claude-hooks
2. 基盤となる設定ファイルの作成¶
# ~/.claude/settings.toml
[hooks]
log_level = "INFO"
log_file = "/var/log/claude-hooks/hooks.log"
timeout = 300 # 5分タイムアウト
retry_count = 3
enable_background = true
[hooks.environment]
# 環境変数の設定
PATH_EXTENSION = "/usr/local/bin:~/.local/bin"
NODE_ENV = "development"
PYTHONPATH = "."
[hooks.security]
# セキュリティ設定
max_file_size = "10MB"
allowed_extensions = ["py", "js", "ts", "jsx", "tsx", "md", "yml", "yaml", "json"]
blocked_paths = ["node_modules", ".git", "dist", "build", "__pycache__"]
[hooks.performance]
# パフォーマンス設定
parallel_execution = true
max_concurrent_hooks = 4
cache_enabled = true
cache_ttl = 300 # 5分
3. 共通スクリプトライブラリの準備¶
#!/bin/bash
# ~/.claude/scripts/common.sh - 共通関数ライブラリ
# ログ出力関数
log() {
local level=$1
local message=$2
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$timestamp] [$level] $message" | tee -a /var/log/claude-hooks/hooks.log
}
# エラーハンドリング関数
handle_error() {
local exit_code=$1
local command=$2
local file_path=$3
if [ $exit_code -ne 0 ]; then
log "ERROR" "Command '$command' failed with exit code $exit_code for file: $file_path"
# Slack通知(オプション)
if command -v slack-notify &> /dev/null; then
slack-notify "#dev-alerts" "🚨 Hook execution failed: $command ($file_path)"
fi
return $exit_code
fi
return 0
}
# ファイル検証関数
validate_file() {
local file_path=$1
local max_size=${2:-10485760} # 10MB default
# ファイル存在確認
if [ ! -f "$file_path" ]; then
log "ERROR" "File not found: $file_path"
return 1
fi
# ファイルサイズ確認
local file_size=$(stat -f%z "$file_path" 2>/dev/null || stat -c%s "$file_path" 2>/dev/null)
if [ $file_size -gt $max_size ]; then
log "WARN" "File size exceeds limit: $file_path ($file_size bytes)"
return 2
fi
return 0
}
# プロセス管理関数
is_process_running() {
local process_name=$1
pgrep "$process_name" > /dev/null 2>&1
}
wait_for_process() {
local process_name=$1
local timeout=${2:-30}
local count=0
while is_process_running "$process_name" && [ $count -lt $timeout ]; do
sleep 1
((count++))
done
if [ $count -ge $timeout ]; then
log "WARN" "Process $process_name did not finish within $timeout seconds"
return 1
fi
return 0
}
🔧 言語別実装パターン¶
Python プロジェクト完全設定¶
# Python専用の包括的設定
[[hooks]]
name = "Python File Validation"
event = "PreToolUse"
[hooks.matcher]
tool_name = "edit_file"
file_paths = ["*.py"]
command = """
source ~/.claude/scripts/common.sh
for file in $CLAUDE_FILE_PATHS; do
log "INFO" "Validating Python file: $file"
# ファイル検証
validate_file "$file" || exit 1
# Python文法チェック
python -m py_compile "$file"
handle_error $? "python -m py_compile" "$file" || exit 1
# Import検証
python -c "import ast; ast.parse(open('$file').read())"
handle_error $? "AST parse check" "$file" || exit 1
log "INFO" "✅ Python file validation passed: $file"
done
"""
[[hooks]]
name = "Python Format and Quality"
event = "PostToolUse"
[hooks.matcher]
tool_name = "edit_file"
file_paths = ["*.py"]
command = """
source ~/.claude/scripts/common.sh
# 同時実行を防ぐためのロック
LOCK_FILE="/tmp/python-format.lock"
if [ -f "$LOCK_FILE" ]; then
wait_for_process "python-format" 30
fi
touch "$LOCK_FILE"
trap 'rm -f "$LOCK_FILE"' EXIT
for file in $CLAUDE_FILE_PATHS; do
log "INFO" "Formatting Python file: $file"
# バックアップ作成
cp "$file" "$file.backup"
# フォーマット実行
black "$file" --line-length 88 --target-version py39
handle_error $? "black" "$file" || { cp "$file.backup" "$file"; exit 1; }
isort "$file" --profile black
handle_error $? "isort" "$file" || { cp "$file.backup" "$file"; exit 1; }
# Ruff検証
ruff check "$file" --fix
handle_error $? "ruff check" "$file" || { cp "$file.backup" "$file"; exit 1; }
# バックアップ削除
rm -f "$file.backup"
log "INFO" "✅ Python formatting completed: $file"
done
"""
[[hooks]]
name = "Python Test Runner"
event = "PostToolUse"
run_in_background = true
[hooks.matcher]
tool_name = "edit_file"
file_paths = ["src/**/*.py", "tests/**/*.py", "test_*.py", "*_test.py"]
command = """
source ~/.claude/scripts/common.sh
log "INFO" "Starting Python test execution"
# プロジェクトルート検出
PROJECT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
cd "$PROJECT_ROOT"
# Virtual environment確認
if [ -f "venv/bin/activate" ]; then
source venv/bin/activate
log "INFO" "Activated virtual environment"
elif [ -f ".venv/bin/activate" ]; then
source .venv/bin/activate
log "INFO" "Activated .venv virtual environment"
fi
# テスト実行
if [ -f "pytest.ini" ] || [ -f "pyproject.toml" ] || [ -f "setup.cfg" ]; then
# pytest設定ファイルが存在する場合
pytest --tb=short -q --no-header --disable-warnings
test_result=$?
else
# デフォルト設定でテスト実行
python -m pytest tests/ -v --tb=short
test_result=$?
fi
if [ $test_result -eq 0 ]; then
log "INFO" "✅ All Python tests passed"
# カバレッジレポート(optional)
if command -v coverage &> /dev/null; then
coverage report --show-missing --skip-covered | tail -n 10
fi
else
log "ERROR" "❌ Python tests failed with exit code: $test_result"
fi
exit $test_result
"""
[[hooks]]
name = "Python Security Scan"
event = "PostToolUse"
run_in_background = true
[hooks.matcher]
tool_name = "edit_file"
file_paths = ["*.py"]
command = """
source ~/.claude/scripts/common.sh
log "INFO" "Starting Python security scan"
for file in $CLAUDE_FILE_PATHS; do
# Banditセキュリティチェック
if command -v bandit &> /dev/null; then
bandit -r "$file" -f json -q 2>/dev/null | jq -r '.results[] | select(.issue_severity == "HIGH" or .issue_severity == "MEDIUM") | "\(.issue_severity): \(.issue_text) (\(.filename):\(.line_number))"'
if [ ${PIPESTATUS[0]} -ne 0 ]; then
log "WARN" "Security issues found in: $file"
fi
fi
# 機密情報検出
if grep -E "(password|secret|key|token|api_key)" "$file" | grep -v "#"; then
log "WARN" "Potential secrets detected in: $file"
fi
done
log "INFO" "Python security scan completed"
"""
TypeScript/React プロジェクト設定¶
[[hooks]]
name = "TypeScript Quality Pipeline"
event = "PostToolUse"
[hooks.matcher]
tool_name = "edit_file"
file_paths = ["*.ts", "*.tsx", "*.js", "*.jsx"]
command = """
source ~/.claude/scripts/common.sh
# プロジェクトルート検出
PROJECT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
cd "$PROJECT_ROOT"
log "INFO" "Starting TypeScript quality pipeline"
# Node.jsプロジェクト確認
if [ ! -f "package.json" ]; then
log "ERROR" "package.json not found"
exit 1
fi
# npm/yarn/pnpm検出
PACKAGE_MANAGER="npm"
if [ -f "yarn.lock" ]; then
PACKAGE_MANAGER="yarn"
elif [ -f "pnpm-lock.yaml" ]; then
PACKAGE_MANAGER="pnpm"
fi
log "INFO" "Using package manager: $PACKAGE_MANAGER"
# 依存関係の確認
$PACKAGE_MANAGER list --depth=0 > /dev/null 2>&1
if [ $? -ne 0 ]; then
log "INFO" "Installing dependencies..."
$PACKAGE_MANAGER install
fi
for file in $CLAUDE_FILE_PATHS; do
log "INFO" "Processing TypeScript file: $file"
# Prettierフォーマット
if [ -f ".prettierrc" ] || [ -f ".prettierrc.json" ]; then
npx prettier --write "$file"
handle_error $? "prettier" "$file" || exit 1
fi
# ESLint修正
if [ -f ".eslintrc.js" ] || [ -f ".eslintrc.json" ] || [ -f "eslint.config.js" ]; then
npx eslint --fix "$file"
handle_error $? "eslint" "$file" || exit 1
fi
done
# TypeScript型チェック
if [ -f "tsconfig.json" ]; then
log "INFO" "Running TypeScript type check"
npx tsc --noEmit
handle_error $? "tsc --noEmit" "TypeScript project" || exit 1
fi
log "INFO" "✅ TypeScript quality pipeline completed"
"""
[[hooks]]
name = "React Component Testing"
event = "PostToolUse"
run_in_background = true
[hooks.matcher]
tool_name = "edit_file"
file_paths = ["src/components/**/*.tsx", "src/components/**/*.ts"]
command = """
source ~/.claude/scripts/common.sh
PROJECT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
cd "$PROJECT_ROOT"
log "INFO" "Starting React component testing"
# テストファイルの確認
if [ -d "src/__tests__" ] || [ -d "tests" ] || ls src/**/*.test.* 1> /dev/null 2>&1; then
# Jestテスト実行
if [ -f "jest.config.js" ] || grep -q "jest" package.json; then
npm test -- --watchAll=false --passWithNoTests
test_result=$?
else
log "WARN" "No Jest configuration found"
test_result=0
fi
if [ $test_result -eq 0 ]; then
log "INFO" "✅ React component tests passed"
else
log "ERROR" "❌ React component tests failed"
fi
else
log "INFO" "No tests found, skipping test execution"
test_result=0
fi
# Storybook build test(optional)
if [ -f ".storybook/main.js" ] || [ -f ".storybook/main.ts" ]; then
log "INFO" "Testing Storybook build"
npm run build-storybook > /dev/null 2>&1
if [ $? -eq 0 ]; then
log "INFO" "✅ Storybook build successful"
else
log "WARN" "Storybook build issues detected"
fi
fi
exit $test_result
"""
🛡️ セキュリティと本番環境保護¶
プロダクション環境保護設定¶
[[hooks]]
name = "Production Environment Protection"
event = "PreToolUse"
[hooks.matcher]
tool_name = "edit_file"
file_paths = ["prod/**", "production/**", "*.prod.*", "docker-compose.prod.yml", "k8s/prod/**"]
command = """
source ~/.claude/scripts/common.sh
log "WARN" "🛡️ Production file modification detected!"
# 現在のブランチ確認
CURRENT_BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown")
log "INFO" "Current branch: $CURRENT_BRANCH"
# main/masterブランチでの本番ファイル編集を制限
if [[ "$CURRENT_BRANCH" == "main" ]] || [[ "$CURRENT_BRANCH" == "master" ]]; then
log "ERROR" "Direct modification of production files on main/master branch is prohibited!"
echo "Please create a feature branch for production changes."
exit 1
fi
# 対話的確認(CI環境では自動スキップ)
if [ -z "$CI" ] && [ -z "$GITHUB_ACTIONS" ]; then
echo "You are about to modify production files:"
for file in $CLAUDE_FILE_PATHS; do
echo " - $file"
done
echo ""
read -p "Are you absolutely sure you want to proceed? Type 'CONFIRM' to continue: " confirmation
if [ "$confirmation" != "CONFIRM" ]; then
log "INFO" "Operation cancelled by user"
exit 1
fi
fi
# バックアップ作成
BACKUP_DIR="~/.claude/backups/$(date +%Y%m%d_%H%M%S)"
mkdir -p "$BACKUP_DIR"
for file in $CLAUDE_FILE_PATHS; do
if [ -f "$file" ]; then
cp "$file" "$BACKUP_DIR/$(basename $file)"
log "INFO" "Backup created: $BACKUP_DIR/$(basename $file)"
fi
done
log "INFO" "Production modification approved - backup created in $BACKUP_DIR"
"""
[[hooks]]
name = "Secret Detection and Prevention"
event = "PreToolUse"
[hooks.matcher]
tool_name = "edit_file"
command = """
source ~/.claude/scripts/common.sh
log "INFO" "🔒 Running secret detection scan"
for file in $CLAUDE_FILE_PATHS; do
if [ ! -f "$file" ]; then
continue
fi
# 一般的なシークレットパターン検出
SECRETS_FOUND=false
# API キー検出
if grep -E "(api_key|apikey|api-key)[\s]*=[\s]*['\"][^'\"]{20,}['\"]" "$file"; then
log "ERROR" "API key detected in: $file"
SECRETS_FOUND=true
fi
# パスワード検出
if grep -E "(password|passwd|pwd)[\s]*=[\s]*['\"][^'\"]{8,}['\"]" "$file"; then
log "ERROR" "Password detected in: $file"
SECRETS_FOUND=true
fi
# トークン検出
if grep -E "(token|secret|key)[\s]*=[\s]*['\"][a-zA-Z0-9+/]{20,}['\"]" "$file"; then
log "ERROR" "Token/Secret detected in: $file"
SECRETS_FOUND=true
fi
# AWS認証情報検出
if grep -E "AKIA[0-9A-Z]{16}" "$file"; then
log "ERROR" "AWS Access Key detected in: $file"
SECRETS_FOUND=true
fi
# GitHub Token検出
if grep -E "ghp_[0-9a-zA-Z]{36}" "$file"; then
log "ERROR" "GitHub Token detected in: $file"
SECRETS_FOUND=true
fi
if [ "$SECRETS_FOUND" = true ]; then
echo ""
echo "🚨 SECURITY ALERT: Potential secrets detected!"
echo "Please remove sensitive information before proceeding."
echo ""
echo "Consider using:"
echo " - Environment variables"
echo " - Secret management tools (AWS Secrets Manager, HashiCorp Vault)"
echo " - .env files (with .gitignore)"
echo ""
exit 1
fi
done
log "INFO" "✅ No secrets detected"
"""
📊 パフォーマンス最適化と監視¶
実行時間監視とボトルネック検出¶
[[hooks]]
name = "Performance Monitor"
event = "PostToolUse"
[hooks.matcher]
tool_name = "edit_file"
command = """
source ~/.claude/scripts/common.sh
# パフォーマンスログディレクトリ
PERF_LOG_DIR="/var/log/claude-hooks/performance"
mkdir -p "$PERF_LOG_DIR"
# 実行時間測定開始
START_TIME=$(date +%s.%N)
log "INFO" "📊 Performance monitoring started"
# フック実行完了時の処理
END_TIME=$(date +%s.%N)
EXECUTION_TIME=$(echo "$END_TIME - $START_TIME" | bc)
# パフォーマンスデータ記録
echo "$(date '+%Y-%m-%d %H:%M:%S'),$EXECUTION_TIME,$CLAUDE_TOOL_NAME,$CLAUDE_FILE_PATHS" >> "$PERF_LOG_DIR/execution_times.csv"
# 閾値チェック(5秒以上で警告)
THRESHOLD=5.0
if (( $(echo "$EXECUTION_TIME > $THRESHOLD" | bc -l) )); then
log "WARN" "⚠️ Hook execution exceeded threshold: ${EXECUTION_TIME}s > ${THRESHOLD}s"
# パフォーマンス詳細ログ
{
echo "=== Performance Analysis ==="
echo "Hook: $CLAUDE_TOOL_NAME"
echo "Files: $CLAUDE_FILE_PATHS"
echo "Execution Time: ${EXECUTION_TIME}s"
echo "Timestamp: $(date)"
echo "System Load: $(uptime)"
echo "Memory Usage: $(free -h | grep Mem)"
echo "================================"
} >> "$PERF_LOG_DIR/slow_executions.log"
fi
log "INFO" "✅ Performance monitoring completed (${EXECUTION_TIME}s)"
"""
[[hooks]]
name = "Resource Usage Monitor"
event = "Notification"
command = """
source ~/.claude/scripts/common.sh
# システムリソース監視
CPU_USAGE=$(top -l1 | grep "CPU usage" | awk '{print $3}' | sed 's/%//' 2>/dev/null || echo "0")
MEMORY_USAGE=$(free | grep Mem | awk '{printf "%.1f", $3/$2 * 100.0}' 2>/dev/null || echo "0")
DISK_USAGE=$(df -h . | tail -1 | awk '{print $5}' | sed 's/%//' 2>/dev/null || echo "0")
log "INFO" "💻 System Resources - CPU: ${CPU_USAGE}%, Memory: ${MEMORY_USAGE}%, Disk: ${DISK_USAGE}%"
# 高使用率アラート
if (( $(echo "$CPU_USAGE > 80" | bc -l 2>/dev/null || echo "0") )); then
log "WARN" "High CPU usage detected: ${CPU_USAGE}%"
fi
if (( $(echo "$MEMORY_USAGE > 85" | bc -l 2>/dev/null || echo "0") )); then
log "WARN" "High memory usage detected: ${MEMORY_USAGE}%"
fi
if (( $(echo "$DISK_USAGE > 90" | bc -l 2>/dev/null || echo "0") )); then
log "WARN" "High disk usage detected: ${DISK_USAGE}%"
fi
"""
🚨 トラブルシューティングと障害対応¶
よくある問題と解決方法¶
1. Hooks実行がハングする場合¶
#!/bin/bash
# ~/.claude/scripts/hook-watchdog.sh
# ハングしたHookプロセスの検出と終了
find_hung_processes() {
local max_runtime=600 # 10分
local current_time=$(date +%s)
ps -eo pid,etime,comm,args | grep claude | while read pid etime comm args; do
# 実行時間を秒に変換
if [[ $etime =~ ([0-9]+):([0-9]+) ]]; then
local minutes=${BASH_REMATCH[1]}
local seconds=${BASH_REMATCH[2]}
local total_seconds=$((minutes * 60 + seconds))
if [ $total_seconds -gt $max_runtime ]; then
echo "Terminating hung process: $pid ($etime)"
kill -TERM $pid
sleep 5
kill -KILL $pid 2>/dev/null
fi
fi
done
}
# 定期実行用cronジョブ
# */5 * * * * /home/user/.claude/scripts/hook-watchdog.sh
find_hung_processes
2. 並列実行時の競合状態解決¶
[[hooks]]
name = "Mutex Protected Operation"
event = "PostToolUse"
[hooks.matcher]
tool_name = "edit_file"
file_paths = ["package.json", "requirements.txt", "Cargo.toml"]
command = """
source ~/.claude/scripts/common.sh
# ミューテックスロック実装
LOCK_FILE="/tmp/claude-dependency-update.lock"
LOCK_TIMEOUT=300 # 5分
acquire_lock() {
local timeout_count=0
while [ -f "$LOCK_FILE" ] && [ $timeout_count -lt $LOCK_TIMEOUT ]; do
sleep 1
((timeout_count++))
if [ $((timeout_count % 30)) -eq 0 ]; then
log "INFO" "Waiting for lock... (${timeout_count}s)"
fi
done
if [ $timeout_count -ge $LOCK_TIMEOUT ]; then
log "ERROR" "Lock acquisition timeout"
return 1
fi
echo $$ > "$LOCK_FILE"
return 0
}
release_lock() {
rm -f "$LOCK_FILE"
}
# トラップでクリーンアップ
trap 'release_lock' EXIT
if acquire_lock; then
log "INFO" "Lock acquired, proceeding with operation"
# 依存関係更新処理
for file in $CLAUDE_FILE_PATHS; do
case "$file" in
"package.json")
npm audit fix
npm update
;;
"requirements.txt")
pip install -r requirements.txt --upgrade
;;
"Cargo.toml")
cargo update
;;
esac
done
log "INFO" "Dependency update completed"
else
log "ERROR" "Failed to acquire lock"
exit 1
fi
"""
3. エラー復旧とロールバック機能¶
[[hooks]]
name = "Auto Rollback on Error"
event = "PostToolUse"
[hooks.matcher]
tool_name = "edit_file"
file_paths = ["*.py", "*.js", "*.ts"]
command = """
source ~/.claude/scripts/common.sh
# バックアップディレクトリ作成
BACKUP_DIR="/tmp/claude-backup-$(date +%s)"
mkdir -p "$BACKUP_DIR"
# バックアップ関数
create_backup() {
local file=$1
local backup_file="$BACKUP_DIR/$(basename $file).backup"
cp "$file" "$backup_file"
echo "$backup_file"
}
# ロールバック関数
rollback_files() {
log "WARN" "Rolling back changes due to error"
for backup_file in "$BACKUP_DIR"/*.backup; do
if [ -f "$backup_file" ]; then
original_file=$(basename "$backup_file" .backup)
# オリジナルファイルの場所を特定
find . -name "$original_file" -exec cp "$backup_file" {} \;
log "INFO" "Rolled back: $original_file"
fi
done
}
# エラートラップ設定
trap 'rollback_files; exit 1' ERR
# 処理開始
for file in $CLAUDE_FILE_PATHS; do
log "INFO" "Processing file: $file"
# バックアップ作成
backup_file=$(create_backup "$file")
log "INFO" "Backup created: $backup_file"
# 実際の処理(例:フォーマット)
case "${file##*.}" in
"py")
black "$file" || { log "ERROR" "Black formatting failed"; exit 1; }
;;
"js"|"ts")
prettier --write "$file" || { log "ERROR" "Prettier formatting failed"; exit 1; }
;;
esac
# 処理成功時はバックアップ削除
rm -f "$backup_file"
done
# 全処理完了時はバックアップディレクトリ削除
rmdir "$BACKUP_DIR" 2>/dev/null || true
log "INFO" "✅ All files processed successfully"
"""
📈 企業導入事例とベストプラクティス¶
大規模チーム向け設定管理¶
#!/bin/bash
# チーム共有設定のセットアップスクリプト
# 企業向けClaude Hooks設定管理
setup_enterprise_hooks() {
local team_config_repo="https://github.com/your-company/claude-hooks-config.git"
local config_dir="$HOME/.claude"
echo "Setting up enterprise Claude Hooks configuration..."
# 既存設定のバックアップ
if [ -d "$config_dir" ]; then
mv "$config_dir" "$config_dir.backup.$(date +%s)"
fi
# チーム設定のクローン
git clone "$team_config_repo" "$config_dir"
# 環境固有設定の適用
local env=${1:-development}
if [ -f "$config_dir/environments/$env.toml" ]; then
cp "$config_dir/environments/$env.toml" "$config_dir/settings.toml"
echo "Applied $env environment configuration"
fi
# チーム固有スクリプトの実行権限設定
chmod +x "$config_dir/scripts/"*.sh
# ログディレクトリの準備
sudo mkdir -p /var/log/claude-hooks
sudo chown $USER:$USER /var/log/claude-hooks
echo "✅ Enterprise Claude Hooks setup completed"
}
# 使用例
# ./setup-enterprise-hooks.sh production
setup_enterprise_hooks "$1"
CI/CD統合例¶
# .github/workflows/claude-hooks-ci.yml
name: Claude Hooks CI Integration
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
claude-hooks-validation:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Claude Code
run: |
curl -fsSL https://claude.ai/install.sh | sh
echo "$HOME/.local/bin" >> $GITHUB_PATH
- name: Install Dependencies
run: |
# Python依存関係
if [ -f requirements.txt ]; then
pip install -r requirements.txt
fi
# Node.js依存関係
if [ -f package.json ]; then
npm ci
fi
- name: Setup Claude Hooks
env:
CLAUDE_API_KEY: ${{ secrets.CLAUDE_API_KEY }}
run: |
mkdir -p ~/.claude
cp .github/claude-hooks/ci-settings.toml ~/.claude/settings.toml
cp -r .github/claude-hooks/scripts ~/.claude/
chmod +x ~/.claude/scripts/*.sh
- name: Run Code Quality Checks
run: |
# Hooksシミュレーション実行
for file in $(git diff --name-only HEAD~1 HEAD | grep -E '\.(py|js|ts)$'); do
if [ -f "$file" ]; then
echo "Simulating hooks for: $file"
# Python処理
if [[ "$file" == *.py ]]; then
black --check "$file"
ruff check "$file"
python -m py_compile "$file"
fi
# JavaScript/TypeScript処理
if [[ "$file" =~ \.(js|ts|tsx)$ ]]; then
npx prettier --check "$file"
npx eslint "$file"
fi
fi
done
- name: Run Tests
run: |
# Pythonテスト
if [ -f pytest.ini ] || [ -f pyproject.toml ]; then
pytest --tb=short
fi
# Node.jsテスト
if [ -f package.json ] && grep -q '"test"' package.json; then
npm test
fi
- name: Performance Report
run: |
echo "## Claude Hooks Performance Report" >> $GITHUB_STEP_SUMMARY
echo "| Check | Status | Duration |" >> $GITHUB_STEP_SUMMARY
echo "|-------|--------|----------|" >> $GITHUB_STEP_SUMMARY
echo "| Code Format | ✅ | 2.3s |" >> $GITHUB_STEP_SUMMARY
echo "| Tests | ✅ | 15.7s |" >> $GITHUB_STEP_SUMMARY
echo "| Security Scan | ✅ | 4.1s |" >> $GITHUB_STEP_SUMMARY
🔧 高度なカスタマイゼーション¶
プロジェクト特化型AI学習機能¶
[[hooks]]
name = "AI-Powered Code Analysis"
event = "PostToolUse"
run_in_background = true
[hooks.matcher]
tool_name = "edit_file"
command = """
source ~/.claude/scripts/common.sh
PROJECT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
ANALYSIS_DIR="$PROJECT_ROOT/.claude/analysis"
mkdir -p "$ANALYSIS_DIR"
log "INFO" "🤖 Starting AI-powered code analysis"
# コードパターン学習
for file in $CLAUDE_FILE_PATHS; do
if [ ! -f "$file" ]; then
continue
fi
# ファイル種別検出
file_type="${file##*.}"
# コード複雑度分析
case "$file_type" in
"py")
if command -v radon &> /dev/null; then
complexity=$(radon cc "$file" -a 2>/dev/null | tail -1 | awk '{print $NF}' | tr -d '()')
echo "$(date '+%Y-%m-%d %H:%M:%S'),$file,python,$complexity" >> "$ANALYSIS_DIR/complexity.csv"
fi
;;
"js"|"ts")
if command -v eslint &> /dev/null; then
complexity=$(npx eslint "$file" --format json 2>/dev/null | jq '.[].messages | length' || echo "0")
echo "$(date '+%Y-%m-%d %H:%M:%S'),$file,javascript,$complexity" >> "$ANALYSIS_DIR/complexity.csv"
fi
;;
esac
# 変更パターン記録
git log -n 5 --oneline "$file" > "$ANALYSIS_DIR/$(basename $file).history" 2>/dev/null
done
# 週次学習サマリー生成
if [ $(date +%w) -eq 1 ]; then # 月曜日
log "INFO" "📊 Generating weekly learning summary"
{
echo "# Weekly Code Analysis Summary - $(date '+%Y-%m-%d')"
echo ""
echo "## Complexity Trends"
tail -n 50 "$ANALYSIS_DIR/complexity.csv" | awk -F',' '
{
sum += $4
count++
}
END {
if (count > 0) {
avg = sum / count
print "Average complexity: " avg
if (avg > 10) print "⚠️ High complexity detected - consider refactoring"
else print "✅ Complexity within acceptable range"
}
}'
echo ""
echo "## Most Modified Files"
find "$ANALYSIS_DIR" -name "*.history" -exec wc -l {} + | sort -nr | head -5
} > "$ANALYSIS_DIR/weekly-summary.md"
fi
log "INFO" "✅ AI code analysis completed"
"""
まとめ¶
Claude Code Hooksのプロダクション環境での実装は、単純な設定ファイルの作成を超えて、堅牢なエラーハンドリング、パフォーマンス監視、セキュリティ確保が重要です。
本ガイドで紹介した設定例とスクリプトを活用することで:
- 段階的導入: リスクを最小化した漸進的な自動化
- 障害対応: 問題発生時の迅速な復旧と原因分析
- チーム運用: 大規模組織での統一された開発環境
- 継続改善: AI支援による自動最適化
これらの実装により、Claude Code Hooksが真の開発生産性向上ツールとして機能します。
次のステップ
- 朝の記事で基本概念を復習
- 小規模プロジェクトでテスト導入を開始
- チーム向け設定ファイルのカスタマイズ
- CI/CD環境への統合実装
プロダクション導入時の注意
本番環境での導入前に、必ず開発・ステージング環境での十分なテストを実施してください。特にPreToolUseフックは、操作をブロックする可能性があるため慎重な設定が必要です。