Claude Code の PermissionRequest hook は、Claude Code が権限確認の prompt を表示しようとした時点で実行され、その prompt に代わりに応答できます。許可する場合、hook は 0 で終了し {"hookSpecificOutput": {"hookEventName": "PermissionRequest", "decision": {"behavior": "allow"}}} を出力します。拒否する場合は "behavior": "deny" と、Claude 向けの message を使います。ツール名でマッチし、deny ルールを上書きすることはできず、このイベントでは終了コード 2 は何の効果もありません。hook が decision を出力しなければ、通常の prompt が表示されます。
01PermissionRequest と PreToolUse、Notification の比較
権限に関わる hook イベントは 3 つあり、それぞれ役割が異なります。
PreToolUse権限の要否にかかわらず、すべてのツール呼び出しの前可能:allow、deny、ask、deferPermissionRequestClaude Code がユーザーに確認しようとするときのみ可能:allow または denyNotification(permission_prompt)離席中に prompt が約 6 秒待機した後いいえprompt そのものに関心がある場合、つまり応答する、ログに残す、どこかに送るといった用途には PermissionRequest を使います。6 秒の遅延なしにすぐ発火します。「rm -rf は絶対に実行しない」のように、すべての呼び出しに適用すべきルールには PreToolUse を使います。prompt が表示されない場合でも実行されるためです。このイベントのタイミングについてはNotification hook ガイドで説明しています。
02hook が受け取るデータ
PermissionRequest hook は、共通フィールドに加えて、Claude が実行しようとしている呼び出しの tool_name と tool_input、そしてオプションの permission_suggestions 配列を受け取ります。
{
"session_id": "abc123",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "PermissionRequest",
"tool_name": "Bash",
"tool_input": {
"command": "rm -rf node_modules",
"description": "Remove node_modules directory"
},
"permission_suggestions": [
{
"type": "addRules",
"rules": [{ "toolName": "Bash", "ruleContent": "rm -rf node_modules" }],
"behavior": "allow",
"destination": "localSettings"
}
]
}
permission_suggestions には、このリクエストに対して Claude Code が提案するルール変更が入ります。ダイアログごとに独自の選択肢を組み立てるため、ダイアログの選択肢と完全に一致するわけではありません。
03decision オブジェクト
hookSpecificOutput 内で decision を返します。
behavior"allow" または "deny"updatedInputallow 時のみ。ツールの入力全体を置き換えるため、変更しないフィールドも含めてくださいupdatedPermissionsallow 時のみ。ルールの追加やモード変更など、適用する権限の変更messagedeny 時のみ。Claude に理由を伝えますinterruptdeny 時のみ。true にすると Claude も停止します覚えておきたいルールが2つあります。
- deny ルールと ask ルールは引き続き適用されます。hook が
"allow"を返しても、設定内の一致する deny ルールは上書きされません。また、変更された入力もこれらのルールで再チェックされます。 - ここでは終了コード
2は無視されます。多くのイベントでは exit2でブロックできますが、PermissionRequesthook がdecisionオブジェクトなしで2で終了しても、プロンプトはそのまま表示されます。拒否したい場合は decision を返してください。
04例: 特定のプロンプトを自動承認する
Anthropic 公式の例では、Claude がプランを作り終えたときに表示される ExitPlanMode のプロンプトを承認し、毎回聞かれないようにしています。
{
"hooks": {
"PermissionRequest": [
{
"matcher": "ExitPlanMode",
"hooks": [
{
"type": "command",
"command": "echo '{\"hookSpecificOutput\": {\"hookEventName\": \"PermissionRequest\", \"decision\": {\"behavior\": \"allow\"}}}'"
}
]
}
]
}
}
matcher はできるだけ絞り込んでください。空の matcher や .* で一律に allow すると、ファイル書き込みやシェルコマンドも含め、すべてのプロンプトが承認されてしまいます。
05例: コマンドの内容を見て判断する
このスクリプト(jq が必要)は、git push に関わるものを Claude が読める理由付きで拒否し、それ以外のプロンプトは何も出力せずにあなたの判断に任せます。
#!/bin/bash
# ~/.claude/hooks/permission-check.sh
input=$(cat)
cmd=$(jq -r '.tool_input.command // empty' <<<"$input")
case "$cmd" in
*"git push"*)
jq -nc '{hookSpecificOutput: {hookEventName: "PermissionRequest",
decision: {behavior: "deny",
message: "Pushing is not allowed from this session. Commit and stop."}}}'
;;
esac
exit 0
{
"hooks": {
"PermissionRequest": [
{
"matcher": "Bash",
"hooks": [{ "type": "command", "command": "~/.claude/hooks/permission-check.sh" }]
}
]
}
}
JSON は文字列連結ではなく jq で組み立てましょう。そうすればメッセージ内の引用符で壊れることがありません。また、stdout にほかの出力が混ざらないようにしてください。シェルのプロファイルが何か echo していると、Claude Code は decision を読み取れません。
06例: 許可してセッション中は記憶させる
リクエストを承認し、セッションが終わるまで Claude に再度聞かれないようにするには、destination: "session" を指定した updatedPermissions エントリを追加します。hook は受け取った permission_suggestions のひとつを、destination だけ変えてそのまま返せます。
#!/bin/bash
input=$(cat)
jq -c '{hookSpecificOutput: {hookEventName: "PermissionRequest",
decision: {behavior: "allow",
updatedPermissions: [(.permission_suggestions // [])[]
| select(.type == "addRules")
| .destination = "session"]}}}' <<<"$input"
このままでは受け取ったリクエストをすべて許可するので、絞り込んだ matcher と組み合わせてください。destination には localSettings、projectSettings、userSettings も指定でき、その場合はメモリ上ではなく設定ファイルにルールが書き込まれます。
07多くの場合は permission ルールのほうが適している
答えが常に同じなら hook は不要です。settings.json にルールを書けば、Claude Code は何も実行せずに適用します。
{
"permissions": {
"allow": ["Bash(npm run *)"],
"deny": ["Bash(git push *)"]
}
}
ルールは deny、ask、allow の順に評価されます。hook が役立つのは、時間帯や作業中のブランチ、別の場所にいる人の返答など、ルールでは判断できない要素に応じて決めたい場合です。そのほかの組み込みオプションについては permission モードの解説をご覧ください。
08ハマりやすいポイント
- 非対話実行。
claude -pでは確認する相手がいません。PermissionRequesthook は実行されますが、どれも decision を返さなければ呼び出しは拒否されます。 - タイムアウト。command hook はデフォルトで最大600秒実行でき、その間 Claude は待機します。人の返答など時間のかかるものを待つ hook では、
timeout(秒単位)を設定してください。 - 発火しないプロンプトもあります。サンドボックス内コマンドのネットワークリクエストでは
PermissionRequestは実行されません。その場合はpermission_prompt通知タイプを使ってください。 - セキュリティ。
"allow"を返す hook は、あなたのユーザー権限で、あなたの代わりに操作を承認していることになります。コマンドを実行できるほかのコードと同様にレビューしてください。
09Claude Code Notifier の位置づけ
PermissionRequest hook を書く一番よくある理由は、キーボードの前にいないときにプロンプトに応答することです。自作する場合、hook がリクエストをどこかに送り、返答を待ち、タイムアウト前に返す必要があります。実現は可能で、チャットボットで作っている人もいます。
Claude Code Notifier ならこれをまとめて引き受けます。無料のコマンドラインツール ccn は Mac、Windows、Linux で動作し、~/.claude/settings.json に hook をインストールします。iPhone または Android アプリとペアリングすると、permission リクエストがスマホに届き、1回だけ許可・セッション中は許可・拒否を選べます。その決定を ccn が PermissionRequest hook から返します。直近30秒以内に入力していれば待機せず、terminal で通常どおり確認されます。離席中は、設定した上限(hold_ceiling_seconds、デフォルト600)までスマホからの返答を待ち、キーボードに触れた時点で待機をやめます。本ツールは独立した製品で、Anthropic によるものではありません。ワークフローはスマホから permission を承認する、セキュリティ面はリモート承認は安全か?をご覧ください。
10よくある質問
hook で permission を自動承認するには?
絞り込んだ matcher で PermissionRequest hook を追加し、hookSpecificOutput 内に "behavior": "allow" を含む JSON の decision を出力して、0 で終了させます。同じコマンドを常に許可するなら、settings.json の permissions.allow ルールのほうがシンプルで、hook も不要です。
終了コード 2 でリクエストが拒否されないのはなぜ?
PermissionRequest は exit 2 が考慮されないイベントのひとつです。Claude Code はこれを無視して通常のプロンプトを表示します。代わりに decision オブジェクトで "behavior": "deny" を返してください。
PermissionRequest hook で deny ルールを上書きできますか?
できません。deny ルールと ask ルールは引き続き評価されるため、hook の "allow" で一致する deny ルールを回避することはできません。返した updatedInput もこれらのルールでチェックされます。
PermissionRequest と PreToolUse の違いは?
PreToolUse はすべてのツール呼び出しの前に実行され、allow・deny・ask・defer を返せます。PermissionRequest は Claude Code がプロンプトを表示する直前にだけ実行され、allow か deny を返せます。ポリシーには PreToolUse、プロンプトへの応答には PermissionRequest を使いましょう。
hook が何も出力しなかったら?
何も変わりません。hook がない場合と同じく、Claude Code は terminal に通常の permission プロンプトを表示します。