Hermes Agent Deep Cuts: Your Rate Limit Has a Scriptable Interface
$ hermes usage --json (selected fields, reset timestamps omitted)
{
"provider": "openai-codex",
"source": "usage_api",
"title": "Account limits",
"plan": "Plus",
"windows": [
{"label": "Session", "used_percent": 0.0},
{"label": "Weekly", "used_percent": 7.0}
],
"details": ["You have 1 reset banked - use /usage reset to activate"],
"unavailable_reason": null
}
That command made no model call. It resolved this CLI’s configured provider, read its existing credentials, fetched account-side quota data, and exited. The interesting part is the shape of the failure: if that provider cannot supply an account snapshot, Hermes exits 1. That makes hermes usage a useful primitive for an operator script, provided you treat unavailable data as unavailable, not as an empty budget.
It asks the provider, not the session database
hermes insights totals usage recorded in Hermes sessions. hermes usage asks the configured provider for the limits attached to its account. Those are different ledgers. A session report can tell you what Hermes recorded; this command can tell you what the provider says remains.
The implementation in agent/account_usage.py normalizes provider responses into an AccountUsageSnapshot: provider, source, timestamp, optional plan, windows, details, and an unavailable reason. Provider adapters then fetch the relevant remote endpoint. The current built-in adapters cover Codex OAuth, Anthropic OAuth, and OpenRouter. Other registered provider profiles may implement a usage hook.
The Codex path is more than a GET with a bearer token. It resolves the active runtime credential, including credential-pool credentials, then requests the quota endpoint. A 401 triggers one forced refresh and retry. Window names use the response’s duration when present, because the weekly-only response can occupy the field normally used for the session window. That is a small but important distinction: positional fields are not a reliable quota label.
hermes usage --json serializes the normalized snapshot. It does not print provider response headers or credentials, and its stable fields include source and fetched_at. Read those before interpreting percentages. A provider’s credit balance, an API-key cap, and a rolling rate-limit window are not interchangeable quantities.
Put the exit code in charge
The command takes an optional provider override. Use the name Hermes recognizes, and check the exact installed CLI with hermes usage --help before wiring new providers into automation.
hermes usage --json > usage.json
status=$?
if [ "$status" -ne 0 ]; then
printf '%s\n' "Provider usage is unavailable; do not infer remaining quota" >&2
exit "$status"
fi
jq -e '.unavailable_reason == null and (.windows | length > 0)' usage.json >/dev/null
jq -r '.provider, (.windows[] | [.label, .used_percent, .resets_at] | @tsv)' usage.json
That check deliberately fails closed if there is no usable window. Some providers can return a snapshot with an unavailable reason, and a successful process exit alone should not be your policy decision. Check both the process status and the document fields. The source field lets logs distinguish a provider’s credits endpoint from a quota endpoint without parsing the human-readable display.
To query a different supported account, pass its provider explicitly:
hermes usage --provider openrouter --json
This does not switch the model Hermes will use, and it does not test whether that provider can answer a prompt. It selects the usage adapter and resolves credentials for that provider. Do not interpret an account-limit response as a live inference health check.
The failure that looks like a zero
A provider may have no account-usage endpoint, the matching credential may be absent, or a request may fail. For that case, the CLI prints an explanatory message to stderr and returns status 1. In this run, an intentionally invalid provider produced:
No account usage available for provider 'definitely-not-a-provider': no credential is configured for it, the provider has no usage endpoint, or the fetch failed.
The message intentionally groups several causes. It is not a detailed diagnosis, and the JSON mode does not turn a missing snapshot into a valid all-zero document. In a shell pipeline, capture the command’s status before jq runs, or a later successful command can hide the failure. A pipefail-aware variant is:
set -o pipefail
hermes usage --json | jq -e '.windows | length > 0'
For scheduled jobs, keep the raw JSON and stderr separately if you need to distinguish transport failure from unsupported provider behavior. Avoid tight polling: this is an account endpoint request, not a local counter. The built-in network calls have provider-specific timeouts, and the plugin usage hook is bounded separately.
Verify the account you meant to query
Run the help command first, then compare the provider field in the result with the intended account. Check source, fetched_at, and each window’s reset timestamp. If the output exits zero but contains no windows, do not convert that into a green quota check. If it exits one, the quota is unknown, not zero and not unlimited.
hermes usage --help
hermes usage --json | jq '{provider, source, fetched_at, plan, windows, unavailable_reason}'
The docs describe hermes usage as the account rate-limit view without starting an agent session. The source makes the operational contract sharper: it is a small provider adapter pipeline with credential resolution and a deliberately coarse unavailable path. Put it in monitoring only when your alert distinguishes “quota low” from “could not read quota.”
Sources
- Hermes Agent, CLI Commands Reference:
hermes usage - Hermes Agent source,
hermes_cli/subcommands/usage.py - Hermes Agent source,
agent/account_usage.py - Live CLI output on the authoring host, Hermes profile
blogposter, 2026-10-01:hermes usage --jsonandhermes usage --provider definitely-not-a-provider --json