Claude Code 的 PermissionRequest hook 會在 Claude Code 即將顯示權限 prompt 時執行,並可以替你回應該 prompt。若要允許,hook 以 0 結束並輸出 {"hookSpecificOutput": {"hookEventName": "PermissionRequest", "decision": {"behavior": "allow"}}};若要拒絕,則使用 "behavior": "deny" 並附上給 Claude 的 message。它依工具名稱比對,無法覆蓋你的 deny 規則,且在此事件中 exit code 2 沒有作用。如果 hook 沒有輸出任何決定,就會顯示一般的 prompt。
01PermissionRequest 與 PreToolUse、Notification 的比較
與權限相關的 hook 事件有三個,各自負責不同的工作:
PreToolUse每次呼叫工具之前,不論是否需要權限可以:allow、deny、ask 或 deferPermissionRequest只在 Claude Code 即將詢問你時可以:allow 或 denyNotification(permission_prompt)在你離開時,prompt 等待約六秒之後否如果你在意的是 prompt 本身,例如回應、記錄或轉送到其他地方,就用 PermissionRequest。它會立即觸發,沒有六秒延遲。若是要套用到每次呼叫的規則,例如「絕不執行 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"updatedInput僅限 allow。會取代工具的整個輸入,所以未變更的欄位也要一併附上updatedPermissions僅限 allow。要套用的權限變更,例如新增規則或切換模式message僅限 deny。告訴 Claude 原因interrupt僅限 deny。設為 true 時也會讓 Claude 停止有兩條規則要記住:
- deny 和 ask 規則依然有效。hook 回傳
"allow"並不會覆蓋設定中相符的 deny 規則,而修改過的輸入也會再次依這些規則檢查。 - 這裡會忽略 exit code
2。在大多數事件中,exit2會阻擋操作,但PermissionRequesthook 若以2結束卻沒有decision物件,prompt 會維持原樣。要拒絕,請回傳 decision。
04範例:自動核准單一 prompt
Anthropic 官方的範例會核准 ExitPlanMode,也就是 Claude 完成計畫時跳出的 prompt,這樣就不用每次都被問:
{
"hooks": {
"PermissionRequest": [
{
"matcher": "ExitPlanMode",
"hooks": [
{
"type": "command",
"command": "echo '{\"hookSpecificOutput\": {\"hookEventName\": \"PermissionRequest\", \"decision\": {\"behavior\": \"allow\"}}}'"
}
]
}
]
}
}
matcher 要盡量精確。空的 matcher 或 .* 搭配一律 allow,會核准所有 prompt,連寫入檔案和 shell 指令都包括在內。
05範例:依指令內容決定
這個腳本(需要 jq)會拒絕任何涉及 git push 的操作,並附上 Claude 看得懂的原因;其他 prompt 則什麼都不輸出,交給你決定:
#!/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" }]
}
]
}
}
請用 jq 產生 JSON,不要用字串拼接,這樣訊息裡的引號才不會把它弄壞。另外要確保沒有其他內容輸出到 stdout。如果你的 shell profile 會 echo 一行字,Claude Code 就讀不到 decision。
06範例:允許並在整個 session 內記住
若要核准請求,並讓 Claude 在 session 結束前不再詢問,請加上一筆 updatedPermissions,並設定 destination: "session"。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。當決定取決於規則看不到的條件時,例如時段、目前所在的 branch,或是有人從別處回覆,hook 才有用武之地。其他內建選項請參考權限模式說明。
08容易踩到的坑
- 非互動式執行。使用
claude -p時沒有人可以回應 prompt。PermissionRequesthook 仍會執行,若沒有任何 hook 回傳 decision,該呼叫就會被拒絕。 - 逾時。command hook 預設最多可執行 600 秒,Claude 會一直等。如果你的 hook 要等待較慢的事物(例如等人回覆),請設定
timeout(單位為秒)。 - 有些 prompt 不會觸發它。sandbox 中指令發出的網路請求不會執行
PermissionRequest。這種情況請使用permission_prompt通知類型。 - 安全性。回傳
"allow"的 hook 等於以你的名義、用你的使用者權限核准操作。請像審查任何能執行指令的程式碼一樣審查它。
09Claude Code Notifier 的角色
撰寫 PermissionRequest hook 最常見的原因,是想在不在電腦前時也能回應 prompt。自己動手做的話,hook 必須把請求送到某處、等待回覆,並在逾時前回傳結果。這做得到,也有人用聊天機器人來實作。
Claude Code Notifier 幫你把這件事做好。它的免費命令列工具 ccn 支援 Mac、Windows 和 Linux,會把 hook 安裝到 ~/.claude/settings.json。配對 iPhone 或 Android app 後,權限請求會送到手機上,你可以選擇允許一次、在本 session 內允許,或拒絕;ccn 會從 PermissionRequest hook 回傳該決定。如果你在最近 30 秒內有打字,就不會等待,terminal 照常詢問。如果你不在電腦前,terminal 會等待手機回覆,最長到你設定的上限(hold_ceiling_seconds,預設 600),而且只要你一碰鍵盤就會停止等待。本工具為獨立開發,並非 Anthropic 出品。操作流程請見從手機核准權限,安全性方面請見遠端核准安全嗎?。
10常見問題
如何用 hook 自動核准權限?
新增一個使用精確 matcher 的 PermissionRequest hook,讓它輸出在 hookSpecificOutput 中含有 "behavior": "allow" 的 JSON decision,然後以 0 結束。如果同一個指令永遠都該允許,在 settings.json 加一條 permissions.allow 規則更簡單,也不需要 hook。
為什麼 exit code 2 不會拒絕請求?
PermissionRequest 是不採用 exit 2 的事件之一。Claude Code 會忽略它並顯示一般的 prompt。請改在 decision 物件中回傳 "behavior": "deny"。
PermissionRequest hook 能覆蓋我的 deny 規則嗎?
不能。deny 和 ask 規則仍會被評估,因此 hook 回傳的 "allow" 無法繞過相符的 deny 規則。你回傳的任何 updatedInput 也會依這些規則檢查。
PermissionRequest 和 PreToolUse 有什麼不同?
PreToolUse 會在每次 tool 呼叫前執行,可以 allow、deny、ask 或 defer。PermissionRequest 只在 Claude Code 即將顯示 prompt 時執行,可以 allow 或 deny。制定政策用 PreToolUse,回應 prompt 用 PermissionRequest。
如果我的 hook 什麼都沒輸出會怎樣?
什麼都不會改變。Claude Code 會在 terminal 照常顯示權限 prompt,就像 hook 不存在一樣。