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

@usagefleet/cli

v1.2.101

Published

Tails Claude Code, Claude Desktop, and pi agent JSONL logs and reports token usage to a UsageFleet server.

Readme

@usagefleet/cli

The UsageFleet collector. It tails the local logs of your Claude agents and reports usage to usagefleet.com, where it's split across your device groups. Read-only on the log files, zero runtime dependencies, Node ≥ 20.

Install

Get a device token from the Devices page, then, on that machine:

npm i -g @usagefleet/cli
usagefleet login uf_xxx

Same two commands on macOS, Linux and Windows (in PowerShell chain them with ; — 5.1 has no &&). login stores the token (the server checks it on the first report, not at login), sets the collector to start with your session and writes ~/.config/usagefleet/config.json (mode 600). The dashboard fills in within a minute.

login takes the token and nothing else. The collector reports to usagefleet.com and there is no way to redirect it: the request carries your device token and a log of what this machine is working on.

If npm i -g fails with EACCES your global prefix is root-owned: use a Node version manager (nvm, fnm, volta) or npm config set prefix ~/.local with ~/.local/bin on your PATH. Don't install under sudo — the collector would run as the wrong user.

Commands

usagefleet status         # service health, last limits reading, resolved config
usagefleet run            # one scan: upload usage + report limits
usagefleet watch          # poll continuously (what the service runs)
usagefleet limits         # report ONLY your real 5h/weekly limit usage
usagefleet guard          # exit 2 if this device's group is over a blocking limit
usagefleet notify-test    # fire a sample desktop notification
usagefleet update         # upgrade now (it also self-updates every 6h)
usagefleet config         # config file location + every env override
usagefleet login <token>  # pair this device + (re)install the service, idempotent
usagefleet uninstall      # remove it
usagefleet completion zsh # print a shell completion script (zsh, fish)

login sets up completions for you, for each shell you actually use — zsh gets ~/.zsh/completions/_usagefleet plus an fpath block appended to .zshrc, fish gets ~/.config/fish/completions/usagefleet.fish. Restart the shell once. uninstall removes both again, and self-update keeps them current.

completion stays for piping a script somewhere else yourself.

What it collects

  • Token usage — Claude Code (~/.claude/projects/**/*.jsonl), Claude Desktop agent-mode (Cowork) sessions, and the pi agent (~/.pi/agent/sessions, Anthropic-provider records only; other providers don't touch Claude limits). A per-file byte offset in the config file means each line is sent once; rotation and truncation are handled and partial lines are never sent. Delivery is at-least-once — the server dedups on uuid.
  • Your real limit % — the collector uses the Claude login already on the machine (subscription OAuth from claude: macOS login Keychain, elsewhere <config dir>/.credentials.json; falling back to ANTHROPIC_API_KEY) and reads the same 5h/weekly percentages Claude's own /usage screen shows — from the free OAuth usage endpoint for subscriptions, or a 1-token Messages ping for API keys. Credentials never leave the machine — only the percentages do. usagefleet status shows which login was found.

Uploaded per record: token counts, model, session id, hostname, working directory, git branch. Prompts, responses and file contents are never read.

Desktop notifications

The first time a window crosses a threshold (default 80 and 95) you get a desktop notification — once per threshold per window, re-armed when the window resets. macOS uses osascript, Linux notify-send (falling back to kdialog --passivepopup; install libnotify-bin if neither exists), Windows a WinRT toast via powershell.exe.

usagefleet notify-test confirms it works. Tune with USAGEFLEET_NOTIFY_THRESHOLDS="50,80,95", disable with USAGEFLEET_NOTIFY=0.

Blocking prompts over the limit

A group can be set to refuse new prompts once it has burned its budget slice (1/N of the account limit) for a window — a switch per window on the Groups page, both off by default. Each device also has its own blocking toggle on the Devices page: switched off, that machine is never refused, whatever its group says. usagefleet login registers a Claude Code UserPromptSubmit hook in ~/.claude/settings.json (removed by uninstall, refreshed rather than stacked on re-install, and skipped entirely with USAGEFLEET_HOOK=0):

{
  "hooks": {
    "UserPromptSubmit": [
      { "hooks": [{ "type": "command", "command": "usagefleet guard" }] }
    ]
  }
}

If the pi coding agent is on the machine (~/.pi/agent exists), login also writes a pi extension — ~/.pi/agent/extensions/usagefleet-guard.ts — that runs the same guard before every pi prompt. Same lifecycle: refreshed on re-install, removed by uninstall, skipped with USAGEFLEET_HOOK=0.

If USAGEFLEET_CONFIG was set when you logged in, the installed command carries it (USAGEFLEET_CONFIG=<path> usagefleet guard, or set "..." && ... on Windows). That is what binds the hook to the right store, and so to the right Anthropic account — see "Two Claude accounts on one machine" below.

guard fails open everywhere else — no config, server down, timeout (5s), old server, 429 — because a tracker problem must never stop you working. Only whole prompts are blocked, never tool calls mid-turn, so the current turn always finishes.

Configuration

~/.config/usagefleet/config.json (honours XDG_CONFIG_HOME) holds everything the CLI persists: your settings plus two machine-managed sections, state (tail offsets) and notify (which thresholds already fired). Delete it to start clean. Re-running login merges, so rotating a token doesn't reset offsets.

Every knob is a top-level key in that file, and the matching env var overrides it (usagefleet config prints this same table):

| File key | Env override | Meaning | |----------|--------------|---------| | token | USAGEFLEET_TOKEN | device token | | projectsDir | USAGEFLEET_PROJECTS | override ~/.claude/projects | | desktopDir | USAGEFLEET_DESKTOP | override the Claude Desktop sessions dir; off to skip it | | piDir | USAGEFLEET_PI | pi sessions dirs — string or array in the file, comma-separated in env; off to skip | | interval | USAGEFLEET_INTERVAL | watch poll seconds (default 15) | | limitsInterval | USAGEFLEET_LIMITS_INTERVAL | seconds between limit reports (default 60; 300 on API keys, where each report costs a 1-token ping) | | notifications | USAGEFLEET_NOTIFY | desktop notifications, on by default (false/0 disables) | | notifyThresholds | USAGEFLEET_NOTIFY_THRESHOLDS | utilization % that trigger an alert — array in the file, comma list in env (default 80,95) | | batch | USAGEFLEET_BATCH | records per upload (default 100, server caps at 1000) | | update | USAGEFLEET_UPDATE | false/0 turns the self-update check off | | updateInterval | USAGEFLEET_UPDATE_INTERVAL | seconds between update checks (default 21600 = 6h) | | hook | USAGEFLEET_HOOK | false/0 keeps the prompt-blocking guard out of Claude Code and pi | | — | USAGEFLEET_CONFIG | override the config file path (env only — it locates the file) | | — | CLAUDE_CONFIG_DIR | Claude Code's own knob: which login to watch (default ~/.claude) |

When run as a service, login bakes every USAGEFLEET_* value currently set (plus ANTHROPIC_API_KEY and CLAUDE_CONFIG_DIR) into the launchd/systemd unit, written mode 600.

Two Claude accounts on one machine

One collector watches one login. To report a second subscription from the same machine, run a second collector against Claude Code's other config dir, with its own device token and its own state:

CLAUDE_CONFIG_DIR=~/.claude-work \
  USAGEFLEET_CONFIG=~/.config/usagefleet/work.json \
  USAGEFLEET_PROJECTS=~/.claude-work/projects \
  usagefleet login uf_...

Each reports its own account, and the dashboard keeps their limits apart. The prompt guard follows: because USAGEFLEET_CONFIG was set for this login, the hook written into ~/.claude-work/settings.json carries it, so that account's guard reads that account's token and blocks against the right subscription. With a relocated config dir the macOS Keychain is skipped on purpose: that item belongs to the default login.

Only one of them can run as the background service. The launchd label, systemd unit and Scheduled Task name are fixed, so the second login rewrites the first one's service definition rather than adding a second. Run the extra collector yourself with the same env — ... usagefleet watch, under your own unit or terminal — and keep login for the account you want supervised.

Background service

login is idempotent and reload-safe: re-running it rewrites the service definition and restarts it, so it doubles as the update step. It launches an absolute node plus the installed package path, so an empty service PATH is fine — but removing that Node version (nvm uninstall) stops the collector until you re-run usagefleet login under the new one.

  • macOS — a LaunchAgent (~/Library/LaunchAgents, RunAtLoad + KeepAlive), booted immediately. Logs in ~/Library/Logs/usagefleet/. Plist is mode 600: it holds your token.
  • Linux — a systemd --user unit, plus loginctl enable-linger $USER so it survives logout. If systemctl can't be driven it prints the manual steps.
  • Windows — a Scheduled Task (usagefleet) starting at logon, restarting on failure, running hidden through a wscript launcher in %LOCALAPPDATA%\usagefleet (which carries the env values set at install time). Log: %LOCALAPPDATA%\usagefleet\usagefleet.log. Inspect with schtasks /query /tn usagefleet /v /fo list.

macOS limits under the service. Usage collection works headless. Reading the login Keychain for the real limit % may be denied to a non-interactive agent — the collector logs a clear hint. Either approve /usr/bin/security access to the Claude Code-credentials item once, or set ANTHROPIC_API_KEY before usagefleet login so limits use the API key.

Updates

watch checks the npm registry at startup and every 6 hours; on a new version it runs npm install -g @usagefleet/cli@<version> and re-runs login to restart the service on it. usagefleet update does the same on demand. npm is called through the absolute path next to the running node, because a launchd/systemd service gets a minimal PATH.

Every failure is a no-op — registry unreachable, non-semver version, npm missing or exiting non-zero, local dev builds — and the service is only restarted after npm reports success.

From source

cd apps/cli
bun install
bun run src/index.ts status   # or: npm run build && node dist/index.js status