AgentStack
SKILL unreviewed MIT Self-run

Usage Guard

skill-shirley-xue-2025-usage-guard-usage-guard · by shirley-xue-2025

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.

No reviews yet
0 installs
13 views
0.0% view→install

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

⚠ Flagged

1 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.

Are you the author of Usage Guard? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

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:

  1. Follow this file (you are reading it — treat that as the contract).
  2. Run arm.sh via bash before heavy work (same as ARM MODE below).
  3. Tell the user: /usage-guard is the normal entry point; with disable-model-invocation it may not show in the slash picker — typing /usage-guard still 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 with resume): 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: true
  • phase is normal (or five_hour_percent is set) — not stuck on waiting_first_poll without 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, statenot raw UTC strings
  • If weekly_percent is present (weekly monitoring enabled in config), also report weekly % and weekly_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 status formats them), or run usage-guard poll for a live snapshot

If arm JSON has "already_armed": true (daemon from a prior sitting):

  • Proceed — guard is active; do not --force restart unless user asks.
  • Same arc, new sittingjoin.sh --task "label" (not arm with a task — task is ignored on already_armed; JSON includes task_ignored if you tried).
  • After joincheckpoint.sh writes to sitting_session_id automatically (stored in control.json). Do not use primary session_id unless you pass --session-id intentionally.
  • 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 state only: RUN = continue, PAUSE or COOLDOWN = 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, or both) 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 run claude login or usage-guard doctor (they may get a macOS notification). state may still say RUN.
  • Never decide pause/continue from five_hour_percent yourself.
  • 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 or five_hour_reset_pending: false = reset time passed
  • five_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 (OAuth seven_day = Desktop "All models" weekly bar)
  • If state is RUN, 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-null five_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. Check awaiting_post_reset_poll and percent_note; trust state. Expect correction at daemon_next_poll_at / daemon_next_poll_local.
  • After a window reset, five_hour_percent may be null until the daemon's next poll. If state is RUN, trust state (check last_reset_at if present) — do not wait for the user to return.
  • session_check_seconds — recommended delay for self-paced /loop guard ticks while armed. During PAUSE/COOLDOWN, prefer sleep_until instead. 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 primary session_id and sitting_session_id).
  • Later sitting (daemon already running): join.sh --task "this sitting's label" — sets sitting_session_id in control.json; all checkpoint.sh writes go there until the next arm/join.
  • To share one checkpoint chain across sittings (advanced): pass --session-id 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 status in Terminal to see progress if Desktop UI is stuck.

Safe checkpoints (critical for subagents / long runs)

Read control.json only at these times:

  1. Before starting the main task loop
  2. Before dispatching each subagent or parallel batch
  3. After each subagent returns
  4. Before starting any new multi-step tool sequence expected to take >10 minutes
  5. At each /loop iteration 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

  1. Finish the current atomic unit only — do not abandon mid-write.
  2. Update checkpoint with done, next, clear note.
  3. 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.
  4. Do not start new subagents, batches, or long tool chains this turn.
  5. During COOLDOWN, use sleep_until / seconds_until_five_hour_reset for 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 CronCreate one-shot pinned to five_hour_reset_local (+ ~3 min margin)
  • Claude may implement this via ScheduleWakeup or CronCreate — either is fine
  • Chain: if still COOLDOWN after 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.

  1. 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_utilization from control.json, or usage-guard status for 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

  1. Read ~/.usage-guard/control.json — if state is not RUN, tell user to wait (show five_hour_reset_local / sleep_until_local, or seconds_until_*).
  2. Read checkpoint for sitting_session_id (or checkpoint_writes_target / primary session_id if no join).
  3. Continue from next; dedupe using done.
  4. Re-arm only if armed is false: run arm.sh again.

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 resume in a new session (re-arms daemon if needed).
  • Daemon exit does not keep the guard active — always /usage-guard or /usage-guard resume at 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.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.