npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@kill-switch/agent-guard

v0.2.0

Published

Kill Switch for coding agents — stop runaway Claude Code / Cursor / Aider sessions from racking up an LLM bill. Native hook + token-metering proxy with per-session and daily-rolling budgets.

Readme

@kill-switch/agent-guard

Kill Switch for coding agents. Stop a runaway Claude Code / Cursor / Aider session from racking up an LLM bill — before it becomes a $4,200 weekend, an $87k month, or a $500M month "after failing to put usage limits on Claude licenses for employees."

A coding agent runs a reasoning loop — read, edit, validate, re-check — and re-sends its entire accumulated context on every tool call. Cost compounds silently. agent-guard puts a hard ceiling on that loop with two complementary surfaces that share one budget:

| Surface | What it is | Stops | Works with | |---|---|---|---| | Hook | A Claude Code PreToolUse / UserPromptSubmit / Stop hook that reads the live transcript, prices real token usage, warns at the soft cap and denies the next tool call at the hard cap | A single Claude Code session, gracefully | Claude Code | | Proxy | A local metering reverse-proxy on the agent's API base URL that counts usage from real responses and returns HTTP 402 at the cap | Any agent — the API literally stops answering | Claude Code, Cursor, Aider, raw scripts |

The hook is the friendly, native stop. The proxy is the dumb hard wall that can't be argued past. Both feed one ledger with two budget scopes:

  • Per-session — catches a single runaway run.
  • Daily rolling 24h — catches many small sessions quietly adding up.

…each with a soft cap (warn + alert) and a hard cap (block).

Install

npm i -g @kill-switch/agent-guard   # provides `agent-guard` and `ksg`

Or use it through the main Kill Switch CLI as ks guard … (same engine, one shared ledger/budget) — see packages/cli.

Developing from this monorepo

The hook is wired into Claude Code by absolute path to dist/cli.js, so it must be built before install, and the bare agent-guard / ksg commands only land on your PATH after a link or publish:

# from the repo root
npm run build:agent-guard          # compile src → dist (required before install/link)
npm run test:agent-guard           # 21 unit tests

# put `agent-guard` / `ksg` on PATH for local dev
cd packages/agent-guard && npm link
agent-guard --help                 # now resolves

# unlink when done
npm rm -g @kill-switch/agent-guard

⚠️ If agent-guard reports command not found (e.g. when a runaway session hits the cap and the recovery command won't run), it just means the package isn't linked/published yet. The block message always prints an absolute-path fallback so recovery works regardless, and ks guard … works whenever the ks CLI is installed. You can also always pause with zero tooling: touch ~/.kill-switch/agent-guard/PAUSED.

Quick start — Claude Code (hook)

# Wire the hook into ./.claude/settings.json (use --global for ~/.claude)
agent-guard install

# Set your caps (USD)
agent-guard config --session-soft 5 --session-hard 20 --daily-soft 25 --daily-hard 100

# See where you stand any time
agent-guard status

That's it. On every tool call the hook recomputes the session's real spend from the transcript. Cross the soft cap → Claude sees a warning and you get an alert. Hit the hard cap → the next tool call is denied with a reason, halting the agent.

Quick start — any other agent (proxy)

agent-guard proxy                      # listens on :8787, meters Anthropic by default
# point your agent at it:
ANTHROPIC_BASE_URL=http://localhost:8787 claude      # (if NOT using the hook — see caveat)
OPENAI_BASE_URL=http://localhost:8787/v1 aider       # agent-guard proxy --flavor openai

At the hard cap the proxy returns 402 kill_switch_budget_exceeded instead of forwarding — the agent can't spend another token.

⚠️ Don't run Claude Code through both the hook and the proxy — they'd each meter the same dollars and double-count. Hook for Claude Code; proxy for everything else.

Budgets

Resolution order (later wins): built-in defaults → ~/.kill-switch/agent-guard/config.json → environment variables. Env override lets you tighten a single risky run:

AGENT_GUARD_SESSION_HARD=10 claude          # one-off $10 ceiling

| Env var | Meaning | Default | |---|---|---| | AGENT_GUARD_SESSION_SOFT | per-session warn (USD) | 5 | | AGENT_GUARD_SESSION_HARD | per-session block (USD) | 20 | | AGENT_GUARD_DAILY_SOFT | rolling-24h warn (USD) | 25 | | AGENT_GUARD_DAILY_HARD | rolling-24h block (USD) | 100 |

A cap of 0 disables that check.

Subscription limits (Claude Code Pro / Max)

Dollar caps are the wrong currency for a Pro/Max subscription: you pay a flat fee, so the scarce resource isn't dollars — it's your plan's rate-limit quota, in two rolling windows:

  • a 5-hour window (burst protection), and
  • a weekly (7-day) window — the real lockout risk, "resets a couple times a month".

Easiest: wire up the statusLine

Claude Code hands its status bar a JSON payload on stdin, and for Pro/Max sessions that payload includes your live standing:

// .claude/settings.json (or settings.local.json)
{ "statusLine": { "type": "command", "command": "agent-guard statusline" } }

That's the whole setup. agent-guard statusline reads rate_limits.five_hour and rate_limits.seven_day off stdin and keeps a live pill in your bar:

🛡 🟢 12%5h · 17%w · 9%d · 5.0wd

This is the primary source, and it's the good kind of boring: it's documented, needs no network call, no credential read, and can't be rate-limited. It also refreshes on every render, so the snapshot the hook paces against is always current.

Two things it can't do, both by design:

  • rate_limits only appears for Claude.ai Pro/Max subscribers, and only after the first API response in a session — so the very first render of a session falls back to the endpoint.
  • It carries no per-model breakdown. If you have a per-model weekly (e.g. a model-specific cap sitting at 56% while your all-models weekly is at 31%), that is your real constraint and stdin won't show it — see below.

Filling the gaps: agent-guard usage

For the per-model weekly, and when stdin isn't available, agent-guard falls back to Anthropic's /api/oauth/usage endpoint:

agent-guard usage     # → 5-hour, weekly, and per-model (Sonnet/Opus) weekly utilization + resets

It reads your Claude Code OAuth token from the OS credential store (macOS Keychain Claude Code-credentials, or ~/.claude/.credentials.json on Linux — used only as a Bearer header, never logged or stored). When statusLine stdin is already supplying 5h + weekly, this runs at most hourly, purely to top up the per-model extras.

⚠️ The endpoint is undocumented and genuinely unreliable — it rate-limits aggressively (429 with an hour-long retry-after) and returns 401 once the stored OAuth token expires. agent-guard now honours the server's cooldown (and backs off exponentially, 5m→1h, on other failures) instead of retrying into the wall; an earlier build hammered it every 120s and kept itself locked out. Treat per-model numbers as best-effort: if the endpoint is unavailable, you'll still get 5h + weekly from stdin, and the guard says so rather than guessing.

macOS Keychain: the first agent-guard usage/status may pop a Keychain prompt — click Always Allow so it doesn't ask again. Background auto-refresh (from the hook/statusLine) stays off until that first foreground command succeeds, so you never get a surprise prompt mid-session.

Token safety: the OAuth token is only ever sent to Anthropic (*.anthropic.com over https) or loopback — even if AGENT_GUARD_USAGE_URL is set, an off-allowlist host is refused, so a poisoned env var can't exfiltrate it. Set AGENT_GUARD_NO_KEYCHAIN=1 to forbid Keychain reads.

🟢 Claude Code plan limits  ·  observed just now
  [██░░░░░░░░░░░░░░░░░░]  5-hour limit 12% used, resets 9:19 AM
  [███░░░░░░░░░░░░░░░░░]  weekly limit 17% used, resets Tue 7:59 PM, ~83% left over 5.0d (~17%/day vs ~14%/day budget)
  [░░░░░░░░░░░░░░░░░░░░]  weekly · Sonnet   1%

The weekly line spells out the daily budget — your weekly cap ÷ 7 (≈ 14%/day) — and how much runway you actually have, so a number like 17% (or even 60%) reads as "days left", not alarm.

Never a stale number. If the feed stops updating, agent-guard says so instead of quoting an old reading — a 10-hour-old "0%" is indistinguishable from a real 0% but is simply wrong. A snapshot older than 30 minutes renders as 🛡 ⚪ limits stale (…), is never graded into a warning level, and never fires a pacing nudge.

Alternative: the proxy

Anthropic also reports your standing on every response via anthropic-ratelimit-unified-* headers (5h + weekly only — no per-model). Run Claude Code through the proxy and agent-guard reads them in-flight:

agent-guard proxy                                    # meters Anthropic + reads limit headers
ANTHROPIC_BASE_URL=http://localhost:8787 claude

Once those headers are seen, the session is in subscription mode: alert-only. agent-guard never blocks a flat-fee plan (you already paid; Anthropic's own limit is the real wall) — instead it paces you. For each window it computes burn-rate vs. a sustainable pace (the daily budget = weekly cap ÷ 7 ≈ 14%/day) and projects whether you'll exhaust the window before it resets. Crucially the warning is pace-aware: 60% of the weekly cap with two days left is under the daily budget, so it stays quiet — it only warns when you're at or above the pace, or projected to lock out. The danger level is pace-gated the same way: 89% of the cap with 8 hours left, under pace, won't lock out, so it stays calm rather than screaming red — high utilization while under pace only happens near reset, where a lockout can't land (a real projected lockout still escalates regardless of pace). When it does fire, it says so in-session and via your alert channels:

🟥 Claude Code plan limits  ·  observed just now
  [████████████░░░░░░░░]  weekly limit 62% used, resets Sat 6:00 PM,
                          ~38% left over 5.4d (~7%/day vs ~14%/day budget),
                          burning 3.1× pace, → lockout in ~14h (5.1d before reset)

status shows it; the hook injects it into the session even when only the hook is running (it reads the snapshot the proxy persisted).

Without the proxy, real percentages are unknowable — Claude Code fetches them from Anthropic and never writes them to disk, and local cost does not map to Anthropic's internal rate-limit units (so we don't fake a "% of limit"). Instead, hook-only mode shows what's honestly knowable: your auto-detected plan tier (read from ~/.claude.json) plus absolute rolling cost — and points you at the proxy for the real numbers. Your tier needs no flag; --plan only overrides the auto-detection.

ks guard config --plan max5        # auto (detect) | pro | max5 | max20

Tune the thresholds (0–1 utilization) if the proxy's pacing is too eager:

| Setting | Meaning | Default | |---|---|---| | --plan (AGENT_GUARD_PLAN) | auto (detect from ~/.claude.json) or pin a tier | auto | | --weekly-soft / --weekly-danger | weekly warn / danger utilization | 0.6 / 0.85 | | --5h-soft / --5h-danger | 5-hour warn / danger utilization | 0.7 / 0.9 | | --burn-ratio | pace multiplier that triggers a warning | 1.5 |

Both the soft and danger thresholds are pace-gated: once a reset time is known, crossing either only escalates when you're at or ahead of the prorated daily budget (weekly ÷ 7), or projecting a lockout — so being deep into the week's quota with little time left doesn't cry wolf (89% with 8h left, under pace, stays calm). A genuine projected lockout still escalates regardless of pace.

The first time the proxy sees the unified-* headers it writes the raw values once to ~/.kill-switch/agent-guard/events.jsonl (kind: "unified-headers-observed") — so you can confirm Anthropic's exact value formats with a single cat. Only unified-* headers are captured (an explicit allowlist — never Authorization / x-api-key / cookies), values are length-capped, and the dump stays local. In auto mode the dollar-wall suppression trusts the upstream's headers; pin --plan if you'd rather it not depend on what the upstream reports.

Because subscription mode is alert-only, the "don't run both hook and proxy" caveat below doesn't bite here — running Claude Code through the proxy is exactly what feeds the limit headers, and dollars no longer gate anything.

Alerts

On the first soft/hard trip per scope, agent-guard:

  1. appends an event to ~/.kill-switch/agent-guard/events.jsonl (local audit trail),
  2. posts to Slack if KILL_SWITCH_SLACK_WEBHOOK (or config --slack-webhook) is set,
  3. reports to the Kill Switch dashboard if KILL_SWITCH_API_KEY is set, so agent kills sit alongside your cloud-account kills.

All network alerts are best-effort with a short timeout — a down endpoint never delays the agent.

Pricing

Built-in rates for current Claude and OpenAI models (USD/1M tokens), including Anthropic cache multipliers (cache write = input × 1.25, cache read = input × 0.10) — the buckets a context-replaying agent loop hits hardest. Unknown models fall back to premium Sonnet-class rates so the guard never under-counts. Override any model in ~/.kill-switch/agent-guard/pricing.json.

Commands

agent-guard install [--global] [--command <cmd>]   wire the Claude Code hook
agent-guard proxy   [--port 8787] [--flavor anthropic|openai] [--upstream URL]
agent-guard status  [--json]                        spend vs budget + plan limits
agent-guard config  [--session-hard N ...]          view/set caps
agent-guard config  [--plan max5 --weekly-soft 0.6 ...]   view/set plan limits
agent-guard reset   [--all|--limits|--today|--session <id>]  clear the ledger / subscription-limit state
agent-guard hook                                    (internal) Claude Code entrypoint

How it fails

By design, the hook fails open: any internal error → exit 0, the agent proceeds. A buggy guard must never brick your session. The proxy fails open too (on a metering error it still relays the response) but the budget check itself fails closed at the 402 wall.

MIT · part of Cloud Kill Switch