[FEATURE] PermissionRequest and PermissionResponse hook events for metrics

Status Fixed / completed
Maintainer reply None cached
Activity 9 comments · opened Jan 30, 2026 · closed Aug 17, 2026

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:

  1. When a permission prompt is displayed to the user
  2. How long the user takes to respond
  3. What the user's response was (allow, deny, allow_always, deny_always)
  4. 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.

View original on GitHub ↗

8 Comments

chrisae9 · 7 months ago

+1 for this feature! I have a related use case:

Use Case: External status indicators (tmux, polybar, waybar, etc.)

I'm using hooks to update my tmux status bar to show Claude's state:

  • PermissionRequest → Yellow status (Claude needs input)
  • Stop → Green status (Claude idle)

The problem: there's no hook to clear the yellow when I approve a permission. Currently:

  1. PreToolUse fires before the permission check
  2. PostToolUse fires after the tool completes

So for long-running commands, the status stays yellow during the entire execution even though I've already approved. The PermissionResponse hook would let me clear the status immediately on approval.

Example config:

{
  "hooks": {
    "PermissionRequest": [
      { "hooks": [{ "type": "command", "command": "tmux-status.sh yellow" }] }
    ],
    "PermissionResponse": [
      { "hooks": [{ "type": "command", "command": "tmux-status.sh clear" }] }
    ]
  }
}

This would make external status indicators accurately reflect when Claude actually needs attention vs when a tool is just running.

hiragram · 6 months ago

+1 to this

SimeonC · 6 months ago

I too would like this. My use case is also updating External status indicators and having the "permissions accepted but tool not finished" for things like npm run build or linters that take several minutes leaves quite a gap where we cannot know if the claude session is "waiting for input" or not.

The case get's quite a lot more complicated when taking into account Agent Teams which can also fire off permissions requests.

axelson · 5 months ago

+1 for this. I'd also like to use this to know which worktree to switch to (and I also want to ensure this issue doesn't get marked as stale)

evgunter · 5 months ago

+1; i have the same use case as @chrisae9

sethfitz · 5 months ago

My use case is to clear status indicators triggered by PreToolUse (fired before PermissionRequest) when I explicitly deny with a reason (allowing the agent loop to continue) and PostToolUse never fires.

mr-lee · 5 months ago

+1. The lack of tool_use_id on PermissionRequest makes it impossible to correlate permissions with tool usage.

When a PermissionRequest fires, the hook payload includes the tool name and input but not the tool_use_id. The only workaround is positional matching — the permission event sits between the tool's PreToolUse and PostToolUse for the same tool name — which breaks for parallel calls to the same tool in one turn.

The paired PermissionRequest/PermissionResponse design here would solve this cleanly:

  • tool_use_id — direct link to the tool call being gated
  • request_id — pairs the request to its response, even with out-of-order events
  • Response type (allow/deny/allow_always) — currently the only way to know a tool was allowed is to observe that PostToolUse fired afterward

Also +1 on #37153's ToolUseDenied idea — a denied tool currently produces a PreToolUse with no matching PostToolUse, and consumers can't distinguish a denial from an interrupt or a crash.

fpohtmeh · 5 months ago

I have another use case, where a paired hook is needed for PermissionRequest
Thus:

  • Claude is connected to my IDE through RPC and hooks
  • PermissionRequest make an UI component red for developer attention
  • There is no guaranteed way to know that the permission has been processed to make the UI component color normal again

Showing cached comments. Read the full discussion on GitHub ↗