[FEATURE] Delayed and Debounced Hook Execution with Cancellation Events
[FEATURE] Delayed and Debounced Hook Execution with Cancellation Events
Preflight Checklist
- [x] I have searched existing requests and this feature hasn't been requested yet
- [x] This is a single feature request (not multiple features)
Problem Statement
When Claude Code requires user attention (permission prompts, idle prompts, etc.), I want different notification behaviors based on my availability:
- At my desk: Instant desktop notification is sufficient
- Stepped away briefly: SMS/mobile notification after 2 minutes of no response
- Away for extended period: Slack message after 10 minutes
Currently, all hooks fire immediately when their event triggers. There's no way to implement "notify me on my phone only if I haven't responded within 2 minutes" without complex external state management involving:
- Writing marker files with timestamps
- Running separate cron jobs or daemons
- Coordinating state across multiple hook invocations
This pattern is common in on-call/alerting systems (PagerDuty, OpsGenie) where notifications escalate through channels based on response time.
Proposed Solution
Add two new optional fields to hook configuration:
delay (number, seconds)
Wait N seconds before executing the hook. If a cancelOn event fires before the delay expires, the hook is cancelled.
cancelOn (string array)
List of event names that cancel a pending delayed hook before it fires.
Example Configuration
{
"hooks": {
"Notification": [
{
"matcher": "permission_prompt",
"hooks": [
{
"type": "command",
"command": "notify-send 'Claude needs attention'",
"statusMessage": "Desktop notification"
},
{
"type": "command",
"command": "/scripts/send-sms.sh",
"delay": 120,
"cancelOn": ["PermissionRequest", "UserPromptSubmit"],
"statusMessage": "SMS notification (2 min delay)"
},
{
"type": "command",
"command": "/scripts/send-slack.sh '#alerts'",
"delay": 600,
"cancelOn": ["PermissionRequest", "UserPromptSubmit"],
"statusMessage": "Slack notification (10 min delay)"
}
]
}
]
}
}
Behavior: When a permission prompt appears:
- Desktop notification fires immediately
- SMS is scheduled for 2 minutes later
- Slack is scheduled for 10 minutes later
- If user responds (triggering
PermissionRequest), both delayed hooks are cancelled - If user doesn't respond within 2 minutes, SMS fires; if still no response by 10 minutes, Slack fires
Optional: debounce field
For coalescing rapid-fire events (alternative to delay):
{
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "/scripts/notify-batch-complete.sh",
"debounce": 30
}
]
}
]
}
This fires once, 30 seconds after the last file edit, rather than after every single edit.
Alternative Solutions
Current workaround: External state management
#!/bin/bash
# Hook 1: Schedule delayed notification
MARKER="/tmp/claude-pending-$(jq -r '.session_id')"
echo "$(date +%s)" > "$MARKER"
(sleep 120 && [ -f "$MARKER" ] && /scripts/send-sms.sh) &
# Hook 2: Cancel on action
rm -f "/tmp/claude-pending-*"
Problems:
- Requires coordination between multiple hooks
- Background processes can outlive Claude Code session
- State files can get out of sync
- No visibility into pending notifications
- Error-prone race conditions
Alternative: External webhook service
Push to a service like Zapier that handles delays.
Problems:
- Requires external infrastructure
- Adds latency and complexity
- Harder to configure per-project
Priority
Medium - Would be very helpful
This is particularly valuable for:
- Remote/headless Claude Code sessions (SSH, CI/CD)
- Long-running agentic tasks
- Teams with different notification urgency tiers
Feature Category
Configuration and settings
(Hooks subsystem)
Use Case Example
Scenario: Working remotely with Claude Code over SSH
- I start a long-running Claude task on a remote server via SSH
- Claude needs permission to run a deployment script
- Immediate: Desktop notification fires (but I've stepped away for coffee)
- After 2 minutes: No response, so SMS fires to my phone
- I see the SMS, SSH back in, and approve the permission
- Cancelled: The 10-minute Slack escalation never fires because I responded
Without this feature: I either miss the notification entirely (if only desktop), or get spammed on all channels simultaneously (annoying and noisy).
Additional Context
Similar patterns in other tools
- PagerDuty/OpsGenie: Escalation policies with time-based routing
- GitHub Actions:
timeout-minuteswith conditional steps - Kubernetes: Probe delays with
initialDelaySeconds
Implementation considerations
- Pending delayed hooks could be tracked per-session
/hooksmenu could show pending hooks with countdown- On session end, pending hooks could be cancelled or optionally executed
- Verbose mode (
Ctrl+O) should log scheduling, cancellation, and execution
Proposed UI in /hooks menu
Pending Delayed Hooks:
- SMS notification (fires in 1m 42s) [Cancel]
- Slack notification (fires in 8m 42s) [Cancel]This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗