[Feature] Native settings option for idle/ready notification (no hook needed)

Resolved 💬 3 comments Opened May 1, 2026 by Lc2306 Closed May 4, 2026

[Feature] Native settings option for idle/ready notification (no hook needed)

Summary

Add a built-in config option in settings.json that triggers a sound (terminal bell, local command, or system notification) when Claude Code returns to the idle state waiting for user input. Implementation lives in the binary — no hooks, no LLM tokens, no shell scripts to maintain.

Motivation

Long-running tasks make users tab away. When Claude finishes a complex task and waits for the next prompt, there's no audible signal that it's ready. Hook-based workarounds are unreliable:

  • Stop hook fires multiple times within complex tasks (subagent bubbling, plan mode, internal continuations) → false beeps mid-task
  • Notification with idle_prompt matcher is documented as buggy (#8320) → fires on every response, not on real idle
  • DIY state machines via shell hooks consume time, debugging effort, and miss edge cases (we tried)

Issue #13024 requests the same goal but as a hook. A hook still requires the user to write/maintain shell scripts, handle WSLg/Wayland/macOS audio differences, and reinvent debounce logic — all for a binary state the runtime already knows internally.

Proposed Design (mirrors existing statusLine)

{
  "idleNotify": {
    "enabled": true,
    "command": "paplay /usr/share/sounds/freedesktop/stereo/complete.oga"
  }
}

Or a minimal terminal-bell variant:

{
  "idleNotify": "bell"
}

Possible values:

  • "bell" — emit \a to the terminal
  • "none" (default) — disabled
  • { "command": "<shell command>" } — runtime invokes any local command

Fires once on the transition into "ready for next user prompt". Subagent stops, auto-compaction, and internal continuations do not trigger it — the runtime distinguishes those because the state is internal to the binary.

Why Not a Hook

A hook can't reliably distinguish "Claude is idle waiting for me" from "Claude is mid-task between internal turns" — the difference lives inside the binary. Exposing the transition as a native config trigger:

  1. Solves the problem correctly (no false positives possible)
  2. Zero LLM token cost
  3. Removes WSLg/Wayland/macOS/tmux audio concerns from user-space
  4. No shell debugging, no state files in /tmp

Precedent

statusLine is the existing pattern: native config, runtime decides invocation timing, user provides a local command. idleNotify would be the same shape.

Related

  • #13024 — same goal, hook-based proposal
  • #8320 — idle_prompt notification matcher bug
  • #12048 — broader notification matcher gaps

View original on GitHub ↗

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