Summary
In 2.1.141, the Notification hook event with notification_type: permission_prompt does not fire when a permission prompt appears while the assistant is in an active thinking phase. The prompt renders correctly in the TUI; downstream hooks subscribed to Notification never run.
Confirmed working in 2.1.139 with the same project, settings, and hook scripts. 2.1.140 not tested.
Repro
- Configure a
Notification hook with matcher permission_prompt:
where log-prompt.sh is echo "$(date '+%H:%M:%S') fired" >> /tmp/prompts.log.
- Run any task in extended-thinking mode that triggers a permission prompt mid-reasoning. The unsandboxed-Bash override prompt is reliable because it always appears mid-thinking.
- Observe: prompt renders, user sees it.
/tmp/prompts.log gets no new line.
- Downgrade to 2.1.139, repeat.
/tmp/prompts.log gets a new line for every prompt.
PreToolUse and AskUserQuestion hooks fire correctly on 2.1.141 — only Notification:permission_prompt is affected.
Suspected mechanism (from the 2.1.141 binary)
The permission_prompt Notification trigger is gated by a 6-second user-idle check:
const NIK = 6000;
function AR() { return m_.lastInteractionTime; }
function hF3() { return Date.now() - AR(); }
function EF3(H){ return hF3() < H; }
function SF3(H){ return !EF3(H); } // idle ≥ H ms
function KG_(message, notificationType) { // permission_prompt path
...
P1(() => {
if (SF3(NIK)) {
setFired(true);
MHH({ message, notificationType }, q); // ← actual hook fire
}
}, fired ? null : NIK);
}
m_.lastInteractionTime is reset by bt8() (called via u6H(true) → Ci8()). Ci8() is invoked from the SDK control-request handlers:
if (plK(K.request)) Ci8(...) // adjacent to can_use_tool / pendingRequests
if (mlK(_)) Ci8(...) // adjacent to onControlRequestResolved
The release note for 2.1.141 mentions the spinner now warms to amber after 10 seconds during long thinking periods. That feature appears to emit periodic progress/heartbeat control messages on the same channel — each tick matches plK/mlK, calls Ci8 → bt8 → lastInteractionTime = Date.now(). The 6-second idle window never accumulates during thinking, so SF3(6000) stays false and MHH(...) is never reached.
Symbol names may roll in subsequent versions; the structural pattern is KG_(..., "permission_prompt"), gated by SF3(NIK) with NIK = 6000, with lastInteractionTime reset via Ci8() from control-request predicates.
Impact
Any hook subscribed to Notification:permission_prompt silently misses prompts that arrive mid-thinking. The terminalSequence hook output field added in this same release is also effectively unreachable for permission_prompt, since it depends on the parent event firing.
Suggested fix
Exclude progress/spinner heartbeats from the user-interaction reset. Options:
- Narrow
plK/mlK predicates so spinner heartbeats don't match.
- Tag heartbeat control messages and skip
Ci8() for them.
- Decouple the
permission_prompt Notification gate from lastInteractionTime — user-input idle is the wrong proxy when the assistant is what's keeping the system "active".
Environment
- claude-code 2.1.141 (Mach-O arm64, macOS 25.5.0)
- Verified working: 2.1.139
- Not tested: 2.1.140
- Terminal: VS Code Insiders integrated terminal + tmux; also reproduces in Ghostty
Summary
In 2.1.141, the
Notificationhook event withnotification_type: permission_promptdoes not fire when a permission prompt appears while the assistant is in an active thinking phase. The prompt renders correctly in the TUI; downstream hooks subscribed toNotificationnever run.Confirmed working in 2.1.139 with the same project, settings, and hook scripts. 2.1.140 not tested.
Repro
Notificationhook with matcherpermission_prompt:log-prompt.shisecho "$(date '+%H:%M:%S') fired" >> /tmp/prompts.log./tmp/prompts.loggets no new line./tmp/prompts.loggets a new line for every prompt.PreToolUseandAskUserQuestionhooks fire correctly on 2.1.141 — onlyNotification:permission_promptis affected.Suspected mechanism (from the 2.1.141 binary)
The
permission_promptNotification trigger is gated by a 6-second user-idle check:m_.lastInteractionTimeis reset bybt8()(called viau6H(true)→Ci8()).Ci8()is invoked from the SDK control-request handlers:The release note for 2.1.141 mentions the spinner now warms to amber after 10 seconds during long thinking periods. That feature appears to emit periodic progress/heartbeat control messages on the same channel — each tick matches
plK/mlK, callsCi8 → bt8 → lastInteractionTime = Date.now(). The 6-second idle window never accumulates during thinking, soSF3(6000)stays false andMHH(...)is never reached.Symbol names may roll in subsequent versions; the structural pattern is
KG_(..., "permission_prompt"), gated bySF3(NIK)withNIK = 6000, withlastInteractionTimereset viaCi8()from control-request predicates.Impact
Any hook subscribed to
Notification:permission_promptsilently misses prompts that arrive mid-thinking. TheterminalSequencehook output field added in this same release is also effectively unreachable forpermission_prompt, since it depends on the parent event firing.Suggested fix
Exclude progress/spinner heartbeats from the user-interaction reset. Options:
plK/mlKpredicates so spinner heartbeats don't match.Ci8()for them.permission_promptNotification gate fromlastInteractionTime— user-input idle is the wrong proxy when the assistant is what's keeping the system "active".Environment