Install
$ agentstack add skill-shirley-xue-2025-usage-guard-usage-guard Open-source listing — not yet scanned by AgentStack. Follow the source repository for install instructions.
Security review
⚠ Flagged1 finding(s); flagged for manual review. · v0.1.0 How review works →
- • Prompt-injection patterns
- • Secret / credential exfiltration
- • Dangerous shell & filesystem operations
- • Untrusted network calls
- • Known-malicious package signatures
- high Possible prompt-injection directive.
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
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//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 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(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-idto 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. /loop guard tick (preferred) — any session type: ``text /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) uses ScheduleWakeup` internally 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 ScheduleWakeup for dynamic /loop, but it often works for one-shot waits too — never fall back to asking the user to ping you.
- 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 , 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.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: shirley-xue-2025
- Source: shirley-xue-2025/usage-guard
- License: MIT
- Homepage: https://github.com/shirley-xue-2025/usage-guard#install-macos
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.