[FEATURE] Replace idle_prompt timer heuristic with deterministic state-aware idle detection

Resolved 💬 3 comments Opened Mar 9, 2026 by jayenashar Closed Apr 13, 2026

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

The idle_prompt notification hook uses a 60-second timer to guess when Claude is idle. This is fundamentally the wrong approach — Claude Code is a state machine that knows whether it's idle or actively working. The timer causes two problems:

  1. ~1 minute delay before notification: When Claude finishes its work and is genuinely waiting for input, the user doesn't find out for 60 seconds. This is especially painful when multitasking across multiple Claude sessions.
  1. False positives during "thinking" pauses: Claude sometimes pauses for extended periods while reasoning (e.g., between tool calls, during complex planning). The timer can't distinguish "Claude is thinking" from "Claude is done and waiting" — but Claude Code itself absolutely can, because it knows whether it's mid-turn or has yielded control back to the user.

Proposed Solution

Emit idle notifications immediately and deterministically based on Claude Code's internal state, not a timer:

  • When Claude's turn ends and the input prompt is shown → fire notification immediately (0 delay, not 60s)
  • When Claude is mid-turn (thinking, waiting for API response, between tool calls) → do not fire, regardless of elapsed time
  • When Claude is waiting for permission approval → fire permission_prompt immediately (this already works better)

Additionally, include background task metadata in the hook's stdin JSON, so the notification hook can make smarter decisions:

{
  "notification_type": "idle_prompt",
  "cwd": "/home/user/project",
  "message": "Claude is waiting for your input",
  "background_tasks": [
    {"id": "task-123", "description": "Running tests", "status": "running"},
    {"id": "task-456", "description": "Building project", "status": "running"}
  ],
  "has_running_background_tasks": true
}

This lets hook scripts decide whether to notify differently when background work is still in progress (e.g., "Claude is idle but 2 background tasks are still running" vs "Claude is completely done").

Related Issues

  • #13922 — Configurable timeout for idle_prompt (workaround for the same root cause)
  • #21238 — Immediate notification when Claude awaits user input
  • #12048 — idle_prompt fires after every response / false positives (closed)
  • #19627 — High latency in hook invocation
  • #23383 — Notification hook delay vs Stop hook

These issues all stem from the same root cause: using a timer heuristic instead of leveraging Claude Code's own state machine. A deterministic approach would resolve all of them.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗