Hermes Credential Pools (Multi-Key Failover & Free-Tier Stacking)
Hermes can hold multiple API keys for the same provider and automatically rotate to the next healthy key when one hits a rate limit or quota. This is the mechanism behind "use N accounts, switch when one hits its cap". It is distinct from fallback providers (cross-provider failover, hermes fallback) — pools are tried first; only when all pool keys are exhausted does the fallback chain activate.
When to Use
- User wants rate-limit resilience on a paid provider (several OpenRouter/Anthropic keys).
- User wants to stack multiple free-tier accounts on one provider (e.g. OpenCode Zen free models).
- Diagnosing why rotation is/isn't happening, or why a key is stuck in cooldown.
Note: the bundled
hermes-agentskill'sreferences/providers-and-models.mdmentions pools in one line only. This skill is the operational deep-dive — prefer this one for pool questions.
Key Commands
hermes auth add <provider> --api-key <KEY> # add a key to the pool (repeatable)
hermes auth add <provider> # interactive wizard (asks api-key vs oauth)
hermes auth list # all pools; ← marks the selected credential
hermes auth list <provider> # one provider's pool
hermes auth remove <provider> <index> # 1-based index
hermes auth reset <provider> # clear all cooldowns/exhaustion flags
hermes auth # interactive wizard (add/remove/reset/strategy)
No cap on the number of keys per pool. Env-var keys (OPENROUTER_API_KEY etc.) are auto-seeded as pool entries and auto-pruned if the env var disappears; keys added via hermes auth add are persisted in auth.json under credential_pool and never auto-pruned.
Rotation Behavior (verified against agent/credential_pool.py + official docs)
| Error | Behavior | Cooldown |
|---|---|---|
| 429 rate limit | Retry same key once (transient); second consecutive 429 rotates to next key | 1 hour |
| 402 billing/quota | Rotate immediately | 24 hours |
| Plan/usage limit message (e.g. "usage limit reached") | Rotate immediately — no retry, the cap won't clear | — |
| 401 auth expired | Try OAuth token refresh first; rotate only if refresh fails | — |
| All keys exhausted | Fall through to fallback_providers chain if configured |
— |
Rotation strategies (set via interactive hermes auth wizard or credential_pool_strategies: in config.yaml):
| Strategy | Behavior |
|---|---|
fill_first (default) |
Use first healthy key until exhausted, then next — the natural "one account at a time" mode |
round_robin |
Cycle evenly after each selection |
least_used |
Lowest request count wins |
random |
Random among healthy keys |
For "use account 1 until it caps, then account 2", the default fill_first is exactly right — no config change needed.
Delegation: delegate_task children automatically share the parent's pool (same provider) with per-task credential leasing — subagents get the same rate-limit resilience for free.
Pitfalls
- Rotation resets the provider-side prompt cache. Caches are scoped per account/key, so after rotating, the next request re-reads the whole conversation at undiscounted input price. On long sessions with frequent rotation this is real money. Exception: free models — when input/output/cached-read are all $0 (e.g. OpenCode Zen free tier), rotation costs nothing. Always check the model's pricing table before promising "costless rotation".
- Pool rotation vs provider fallback semantics: provider-level fallback is turn-scoped (primary restored each user message; fallback fires at most once per turn). Pool rotation is NOT turn-scoped — an exhausted key stays in cooldown (1h/24h) and the pool keeps using the next key until cooldown clears or
hermes auth resetis run. - Don't tell users to put pool config in
.env— strategies belong inconfig.yaml(credential_pool_strategies:), keys are added viahermes auth add(manual entries persist inauth.json). - OpenCode Go uses a weekly usage-limit scheme ("Resets in Xh Ym" format is handled in the pool source) — cooldown expectations differ from daily-reset providers.
- Free-tier stacking math: the per-account cap multiplies with account count (10 accounts ≈ 10× daily cap), but agent work burns many requests per user turn (each tool call = ~1 request), so realistic throughput is dozens of agent tasks/day, not hundreds of chats. Set expectations with real numbers.
- Free models are usually time-limited promotions — verify the model still exists in the provider's current model list before promising a durable setup.
Provider Quota Knowledge Bank
Provider-specific free-tier/limit mechanics verified in sessions live in references/:
references/opencode-zen-free-tier.md— OpenCode Zen free models: IDs, endpoints, per-account request cap, rotation cost analysis for stacking accounts.
Verification
hermes auth listshows all intended credentials under the provider.- Send one real request with the target model; confirm response and no auth errors.
- (Optional) confirm rotation by checking
~/.hermes/auth.jsoncredential_poolforlast_status/request_countmovement, orhermes auth reset <provider>to clear cooldowns between tests.