[FEATURE] PermissionRequest and PermissionResponse hook events for metrics
Problem
We want to measure how much time Claude Code spends blocked waiting for user permission responses. This is important for understanding developer productivity impact and whether permission prompts cause significant workflow interruptions.
Currently, there's no way to capture:
- When a permission prompt is displayed to the user
- How long the user takes to respond
- What the user's response was (allow, deny, allow_always, deny_always)
- Metrics for denied permissions (since the tool never executes)
Related: #20213 requests StartedToolUse which would help, but doesn't capture the response type or denied permissions.
Proposed Solution
Add two new hook events:
PermissionRequest
Fired when Claude Code displays a permission prompt to the user.
{
"hook_event_name": "PermissionRequest",
"session_id": "abc123",
"tool_use_id": "toolu_01ABC...",
"request_id": "perm_req_12345",
"timestamp_ns": 1706547200000000000,
"tool_name": "Bash",
"tool_input": { "command": "npm install lodash" },
"permission_type": "tool_execution"
}
PermissionResponse
Fired when the user responds to a permission prompt.
{
"hook_event_name": "PermissionResponse",
"request_id": "perm_req_12345",
"timestamp_ns": 1706547205000000000,
"response": "allow",
"tool_name": "Bash",
"tool_input": { "command": "npm install lodash" }
}
Where response is one of: allow, deny, allow_always, deny_always
Use Cases
- Productivity metrics: Track total time per session blocked on permission prompts
- UX optimization: Identify which tool types cause the most permission friction
- Permission tuning: Understand grant/deny patterns to improve default allow rules
Open Questions
- How should timeout/cancellation be represented (user closes terminal without responding)?
- Will MCP tool permissions use the same events?
- How does batched permission approval work with these events?
Implementation Ready
We've already built plugin hooks ready to consume these events: https://github.com/intercom/claude-plugins/pull/181
The hooks sanitize sensitive data (env vars, tokens) before sending metrics to our observability platform.
This issue has 8 comments on GitHub. Read the full discussion on GitHub ↗