SLOPSHOPPER

session-limit-pause

Tells Claude to wrap up when the 5-hour or weekly usage window is nearly used.

newstatusprompt
A shopper browsing a rack in a slop shop
README

claude-mods

Small Claude Code mods.

/plugin marketplace add PhilRoli/claude-mods

train-pause

For TrainTracker. Shortly before your tracked train arrives (default: 10 minutes), every session is told to stop starting new work, leave the code in a consistent state and report what's done and what remains, so you can switch locations or turn off wifi without cutting a session off mid-task.

/plugin install train-pause@claude-mods

Requires TrainTracker (≥ 1.3.0), which writes the arrival time to ~/.traintracker/arrival.json ({"arrival": <epoch seconds, delay included>}) while a train is tracked. Idle sessions pick up the instruction on their next prompt; the status line shows a countdown. Change the window with WRAP_UP_MINUTES in plugins/train-pause/hooks/register.ts.

session-limit-pause

Same idea for usage limits: once the 5-hour or weekly window is ≥ 95% used, the session is told to wrap up. A window that resets within 5 minutes is ignored. Needs a subscription (the engine reports no limits otherwise).

/plugin install session-limit-pause@claude-mods

Tune with WRAP_UP_PERCENT and IGNORE_IF_RESET_WITHIN_MIN in plugins/session-limit-pause/hooks/register.ts.

Source 1 files
hooks/register.ts 49 lines
1import type { Register, SessionRateLimit } from 'claude-code'
2
3const WRAP_UP_PERCENT = 95
4const IGNORE_IF_RESET_WITHIN_MIN = 5
5
6const LABELS: Record<string, string> = { five_hour: '5-hour session', seven_day: 'weekly', spend_limit: 'spend' }
7
8const resetsSoon = (l: SessionRateLimit, nowMs: number) =>
9  l.resetsAt !== undefined && Date.parse(l.resetsAt) - nowMs <= IGNORE_IF_RESET_WITHIN_MIN * 60_000
10
11export const nearLimit = (limits: SessionRateLimit[], nowMs: number): SessionRateLimit | undefined =>
12  limits
13    .filter(l => l.percentUsed >= WRAP_UP_PERCENT && !resetsSoon(l, nowMs))
14    .sort((a, b) => b.percentUsed - a.percentUsed)[0]
15
16const describe = (l: SessionRateLimit) => {
17  const label = LABELS[l.kind] ?? l.kind
18  const reset = l.resetsAt ? ` (resets ${new Date(l.resetsAt).toLocaleTimeString()})` : ''
19  return `${label} limit ${Math.round(l.percentUsed)}% used${reset}`
20}
21
22export const register: Register = on => {
23  on('session.measure', async ($, e, next) => {
24    const hit = nearLimit(e.rateLimits, await $.clock.now())
25    $.ui.status(hit ? `⏳ ${describe(hit)} — wrap up` : undefined)
26    return next(e)
27  })
28
29  on('prompt.compose', async ($, e, next) => {
30    const res = await next(e)
31    const hit = nearLimit((await $.session.usage()).rateLimits, await $.clock.now())
32    if (!hit) return res
33    return {
34      sections: [
35        ...res.sections,
36        {
37          id: `${$.plugin.name}:wrap-up`,
38          scope: 'session',
39          text:
40            `The user's ${describe(hit)}; they are about to be cut off. ` +
41            `Do not start new work. Finish the current step only if it can be done in a minute or two, leave the code in a ` +
42            `consistent, working state (no half-applied edits), commit or note progress if appropriate, then stop and tell ` +
43            `the user briefly what is done and what remains so they can resume after the limit resets.`,
44        },
45      ],
46    }
47  })
48}
49