Skip to content

原文(日本語に翻訳)

PreToolUse フックに "defer" 権限決定を追加 — ヘッドレスセッションはツール呼び出しで一時停止し、-p --resume で再開してフックを再評価できます

原文(英語)

Added "defer" permission decision to PreToolUse hooks — headless sessions can pause at a tool call and resume with -p --resume to have the hook re-evaluate

概要

PreToolUse フックで新たに "defer" という権限決定が使用できるようになりました。これにより、ヘッドレス(-p フラグ)セッション中にツール呼び出しを一時停止し、外部処理や人間によるレビューを挟んだ後、-p --resume で再開してフックに再評価させることができます。CI/CD パイプラインや自動化ワークフローで、特定のツール呼び出しに対して動的な承認フローを組み込む際に非常に有用です。

基本的な使い方

PreToolUse フックから "defer" を返すことで、セッションを一時停止できます。

json
// settings.json のフック設定例
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "check-requires-approval.sh"
          }
        ]
      }
    ]
  }
}
bash
# check-requires-approval.sh の例
#!/bin/bash
TOOL_INPUT="$CLAUDE_TOOL_INPUT"

# 危険なコマンドが含まれていたら defer を返す
if echo "$TOOL_INPUT" | grep -q "rm -rf\|DROP TABLE"; then
  echo '{"decision": "defer", "reason": "危険なコマンドのため手動承認が必要です"}'
  exit 0
fi

# 通常のコマンドは allow
echo '{"decision": "allow"}'

セッションの再開

bash
# 最初のヘッドレス実行(deferで一時停止される)
claude -p "本番データベースをクリーンアップしてください" --session-id my-session

# 外部承認後に再開
claude -p --resume my-session

実践例

CI/CDパイプラインでの承認フロー

bash
#!/bin/bash
# pre-tool-hook.sh

TOOL_NAME="$CLAUDE_TOOL_NAME"
TOOL_INPUT="$CLAUDE_TOOL_INPUT"
SESSION_ID="$CLAUDE_SESSION_ID"

# 本番環境へのデプロイコマンドは defer
if echo "$TOOL_INPUT" | grep -q "deploy.*production\|kubectl.*prod"; then
  # Slack通知やチケット作成などの処理
  notify-slack "承認が必要: $TOOL_INPUT (セッション: $SESSION_ID)"
  echo '{"decision": "defer", "reason": "本番デプロイは手動承認が必要"}'
  exit 0
fi

echo '{"decision": "allow"}'
yaml
# GitHub Actions での利用例
- name: Run Claude with approval flow
  run: |
    # 初回実行(deferで停止する可能性あり)
    claude -p "$PROMPT" --session-id $SESSION_ID || true

    # 承認後に再開
    claude -p --resume $SESSION_ID

外部審査システムとの統合

python
# approve_and_resume.py
import subprocess
import json

def check_approval(session_id: str, tool_input: str) -> bool:
    # 外部審査システムへ問い合わせ
    response = requests.post(
        "https://approval-system.internal/check",
        json={"session_id": session_id, "input": tool_input}
    )
    return response.json()["approved"]

def resume_session(session_id: str):
    subprocess.run(["claude", "-p", "--resume", session_id])

# メイン処理
if check_approval(session_id, tool_input):
    resume_session(session_id)

注意点

  • "defer"-p(ヘッドレス)モードでのみ機能します。インタラクティブセッションでは動作が異なります
  • --resume で再開した際、フックが再度実行されます。無限ループを防ぐため、承認済みのセッションIDを記録しておくことを推奨します
  • ツール入力が64KBを超える場合の --resume ハングバグは v2.1.89 で修正済みです
  • セッションIDの管理はユーザー側の責任となります

関連情報