Feature Request: Allow Permission Mode Switching in PermissionRequest Hooks
Feature Request: Allow Permission Mode Switching in PermissionRequest Hooks
Summary
Add ability to programmatically switch Claude CLI permission modes when responding to PermissionRequest hooks.
Problem Statement
Currently, there's no way to programmatically control the session's permission mode from hooks. The permission_mode field in hook input is read-only, and there's no API to change it.
Current behavior: When approving a permission request via a PermissionRequest hook, Claude remains in its current permission mode. There's no way to replicate the native approval prompt options like "Yes, accept all edits" (switch to acceptEdits) vs "Yes" (stay in current mode).
Desired behavior: Allow hook responses to optionally switch permission modes when approving permission requests.
Use Case
When building external approval workflows for any PermissionRequest (not just ExitPlanMode), it would be valuable to programmatically control the permission mode. This enables emulating the native approval prompt options:
In Plan Mode (ExitPlanMode approval):
- "Yes, accept all edits" - Approve and switch to
acceptEditsmode - "Yes" - Approve and switch to
defaultmode
In Default Mode (general tool approvals):
- "Yes, allow all edits during this session" - Approve and switch to
acceptEditsmode - "Yes" - Approve and stay in
defaultmode
This would enable external tools to offer the same flexibility that exists in the native Claude Code interactive approval prompts.
Proposed Solution
Option 1: Add switchToMode Field in Hook Response
Allow hooks to request a permission mode switch in the decision response:
{
"hookSpecificOutput": {
"hookEventName": "PermissionRequest",
"decision": {
"behavior": "allow",
"switchToMode": "acceptEdits"
}
}
}
Valid values: "default", "plan", "acceptEdits", "bypassPermissions" (or null to leave unchanged)
Option 2: Add permission_mode to Tool Input
Instead of permission_mode being session-level metadata only, include it as a modifiable field in tool_input. This would allow hooks to change the mode via updatedInput:
Current structure:
{
"session_id": "...",
"permission_mode": "plan", // Read-only, not in tool_input
"tool_name": "ExitPlanMode",
"tool_input": {
"plan": "..."
}
}
Proposed structure:
{
"session_id": "...",
"tool_name": "ExitPlanMode",
"tool_input": {
"plan": "...",
"permission_mode": "plan" // Now modifiable via updatedInput
}
}
Hook response:
{
"hookSpecificOutput": {
"hookEventName": "PermissionRequest",
"decision": {
"behavior": "allow",
"updatedInput": {
"permission_mode": "acceptEdits"
}
}
}
}
Example Hook Implementation
Using Option 1 (switchToMode):
#!/bin/bash
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
CURRENT_MODE=$(echo "$INPUT" | jq -r '.permission_mode')
# External logic determines user's approval preference
DESIRED_MODE=$(get_user_approval_preference "$TOOL_NAME" "$CURRENT_MODE")
if [[ "$DESIRED_MODE" == "current" ]]; then
echo '{"hookSpecificOutput":{"hookEventName":"PermissionRequest","decision":{"behavior":"allow"}}}'
else
echo "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"decision\":{\"behavior\":\"allow\",\"switchToMode\":\"$DESIRED_MODE\"}}}"
fi
Using Option 2 (updatedInput):
#!/bin/bash
INPUT=$(cat)
DESIRED_MODE=$(get_user_approval_preference)
echo "{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"decision\":{\"behavior\":\"allow\",\"updatedInput\":{\"permission_mode\":\"$DESIRED_MODE\"}}}}"
Benefits
- Enables external automation tools to fully replicate native approval UX
- Works for all permission requests, not just specific tools
- Consistent with existing hook decision structure (Option 1) or existing
updatedInputpattern (Option 2) - No breaking changes - feature is opt-in
- Provides parity with native interactive approval prompts
Additional Context
- Platform: macOS (but issue affects all platforms)
- Related keyboard shortcut:
Shift+Tabcycles modes interactively, but there's no programmatic equivalent - This applies to all
PermissionRequesthooks, not justExitPlanMode
This issue has 8 comments on GitHub. Read the full discussion on GitHub ↗