Skip to content

Repository files navigation

Nous Research Hermes mark

Resetwatch

Plans run out. This page tells you when.

Resetwatch is a Hermes Desktop plugin for remaining quota. Live bars for the plans you already signed into. A clock for when each one comes back. No chat has to be open.

POWERED BY HERMES AGENT  ·  COMMUNITY PLUGIN  ·  VERSION 0.2.18



See the cards  ·  Install it  ·  Where the numbers come from

Resetwatch live quota cards

Powered by Hermes

Resetwatch is a community plugin for Hermes Desktop. It uses the Hermes plugin SDK and the same desktop you already run. Stock Hermes. No fork, no extra server, no build step.

Copy two files and open the page.

What's left, on one page

Most usage pages live on a vendor site you have to remember to open. Resetwatch puts the bars in Hermes.

Live cards
Nous, Claude, Codex, Cursor, and the rest fill themselves from logins already on this machine. Each card is one window: how full it is, how much is left, and when it resets.
Plan names
Claude shows Pro, Max, Max 5x, or Max 20x. Codex shows Plus. Cursor shows Ultra, or whatever that app is on. Kimi shows Advanced. GLM shows Lite, Pro, or Max. Nous shows the portal plan, not a bare Plus.
Manual clocks
Gemini, Perplexity, or anything you type. Paste the percent left and the reset time from the vendor page. Open takes you there in the system browser.
A full page
Sidebar, palette ("Resetwatch: Open"), or Ctrl/Cmd+Alt+R. Not a HUD, not a chip, not a side pane. Click a section name to fold it. They start open, and they remember.

It does not scrape vendor websites. Live rows come from Hermes OAuth plus the same CLI and app logins those vendors already use. Nothing leaves this machine except the usage calls those apps already make for you.

Leave it open

  • Live cards refresh every 5 minutes while the page is open.
  • Probe results are cached for 5 minutes. Refresh skips that cache, with a one-minute floor so repeated clicks do not hammer vendor APIs.
  • If a login exists but the vendor call fails (HTTP error, timeout, changed payload), the card stays on the page marked "unavailable" with the reason. A vendor you never signed into shows nothing.
  • Claude and Codex pool accounts share one fold per vendor. Each account has its own rate-limit backoff.
  • Codex extra limits like Spark show up when that account has them.
  • Vendor fetches run in parallel with a time budget, so one slow API cannot wipe the page.
  • Tokens never go to stdout.

Open Providers and order to turn individual providers off or move them up and down. Disabled providers are hidden and skipped by future fetches; an already-running refresh may finish. The controls also list providers with no current login, so you can enable them later. Reset providers restores all providers and the original order. Manual clocks are unaffected.

These preferences are saved in this Desktop installation and apply across its connections and profiles. Changing order does not fetch again. Changing the enabled providers starts a query for that selection; cached results from a different selection are not reused. While any provider is disabled, Resetwatch uses individual probe fetchers instead of the gateway's broad account.usage and /usage calls, which cannot guarantee skipping a provider. Gateway-only providers outside the probe's supported list are unavailable in this mode. Nous still uses its own usage RPCs when enabled.

Update both Desktop plugin.js and the selected gateway's probe.py to use provider filtering. For direct probe calls, pass --disabled-providers=cursor,kimi (comma-separated provider IDs).

Want another live row? Open an issue. We can add it if that app or CLI already has a remaining-quota path we can read on your machine.

Works with the logins you already have

Live cards fill on their own when that login is already on the machine:

  • Nous Portal: Hermes
  • Claude: every Hermes OAuth account in the credential pool, or Claude Code
  • Codex: every Hermes OAuth account in the credential pool, or the Codex CLI
  • OpenRouter: Hermes
  • Cursor: Cursor app or cursor-agent
  • Kimi: Kimi Code CLI, or KIMI_CODING_API_KEY / KIMI_API_KEY in Hermes env (Coding Plan)
  • Grok: Grok CLI
  • GLM: ZCode Coding Plan, or ZAI_API_KEY / GLM_API_KEY in Hermes env (includes peak / off-peak pricing)
  • DeepSeek: DEEPSEEK_API_KEY in Hermes env (balance plus peak / off-peak). Funded USD and CNY balances appear separately with their own top-up and granted amounts. An empty USD row does not hide CNY funds; currencies are never added or compared by amount. Peak pricing is Monday-Friday, 01:00-04:00 and 06:00-10:00 UTC. All other hours, including weekends, are off-peak at half price. Official schedule.
  • OpenCode Go: OPENCODE_GO_API_KEY in Hermes env (5h, weekly, monthly)
  • Ollama Cloud: OLLAMA_API_KEY in Hermes env (5h / weekly; no exact reset time from the API)
  • MiniMax: MINIMAX_API_KEY (or MINIMAX_CN_API_KEY) in Hermes env (Token Plan 5h / weekly)
  • Novita: NOVITA_API_KEY in Hermes env (dollar balance)
  • DeepInfra: DEEPINFRA_API_KEY in Hermes env (prepaid balance)
  • AI Gateway: AI_GATEWAY_API_KEY in Hermes env (Vercel credits)
  • Command Code: COMMANDCODE_API_KEY in Hermes env, or the cmd CLI login (credits, 5-hour / weekly windows, plan, and this period's spend)

Gemini, Perplexity, and anything else can be a manual clock. Type the percent left and the reset time.

Make it yours

Install

Copy plugin.js and probe.py into the Hermes desktop plugin folder:

~/.hermes/desktop-plugins/resetwatch/

On Windows:

%LOCALAPPDATA%\hermes\desktop-plugins\resetwatch\

Open Hermes and choose Resetwatch in the sidebar. If it is missing, use Cmd+K (Ctrl+K on Windows) then Reload desktop plugins. The desktop picks the files up within seconds and reloads on every save.

Copy both files. Live rows need probe.py for CLI and app logins Hermes does not OAuth itself.

Where the numbers come from

Your Hermes Desktop  →  gateway RPCs and probe.py  →  the same usage APIs those apps already call
  • Nous. Dollars and renewal time come from the gateway (usage.bars, then subscription.state if needed).
  • Gateway accounts. If Hermes has account.usage, that RPC fills Claude, Codex, OpenRouter, and any other providers it already knows.
  • Stock Hermes. probe.py fills the rest through shell.exec. Claude and Codex also read every anthropic / openai-codex row in $HERMES_HOME/auth.json (read only) and show one labelled card set per account.
  • CLI fallback. If Hermes OAuth is missing, Claude Code (~/.claude) and Codex CLI (~/.codex) fill those cards. Cursor, Kimi, Grok, and GLM come from those apps first.
  • Env keys. If Kimi or GLM CLI login is missing, Hermes env keys fill the same cards. DeepSeek, OpenCode Go, Ollama Cloud, MiniMax, Novita, DeepInfra, and AI Gateway always use Hermes env (process env or $HERMES_HOME/.env). Command Code uses Hermes env first, then ~/.commandcode/auth.json.
  • Last resort. Older /usage output is still parsed when a session is focused.

Manual clocks are whatever you typed. They do not refresh themselves.

How it talks to vendors

Live data goes through the desktop plugin SDK (host.request JSON-RPC), plus probe.py through shell.exec when a signed-in CLI or app has quota the gateway does not expose. The page does not log into vendor sites.

probe.py does not refresh Claude or Codex credentials. For Kimi and Grok it may refresh on 401 and write that vendor's file back. Before writing it re-reads the file and merges token fields into that fresh record so concurrent CLI edits to other keys are kept. That protects the file. It does not make a shared refresh-token exchange safe if the CLI refreshes in the same window.

Heads up on Kimi and Grok. Those vendors rotate refresh tokens. If Resetwatch and the CLI both refresh close together, one of them can get signed out and you will need to log into that CLI again. It is rare, it is harmless, and when Resetwatch did refresh a token the card says so. If you would rather it never happen, run the CLI once so its token is fresh before opening the page.

It may also write a small cache under $HERMES_HOME/cache/resetwatch. Incomplete timed-out runs and empty runs are not cached.

Compatibility

Resetwatch uses the desktop plugin SDK and the standard Hermes gateway methods. It is one uncompiled plugin.js plus probe.py. No package manager.

It runs on Windows, Mac, and Linux with stock Hermes Desktop. Interpreter discovery runs on the selected gateway. The probe checks that backend's HERMES_PYTHON and VIRTUAL_ENV; on Linux it can also discover the running gateway's Python through its process ancestors, including system-wide and custom venv installs outside the Hermes home. It keeps the venv path instead of resolving its Python symlink to the system binary. Home-relative and PATH interpreters remain fallbacks when runtime discovery is unavailable. Desktop-local environment paths are not used for remote discovery.

Missing-httpx failures are never cached. Old cached dependency failures are ignored automatically, including when using Refresh, so switching to a working interpreter does not require deleting cache files. Update both plugin.js and probe.py on the appropriate Desktop and gateway installations to use runtime discovery.

Live cards follow the focused session's Desktop connection and profile. With no focused session, they use the active profile. Remote profile aliases use the backend profile name. The plugin can live in the base home or a profile home, and profiles can share the base home's Python install.

When a profile is selected, its Hermes credentials and cache stay separate from other profiles. If the gateway is running under a different home, the probe reads API keys from the selected profile's .env. CLI and app logins such as Claude Code and Cursor are still shared when those apps use one login for the whole machine. Older Desktop versions without profile routing keep the normal gateway path; an unknown session owner shows an error instead of another account's cards.

Contributing

Contributions are welcome. Open an issue first for anything bigger than a small fix so we can agree on the shape before you spend time on it.

Run the profile tests with Python and Node.js. No packages need to be installed:

python -m unittest test_profile_switch test_probe_runtime test_provider_controls
node --test test_profile_routing.cjs

The tests use temporary homes and fake credentials. Vendor access is blocked, including when a probe cache is missing. On Linux, the routing suite also launches a fixture gateway in a custom venv to exercise UI interpreter discovery with system Python and a stale dependency cache. CI runs it against both standalone and catalog packages.

The full suite, python -m unittest discover, also requires httpx==0.28.1 in the test environment for vendor response fixtures.

License

MIT


Resetwatch
Know what's left. Know when it comes back.

Community project

Resetwatch is an independent community plugin. It is not affiliated with, endorsed by, sponsored by, or officially associated with Nous Research or the Hermes Agent project. Hermes, Hermes Agent, and Nous Research are names and marks belonging to their respective owners.

Standalone Desktop signed updates and recovery

At the bottom of Resetwatch, choose Check for updates. The plugin checks its own GitHub releases and asks before installing. Update now downloads the offered version; Later leaves the installation unchanged. Checking alone downloads only release metadata.

Every update has an ECDSA P-256 signature verified against the public key embedded in the plugin. The signed metadata binds the repository, plugin identity, version, exact commit, file list, sizes, and SHA-256 hashes. Unsigned releases, changed downloads, and automatic downgrades are rejected. A signature verifies origin and integrity, not the absence of bugs.

Resetwatch updates its existing plugin.js and probe.py together. Both files are verified and staged before replacement, and the helper is replaced before the plugin reloads. No new Python component is added. All file operations use stock Desktop APIs on the local Desktop profile, even when the gateway is remote. Saved settings are preserved. Both hermes-resetwatch and resetwatch install folders are recognized. Keep only one copy installed.

Restore previous version verifies the last complete backup and asks before restoring. Choose Restore now or Cancel. Updating or restoring reloads the plugin, so finish active work first. Terminal connections may close. Use Reload desktop plugins or restart Desktop if the screen does not refresh.

Backups remain beside the installed files as update-<id>-backup-<filename>. Failed replacements attempt to restore every original file. Desktop does not expose an atomic multi-file replacement: a crash between renames can require manual recovery. Close Desktop, move any replaced files aside, restore all files from the same backup ID to their original names, then reopen Desktop. For example, update-<id>-backup-plugin.js becomes plugin.js. Restore probe.py from that same backup too.

Existing installations need one manual installation of this updater-enabled version. Later versions can use the confirmation flow above. Hermes Agent source changes are not required.

Publishing updates

The release description must contain a signed hermes-desktop-update block using schema 2. Publish a stable tag v<VERSION> against the exact pushed commit named in the signature. This plugin accepts only Adolanium/hermes-resetwatch, plugin ID resetwatch, and plugin.js plus probe.py. Signing is a maintainer operation; the private signing key must stay outside the repository and never ship to users.

Maintainer signing procedure

Update VERSION, test, commit, and push. Save this script outside the repository as sign-release.mjs and run node /path/to/sign-release.mjs FULL_COMMIT_SHA from the repository. It prints the path of the signed release notes. Publish with gh release create vVERSION --target FULL_COMMIT_SHA --notes-file NOTES_PATH. Keep the signed block unchanged when adding notes. Only maintainers need Node.js and Git.

The private key is read from HERMES_PLUGIN_SIGNING_KEY, or the maintainer's ~/.hermes-ssh-release/signing-key.pem. This is the existing family signing identity; signatures also bind each release to its own repository. Back up the key securely. Key rotation needs a release signed by the previous key or a manual reinstall.

import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import crypto from 'node:crypto';
import { execFileSync } from 'node:child_process';

const commit = process.argv[2];
if (!/^[a-f0-9]{40}$/.test(commit || '')) throw Error('Use a full pushed commit SHA.');
const source = execFileSync('git', ['show', `${commit}:plugin.js`]).toString('utf8');
const plugin = source.match(/const PLUGIN_ID\s*=\s*['"]([^'"]+)['"]/)?.[1];
const version = source.match(/const VERSION\s*=\s*['"]([^'"]+)['"]/)?.[1];
const repo = source.match(/repo: "(Adolanium\/[^"]+)"/)?.[1];
const names = JSON.parse(source.match(/files: (\[[^\]]+\])/)[1]);
const pinned = source.match(/const UPDATE_KEY = "([^"]+)"/)?.[1];
if (!plugin || !/^\d+\.\d+\.\d+$/.test(version) || !repo ||
    names.some(name => !['plugin.js', 'probe.py'].includes(name))) throw Error('Invalid updater configuration.');
const origin = execFileSync('git', ['remote', 'get-url', 'origin'], { encoding: 'utf8' }).trim().replace(/\.git$/, '');
if (origin !== `https://github.com/${repo}` && origin !== `git@github.com:${repo}`) throw Error('Repository does not match origin.');
const key = fs.readFileSync(process.env.HERMES_PLUGIN_SIGNING_KEY || path.join(os.homedir(), '.hermes-ssh-release', 'signing-key.pem'));
if (crypto.createPublicKey(key).export({ type: 'spki', format: 'der' }).toString('base64') !== pinned) throw Error('Signing key does not match the plugin.');
const files = names.map(name => {
  const content = execFileSync('git', ['show', `${commit}:${name}`]);
  if (!content.length || content.length > 500000) throw Error('Release file exceeds updater limits.');
  return { name, sha256: crypto.createHash('sha256').update(content).digest('hex'), bytes: content.length };
});
const payload = Buffer.from(JSON.stringify({ schema: 2, plugin, repo, version, commit, files }));
const signature = crypto.sign('sha256', payload, { key, dsaEncoding: 'ieee-p1363' });
const envelope = { payload: payload.toString('base64'), signature: signature.toString('base64') };
const output = path.join(os.tmpdir(), repo.split('/')[1] + '-release-notes.md');
fs.writeFileSync(output, `${repo.split('/')[1]} v${version}\n\nSigned updates and backup recovery, with confirmation before each change.\n\n\`\`\`hermes-desktop-update\n${JSON.stringify(envelope)}\n\`\`\`\n`);
console.log(output);

Catalog package

The catalog/ directory packages this Desktop plugin for the Hermes plugin catalog, using the combined package layout. The catalog uses reviewed commit pins. A new repository release becomes available through catalog updates after its pin update is accepted upstream.

To install the package directly from the repository:

hermes plugins install Adolanium/hermes-resetwatch/catalog

Restart Hermes Desktop or rescan plugins, then enable the Desktop component in Capabilities > Plugins. This package adds no Agent tools, hooks, or middleware. It requires Hermes Desktop with combined-package support. On a remote backend, the Desktop component must also be installed on the machine running the app.

The existing root plugin.js remains the standalone distribution. Keep one installation per Desktop plugin. Before switching from a manual install, back up and move its folder out of the Desktop plugin directory; Hermes intentionally does not overwrite manual installations. Keep plugin settings when migrating.

For catalog installations, use hermes plugins update hermes-resetwatch and rescan Desktop plugins to adopt a reviewed update. The packaged copy has no in-app update or restore controls. Its release downloader, signature verifier, backup/restore updater, and code-replacement helpers are removed at build time. Standalone signed updates continue to use the existing root files.

For development, edit the root files, then run python scripts/build_catalog.py. Commit the resulting catalog/ files. CI runs python scripts/build_catalog.py --check to keep the package current, including any companion files. Catalog packaging releases use catalog-v0.2.18 and are not marked as the latest standalone release.

The catalog probe is read-only for all login credentials: it does not exchange refresh tokens, save login files, invoke Hermes OAuth resolvers, or launch Cursor CLI commands. Expired Kimi/Grok logins ask you to sign in using the vendor CLI. Usage and rate-limit caches may still be written. Private usage APIs remain best-effort.

About

How much of each plan is left, and when it comes back. A Hermes Desktop plugin.

Resources

Stars

70 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages