SLOPSHOPPER

turn-timer

Speaks and toasts when a long turn finishes

newtoastaudio
v0.1.0no licenseupdated 2026-10-02anthonyhungnguyen/claude-code-mods/turn-timer
A shopper browsing a rack in a slop shop
README

claude-code-mods

Mods for Claude Code, one folder each. A mod is a plugin of function hooks: panes, status lines, slash commands, tool guards.

ModWhat it does
cost-paneToken and USD spend per session and per day, in the status line and a /cost-pane pane
context-guardContext window fill in the status line; a toast once it passes 80%
cache-watchA toast when a turn rebuilt the prompt cache: tokens written, turn cost, likely cause (idle, model change)
turn-timerSpeaks (say on macOS) and toasts when a turn longer than 2 minutes finishes

Install

git clone git@github.com:anthonyhungnguyen/claude-code-mods.git ~/.claude/mods

List each mod folder you want in ~/.claude/settings.json, separated by ::

{ "env": { "CLAUDE_CODE_PLUGIN_DIRS": "~/.claude/mods/cost-pane:~/.claude/mods/context-guard:~/.claude/mods/cache-watch:~/.claude/mods/turn-timer" } }

New sessions load them. Check a mod with claude plugin validate ~/.claude/mods/<mod>.

Source 1 files
hooks/register.ts 18 lines
1import type { Register } from 'claude-code'
2
3const LONG_MS = 120_000
4
5export const register: Register = on => {
6  on('turn.complete', async ($, e, next) => {
7    const done = await next(e)
8    if (e.agentId || e.isAborted || e.durationMs < LONG_MS) return done
9
10    const min = Math.round(e.durationMs / 60_000)
11    const ok = e.reason === 'answer'
12    $.ui.toast(`${ok ? 'Done' : 'Stopped'} after ${min} min`)
13    // no synthesizer (Linux, a remote surface): the toast still shows
14    void $.audio.speak(ok ? `Claude finished, ${min} minutes` : 'Claude stopped with an error').catch(() => {})
15    return done
16  })
17}
18