Skip to content

原文(日本語に翻訳)

自動モードの分類器による拒否後に発火する PermissionDenied フックを追加 — {retry: true} を返すことでモデルにリトライを指示できます

原文(英語)

Added PermissionDenied hook that fires after auto mode classifier denials — return {retry: true} to tell the model it can retry

概要

新しい PermissionDenied フックは、Claude Codeの自動モード(Auto mode)がツール呼び出しを拒否した後に発火します。フックから {retry: true} を返すことで、モデルに対して異なるアプローチでリトライするよう指示できます。これにより、権限拒否が発生した際の動的なリカバリーロジックを実装することが可能になります。

基本的な使い方

json
// settings.json のフック設定例
{
  "hooks": {
    "PermissionDenied": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "handle-permission-denied.sh"
          }
        ]
      }
    ]
  }
}
bash
#!/bin/bash
# handle-permission-denied.sh

TOOL_NAME="$CLAUDE_TOOL_NAME"
TOOL_INPUT="$CLAUDE_TOOL_INPUT"
DENIAL_REASON="$CLAUDE_DENIAL_REASON"

# ログに記録
echo "権限拒否: $TOOL_NAME - $DENIAL_REASON" >> /var/log/claude-denials.log

# 特定の条件でリトライを許可
if [ "$TOOL_NAME" = "Bash" ] && echo "$DENIAL_REASON" | grep -q "network"; then
  # ネットワーク関連の一時的な拒否はリトライ
  echo '{"retry": true}'
else
  # それ以外はリトライしない(デフォルト動作)
  echo '{}'
fi

実践例

代替アプローチへの誘導

bash
#!/bin/bash
# redirect-on-denial.sh
# 権限拒否時に安全な代替手段をモデルに提案する

TOOL_NAME="$CLAUDE_TOOL_NAME"
TOOL_INPUT="$CLAUDE_TOOL_INPUT"

if [ "$TOOL_NAME" = "Bash" ]; then
  # 危険なコマンドが拒否された場合、safer な手段へ誘導
  SAFE_ALTERNATIVE=$(suggest-safe-alternative.py "$TOOL_INPUT")
  echo "{\"retry\": true, \"message\": \"より安全な方法を試してください: $SAFE_ALTERNATIVE\"}"
else
  echo '{}'
fi

監査ログとの統合

python
#!/usr/bin/env python3
# audit-and-retry.py

import os
import json
import datetime
import requests

tool_name = os.environ.get("CLAUDE_TOOL_NAME", "")
tool_input = os.environ.get("CLAUDE_TOOL_INPUT", "")
session_id = os.environ.get("CLAUDE_SESSION_ID", "")

# 監査ログに記録
audit_entry = {
    "timestamp": datetime.datetime.utcnow().isoformat(),
    "session_id": session_id,
    "tool_name": tool_name,
    "tool_input": tool_input,
    "event": "permission_denied"
}

requests.post("https://audit.internal/log", json=audit_entry)

# ホワイトリストのツールはリトライ許可
RETRY_ALLOWED_TOOLS = ["Read", "Glob", "Grep"]
if tool_name in RETRY_ALLOWED_TOOLS:
    print(json.dumps({"retry": True}))
else:
    print(json.dumps({}))

PreToolUseフックとの組み合わせ

json
// settings.json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "pre-check.sh"
          }
        ]
      }
    ],
    "PermissionDenied": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "on-denied.sh"
          }
        ]
      }
    ]
  }
}

注意点

  • PermissionDenied フックは 自動モード(Auto mode)の分類器による拒否後にのみ発火します。PreToolUse フックによる明示的な拒否では発火しません
  • {retry: true} を返すと、モデルは同じツール呼び出しではなく、異なるアプローチでタスクを再試行します
  • 無限リトライを防ぐため、リトライ回数のカウントやセッション状態の管理を実装することを推奨します
  • /permissions → Recent タブでも拒否されたコマンドを確認でき、r キーで手動リトライが可能です(v2.1.89の新機能)

関連情報