Claude Code has no setting that warns you before a usage limit. It does pass your 5-hour and weekly usage to your statusLine command as rate_limits on stdin, and hooks never receive those numbers. So a warning has to live in a statusline script: read rate_limits.five_hour.used_percentage and resets_at, and send a notification when the percentage crosses a line. Below is a script you can write yourself, then how anotifier 1.5.0 and later does the same at 70%, 85% and 95% for both windows. It works on Claude.ai Pro and Max plans only.
Rather skip the manual setup? One command wires every agent you have installed to desktop toasts, phone push, and Slack, Discord or Telegram:
Updated 2026-10-16 · also see the Claude Code notifier and the full docs
Claude Code runs your statusLine command and writes a JSON session object to its stdin. For subscribers it includes a rate_limits object with two rolling windows. Each has used_percentage (0 to 100) and resets_at (Unix epoch seconds):
{
"rate_limits": {
"five_hour": {
"used_percentage": 72.4,
"resets_at": 1738425600
},
"seven_day": {
"used_percentage": 41.2,
"resets_at": 1738857600
}
}
}rate_limits is present only for Claude.ai Pro and Max subscribers, and only after the first API response of a session. Each window can be missing, so code must cope with absence (behind a Claude apps gateway you get spend_limit instead; anotifier doesn't watch it)./compact, at session start, and on a few other events. A chat you leave idle does not refresh unless you set refreshInterval (seconds) on statusLine, which re-runs it on a timer so idle chats are checked too.This Node script prints a short status line and sends an ntfy push when the 5-hour window first crosses 70%, 85% and 95%. It remembers the highest line it has already announced in ~/.claude/.usage-alert.json, and starts over when resets_at moves to a later window. It prints the line first, sends next, and records the line only after the send succeeds, because Claude Code cancels a run that is still going when a new update arrives, and a cancel after the state was written would lose that warning for good. Save it as ~/.claude/usage-line.mjs:
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
const input = JSON.parse(fs.readFileSync(0, "utf8"));
const model = input.model?.display_name ?? "Claude";
const win = input.rate_limits?.five_hour;
if (typeof win?.used_percentage !== "number") {
process.stdout.write(`[${model}]\n`);
} else {
const pct = Math.round(win.used_percentage);
process.stdout.write(`[${model}] 5h: ${pct}%\n`); // print first
const resetsAt = win.resets_at ?? 0;
const level = [70, 85, 95].filter((t) => pct >= t).pop() ?? 0;
const file = path.join(os.homedir(), ".claude", ".usage-alert.json");
let seen = { resetsAt: 0, level: 0 };
try {
seen = JSON.parse(fs.readFileSync(file, "utf8"));
} catch {}
if (resetsAt > seen.resetsAt + 600) seen.level = 0; // a new window began
if (level > seen.level) {
const at = new Date(resetsAt * 1000).toLocaleTimeString([], {
hour: "2-digit",
minute: "2-digit",
});
const res = await fetch("https://ntfy.sh/your-secret-topic", {
method: "POST",
headers: {
Title: `Claude Code 5-hour limit at ${pct}%`,
Priority: level >= 95 ? "urgent" : level >= 85 ? "high" : "default",
},
body: `Resets at ${at}`,
signal: AbortSignal.timeout(3000),
}).catch(() => null);
// Record it only after a successful send, so a cancelled run retries.
if (res?.ok) fs.writeFileSync(file, JSON.stringify({ resetsAt, level }));
}
}Then point Claude Code at it in ~/.claude/settings.json:
{
"statusLine": {
"type": "command",
"command": "node ~/.claude/usage-line.mjs"
}
}npx anotifier@latest setupanotifier watches the 5-hour and weekly windows and sends one notification as each crosses 70%, 85% and 95%. The title names the window and the percentage, such as Claude Code · 5-hour limit at 72%. The body names the chat, the threshold and the reset time, for example my-app [1a2b3c4d] crossed 70% of the 5-hour usage limit. Resets 14:30 (in 2h 10m). The chat is name (project) [first 8 of session id] when the session has a name that differs from the project folder, and otherwise project [id], so two chats in one folder stay apart.
| Threshold | Priority | ntfy tag |
|---|---|---|
| 70% | default | hourglass_flowing_sand |
| 85% | high | warning |
| 95% | urgent | rotating_light |
rate_limits, so there is nothing to warn about and nothing is sent.Because only the statusline sees usage, setup points the Claude Code statusLine at anotifier's statusline.mjs. If you already have a statusline command, setup wraps it: your command still runs with the same input and its output is still the line you see, and npx anotifier uninstall puts your original back exactly. With no statusline of your own, anotifier prints a short line such as Opus · 5h 42% · 7d 12%. A statusLine that is not a command is left alone. anotifier status shows whether it is wired.
Change the thresholds or turn the feature off in ~/.anotifier/config.json. This is the default:
{
"usageAlerts": {
"enabled": true,
"thresholds": [
70,
85,
95
]
}
}Thresholds are percentages above 0 and at most 100, so [50, 80, 100] also works. An invalid list is reported and the default applies. Set enabled to false to stop the checks; the statusline keeps working.
Not with a setting, but it passes your 5-hour and weekly usage (rate_limits.five_hour.used_percentage and resets_at) to your statusLine command. A script there can send a notification when you cross a percentage. anotifier 1.5.0 and later does this for you at 70%, 85% and 95%.
Claude Code only gives the usage numbers to the statusline command, never to hooks, so the warning has to be triggered from the statusline.
No. Claude Code reports rate_limits only for Claude.ai Pro and Max subscribers, so with API-key billing there is nothing to warn about and anotifier sends nothing.
No. Usage is account-wide, so anotifier warns once per threshold per window across all chats on the machine. The first chat to see the crossing sends it, and the notification names that chat, as `name (project) [id]` when the session has a different name from its folder, otherwise `project [id]`.
No. If you already have a statusline command, setup wraps it: your command still runs with the same input and its output is still shown. npx anotifier uninstall restores the original command exactly.
Yes. Set usageAlerts.thresholds in ~/.anotifier/config.json to your own percentages (above 0, at most 100), or usageAlerts.enabled to false. The default is { "enabled": true, "thresholds": [70, 85, 95] }.
No. While you are snoozed or inside quiet hours no warning is sent and none is recorded, so a threshold you crossed in that time is announced once it ends, if you are still over it and the statusline refreshes.
One command wires every agent you have installed: Claude Code, Codex CLI, Cursor, and Gemini CLI.
npx anotifier@latest setup