Usage guard
Proactive 5h usage guard for Claude Code (macOS). Pause before extra wallet on long batch/subagent runs. Account-level window visibility. /usage-guard skill + daemon. Not affiliated with Anthropic.
npx -y skills add shirley-xue-2025/usage-guard --skill usage-guardAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 14 stars14 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Arm proactive 5-hour usage protection for long Claude Code sessions (batch, subagents, high window % at start). Daemon reads account-level 5-hour window usage (not per-session). User types /usage-guard at session start. Re-arm every sitting. If user mentions usage-guard by name, read this file and run arm.sh.
SKILL.md
12.9 KB, as published. Nobody here has run it
usage-guard
Proactive usage guard for long Claude Code sessions (Desktop Code tab or CLI). Invoke once at session start before heavy batch, subagent, or overnight work — especially when the account window is already partly used.
Why account-level monitoring matters
Each Claude session only sees its own usage. The shared 5-hour window is account-level — you can start at 58% in one session while another tab or earlier work already pushed the window to 94%. The daemon polls the OAuth usage API (same as Desktop Settings) so the guard sees the real window, not just this chat's view.
Re-arm every sitting
Arms do not survive Desktop quit, crash, or daemon exit. At the start of every new sitting, run /usage-guard (or /usage-guard resume if continuing a paused task). If arm.sh prints "warning", the previous guard was stale — proceed with the new arm.
If the user mentions usage-guard without /usage-guard
When the user says "use usage-guard", "pay attention to usage limits", or names this skill but does not run the slash command:
- Follow this file (you are reading it — treat that as the contract).
- Run
arm.shvia bash before heavy work (same as ARM MODE below). - Tell the user:
/usage-guardis the normal entry point; withdisable-model-invocationit may not show in the slash picker — typing/usage-guardstill works.
Do not auto-arm on your own initiative without the user asking for usage protection.
When the user invokes /usage-guard
Mode detection
- If the argument is
resume(or starts withresume): RESUME MODE (skip arm, go to section 4). - Otherwise: ARM MODE.
1. ARM MODE — start guard
Run:
bash "${CLAUDE_SKILL_DIR}/scripts/arm.sh" {{ARGUMENTS}}
If arm fails, stop and tell the user to run usage-guard doctor in Terminal. Do not start heavy work without a successful arm.
Read ~/.usage-guard/control.json once and confirm:
armed: truephaseisnormal(orfive_hour_percentis set) — not stuck onwaiting_first_pollwithout a live daemon- If arm JSON output includes
"warning", tell the user the prior guard was not active and this is a fresh arm - Report go/no-go using arm JSON:
five_hour_percent,five_hour_reset_local,seconds_until_five_hour_reset,state— not raw UTC strings - If
weekly_percentis present (weekly monitoring enabled in config), also report weekly % andweekly_reset_local/seconds_until_weekly_reset. Weekly can trigger PAUSE even when 5h looks safe. - If present in control.json, also report extra usage wallet:
extra_used_credits,extra_monthly_limit,extra_utilization,extra_currency(amounts are in cents;usage-guard statusformats them), or runusage-guard pollfor a live snapshot
If arm JSON has "already_armed": true (daemon from a prior sitting):
- Proceed — guard is active; do not
--forcerestart unless user asks. - Same arc, new sitting →
join.sh --task "label"(not arm with a task — task is ignored on already_armed; JSON includestask_ignoredif you tried). - After join →
checkpoint.shwrites tositting_session_idautomatically (stored in control.json). Do not use primarysession_idunless you pass--session-idintentionally. - Continuing paused work →
/usage-guard resume(not join, not fresh arm).
Decision tree: already_armed + same sitting → proceed on checkpoint_writes_target | new sitting same arc → join.sh | paused task → resume | dead daemon → arm fresh
Warmup: right after arm, phase may be waiting_first_poll with null telemetry while the daemon fetches usage. arm.sh blocks up to ~45s for the first poll. If phase is still waiting_first_poll after arm returns, the daemon is warming up — do not start heavy subagent batches yet; re-read control.json in a few seconds. If five_hour_percent stays null and daemon is dead (usage-guard status → daemon not running), stop and run usage-guard doctor.
2. Session contract (inform up front — before main work)
You are now usage-guard armed. Follow this for the rest of this session:
Control file (only signal that matters)
- Path:
~/.usage-guard/control.json - Obey
stateonly:RUN= continue,PAUSEorCOOLDOWN= stop dispatching new work. - Either limit can pause: account 5-hour window (default 90%) or weekly limit (opt-in, default 98%) — check
pause_reason(five_hour,weekly, orboth) in control.json. - Exception —
telemetry_lost: true: usage API returned no 5h percent for several polls. Guard is blind — do not start heavy or long work; tell user to runclaude loginorusage-guard doctor(they may get a macOS notification).statemay still sayRUN. - Never decide pause/continue from
five_hour_percentyourself. - Never compare timestamps yourself (
five_hour_resets_at,sleep_until, etc.). UTC trips up models. Use precomputed fields only:seconds_until_five_hour_reset— positive = reset not yet; negative orfive_hour_reset_pending: false= reset time passedfive_hour_reset_local— for user-facing reports (local timezone, not UTC)weekly_percent,weekly_reset_local,seconds_until_weekly_reset— when weekly monitoring is enabled (OAuthseven_day= Desktop "All models" weekly bar)- If
stateisRUN, continue — do not call percent "stale" because a UTC clock comparison looked past. Wrong timezone math caused false "reset already passed" bugs.
- Post-reset poll lag:
five_hour_reset_pending: false+ non-nullfive_hour_percent(e.g. 88% with reset time an hour ago) means the old window's percent until the daemon re-polls — not a reason to pause. Checkawaiting_post_reset_pollandpercent_note; truststate. Expect correction atdaemon_next_poll_at/daemon_next_poll_local. - After a window reset,
five_hour_percentmay benulluntil the daemon's next poll. IfstateisRUN, truststate(checklast_reset_atif present) — do not wait for the user to return. session_check_seconds— recommended delay for self-paced/loopguard ticks while armed. DuringPAUSE/COOLDOWN, prefersleep_untilinstead. Daemon polling is separate (daemon_next_poll_at).
Checkpoint file
- Path:
~/.usage-guard/sessions/<session_id>/checkpoint.json(session_id from control.json) - After every completed unit (file, batch item, subagent return): update checkpoint (
done,next,note). - Prefer bash (atomic, no Read-before-Write harness issue):
bash "${CLAUDE_SKILL_DIR}/scripts/checkpoint.sh" --quiet --json '{"done":["item-id"],"next":"next-item","note":""}'
Or flags: checkpoint.sh --quiet --done item-id --next "next-item" --note "" --task "short label for status"
Set task on the first checkpoint (via /usage-guard <task> at arm, or checkpoint.sh --task) so usage-guard status stays readable.
Multi-session arcs (orchestrator + worker sessions)
PAUSE/RUN is account-level (one daemon). Checkpoints are per session_id.
- First sitting:
/usage-guard <task>(arms daemon; sets primarysession_idandsitting_session_id). - Later sitting (daemon already running):
join.sh --task "this sitting's label"— setssitting_session_idin control.json; allcheckpoint.shwrites go there until the next arm/join. - To share one checkpoint chain across sittings (advanced): pass
--session-id <existing>to checkpoint.sh explicitly. - join = new sitting, new checkpoint file, same daemon. resume = continue a paused task from checkpoint (COOLDOWN/PAUSE arc), not "daemon already live."
active_session_ids lists all sittings; sitting_session_id is the active checkpoint write target.
- User can run
usage-guard statusin Terminal to see progress if Desktop UI is stuck.
Safe checkpoints (critical for subagents / long runs)
Read control.json only at these times:
- Before starting the main task loop
- Before dispatching each subagent or parallel batch
- After each subagent returns
- Before starting any new multi-step tool sequence expected to take >10 minutes
- At each
/loopiteration dedicated to guard checks
Never rely on the user sending a chat message mid-run — messages queue during subagent work.
On state == PAUSE or COOLDOWN
-
Finish the current atomic unit only — do not abandon mid-write.
-
Update checkpoint with
done,next, clearnote. -
Tell the user: paused near usage limit (
pause_reason); daemon may macOS-notify at reset. Do not treat that as a substitute for scheduling your own wake-up below. -
Do not start new subagents, batches, or long tool chains this turn.
-
During
COOLDOWN, usesleep_until/seconds_until_five_hour_resetfor wait duration — do not poll every 5 minutes.Before ending this turn, you must schedule a wake-up. Forbidden: ending with "ping me when reset", "tell me when you're back", or "message me after the window resets".
Pick one path (in order of preference):
A.
/loopguard tick (preferred) — any session type:/loop Read ~/.usage-guard/control.json. If PAUSE/COOLDOWN: checkpoint if needed; sleep until sleep_until (cap 59m per iteration; chain). If RUN: continue from checkpoint next.Dynamic
/loop(no interval) usesScheduleWakeupinternally after each iteration.B. One-shot wake at reset — if you are not starting
/loop:- Natural language:
in N minutes, re-read ~/.usage-guard/control.json; if RUN continue checkpoint next; if still COOLDOWN schedule again - Or
CronCreateone-shot pinned tofive_hour_reset_local(+ ~3 min margin) - Claude may implement this via
ScheduleWakeuporCronCreate— either is fine - Chain: if still
COOLDOWNafter fire, schedule the next check (cap 59m steps)
C. Non-negotiable: schedule something before ending the turn. Platform docs emphasize
ScheduleWakeupfor dynamic/loop, but it often works for one-shot waits too — never fall back to asking the user to ping you. - Natural language:
-
If wake scheduling fails (cron disabled, provider lacks loop-dynamic), say so explicitly and give
five_hour_reset_local— checkpoint is still safe for/usage-guard resume.
On state == RUN with existing checkpoint
Continue from next in checkpoint; skip items in done.
Subagent discipline (long batch runs)
- Prefer smaller subagent batches when armed (e.g. 3–5 items, not 50).
- Before each dispatch: read control.json; if not
RUN, do not dispatch. - Main chat orchestrates workload so subagents respect the timetable — no mid-run chat reminders.
Session wrap — report window delta
At session end (or before a long pause), tell the user:
- 5h window now:
five_hour_percent,five_hour_reset_local,state - Weekly limit (if enabled):
weekly_percent,weekly_reset_local,pause_reason - Extra usage wallet (if enabled):
extra_used_credits/extra_monthly_limit/extra_utilizationfrom control.json, orusage-guard statusfor formatted amounts - Delta this sitting if you recorded percent at arm/join (e.g. "4% → 41% this session")
- This is the most useful user-facing summary — report it even without subagents
3. Start work
If the user provided a task in /usage-guard <task>, begin it under the contract above using self-paced /loop.
Example loop prompt:
/loop Read ~/.usage-guard/control.json. If PAUSE/COOLDOWN: checkpoint and stop new work; sleep until sleep_until (or session_check_seconds). If RUN: continue task from checkpoint.
4. RESUME MODE — /usage-guard resume
- Read
~/.usage-guard/control.json— ifstateis notRUN, tell user to wait (showfive_hour_reset_local/sleep_until_local, orseconds_until_*). - Read checkpoint for
sitting_session_id(orcheckpoint_writes_target/ primarysession_idif no join). - Continue from
next; dedupe usingdone. - Re-arm only if
armedis false: runarm.shagain.
5. Limits (be honest with user)
- Cannot force-stop a running subagent from outside; guard prevents new work after PAUSE.
- Progress safety depends on frequent checkpoint writes.
- After force-quit Desktop, use
/usage-guard resumein a new session (re-arms daemon if needed). - Daemon exit does not keep the guard active — always
/usage-guardor/usage-guard resumeat the start of a sitting.