[FEATURE] Mods: let a plugin decide whether Claude Code's turn-end notification is shown
Request
Raise the turn-end notification as a hookable event, so a mod can let it through, hold it back, or reword it before Claude Code (terminal or desktop app) shows it. For example:
on('notification.show', { kind: 'turn-complete' }, async ($, e, next) =>
(await isWaitingOnBackgroundWork($)) ? { suppress: true } : next(e))
Why
Whether a session needs the user is decided by built-in classifiers that can't be changed:
- The agents view reads Claude's final message with fixed text rules ("Needs input" on a trailing question, "waiting for the tests" means working).
- The desktop app decides its "task complete" banner on its own.
The fixed rules miss phrasings they don't list. "Waiting on the background test run" doesn't match their "waiting on the tests" pattern, for example. The result is a banner while Claude is still waiting on results, or none when the user is needed.
A mod has better information than these rules. At turn end it gets the in-flight background_tasks and session_crons (classic.Stop), plus the final message, and can classify with a model call ($.model.complete). But it can't act on the result. In 2.1.289:
- skipping the chain in
turn.complete,classic.Stopandclassic.Notificationdoesn't stop the desktop banner (tested) classic.Notificationdoesn't fire at turn end in a desktop session at all- the only control is the on/off Task complete notifications setting
The workaround is to turn the app's banner off and send a separate notification from the mod. That runs into what #99306 describes: osascript notifications come from Script Editor and clicking them focuses nothing, and PushNotification reports no_transport without Remote Control.
Proposed shape
- One event before any notification Claude Code shows (turn complete, needs input, permission request), with the kind, the session, and the text or summary it would show.
- A hook can return
next(e)to show it,{ suppress: true }to hold it back, or rewrite its text. - It applies to both the terminal and the desktop app's banners, so one mod covers both.
- Optionally, expose the built-in verdict (working / needs input / done) on the event, so a mod can build on it rather than redo it.
Related
- #99306 (let a plugin send a native notification)
- #91870 (mods umbrella)
Environment
- Claude Code 2.1.289, desktop app (macOS), mods API (
hooks/register.tsmodule)