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

Small Claude Code mods.
/plugin marketplace add PhilRoli/claude-mods
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.
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.
hooks/register.ts 49 lines1import 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