AIコーディング 2026.05.05

Claude Code本番運用ガイド【2026年版】Hooks設定・権限管理・25エージェント構成の実装

タグ:Claude Code / 本番運用 / Hooks / 権限管理 / 開発

Hooksアーキテクチャの基本設定

// .claude/settings.json
{
  "permissions": {
    "allow": [
      "Bash(git status)",
      "Bash(git log*)",
      "Bash(gh pr list*)",
      "Read(*)"
    ],
    "deny": [
      "Bash(git push --force*)",
      "Bash(rm -rf*)",
      "Bash(DROP TABLE*)"
    ]
  },
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [{
          "type": "command",
          "command": "bash .claude/hooks/pre_tool_check.sh"
        }]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "*",
        "hooks": [{
          "type": "command",
          "command": "bash .claude/hooks/post_tool_log.sh"
        }]
      }
    ]
  }
}

gh コマンドの readonly ラッパー

#!/bin/bash
# .claude/hooks/gh-readonly-wrapper.sh
# write操作をブロックして読み込みのみ許可する

COMMAND="$*"

# 書き込み操作のブロックリスト
WRITE_OPERATIONS=("pr create" "pr merge" "pr close" "issue create" "issue close" "release create" "push")

for op in "${WRITE_OPERATIONS[@]}"; do
    if echo "$COMMAND" | grep -q "$op"; then
        echo "❌ 書き込み操作はブロックされました: gh $COMMAND"
        echo "   本番環境での書き込みは手動確認後に実行してください"
        exit 1
    fi
done

# 読み込み操作は通す
echo "✅ 読み込み操作を実行: gh $COMMAND"
gh $COMMAND

操作ログのフック実装

# .claude/hooks/pre_tool_check.py
# ツール実行前にログを記録して危険操作を検知する

import sys
import json
import logging
from datetime import datetime
from pathlib import Path

logging.basicConfig(
    filename=".claude/agent_operations.log",
    level=logging.INFO,
    format="%(asctime)s %(message)s"
)

def check_tool_call(tool_name: str, tool_input: dict) -> bool:
    """ツール実行前の安全チェック"""
    DANGEROUS_PATTERNS = [
        "rm -rf", "DROP TABLE", "git push --force",
        "DELETE FROM", "TRUNCATE", "git reset --hard"
    ]
    
    input_str = json.dumps(tool_input)
    for pattern in DANGEROUS_PATTERNS:
        if pattern.lower() in input_str.lower():
            logging.warning(f"BLOCKED: {tool_name} with pattern '{pattern}': {input_str[:200]}")
            print(f"⚠️ 危険な操作をブロック: '{pattern}'")
            return False
    
    logging.info(f"ALLOWED: {tool_name}: {input_str[:100]}")
    return True

# Claude Codeからhookとして呼ばれる
if __name__ == "__main__":
    hook_data = json.loads(sys.stdin.read())
    tool_name = hook_data.get("tool_name", "")
    tool_input = hook_data.get("tool_input", {})
    
    if not check_tool_call(tool_name, tool_input):
        sys.exit(1)  # ← exit code 1でClaude Codeは実行を停止
    
    sys.exit(0)  # ← exit code 0で実行を許可

25エージェント構成のコスト管理

# agent_cost_tracker.py
# 複数エージェントの使用量を一元管理する

import anthropic
from datetime import date
import json
from pathlib import Path

client = anthropic.Anthropic()

MODELS = {
    "haiku": "claude-haiku-4-5-20251001",
    "sonnet": "claude-sonnet-4-5",
    "opus": "claude-opus-5",
}

PRICES = {
    "claude-haiku-4-5-20251001": (0.80, 4.00),
    "claude-sonnet-4-5":         (3.00, 15.00),
    "claude-opus-5":             (15.00, 75.00),
}

usage_log_path = Path(".claude/daily_usage.json")

def track_usage(agent_name: str, model: str, input_tokens: int, output_tokens: int) -> float:
    """エージェントの使用量を記録してコストを返す"""
    inp, out = PRICES.get(model, (3.00, 15.00))
    cost = (input_tokens * inp + output_tokens * out) / 1_000_000
    
    today = str(date.today())
    log = json.loads(usage_log_path.read_text()) if usage_log_path.exists() else {}
    
    if today not in log:
        log[today] = {}
    if agent_name not in log[today]:
        log[today][agent_name] = {"cost": 0.0, "calls": 0}
    
    log[today][agent_name]["cost"] += cost
    log[today][agent_name]["calls"] += 1
    
    usage_log_path.write_text(json.dumps(log, indent=2))
    return cost

def daily_summary() -> dict:
    """今日の全エージェントのコスト合計"""
    if not usage_log_path.exists():
        return {}
    log = json.loads(usage_log_path.read_text())
    today = str(date.today())
    return log.get(today, {})

print("今日のエージェント別コスト:")
for agent, data in daily_summary().items():
    print(f"  {agent}: ${data['cost']:.4f} ({data['calls']}回呼び出し)")

あわせて読みたい

参考ソース