All plugins

cliproxyapi-provider

CLIProxyAPI as native Hermes model providers: discovers each CPA provider group (Claude, Codex, xAI, Gemini, Kiro and others) and registers one profile per group on the wire its CPA executor accepts (Anthropic Messages, Responses or Chat Completions), with context windows and reasoning levels from CPA. Disclosure — sends model-list and inference requests, authenticated with the API key env var you name, to the CPA base_url you configure; with an optional management key it also makes bounded read-only GETs to CPA's management API; with an optional billing route it sends inference, and a model-list GET, to the gateway URL you configure, authenticated with the gateway key env var you name. Known limit: Hermes strips from agent subprocesses only the key env vars a registered provider declares, so the management key env var, and on a routed instance the CPA key env var, stay readable by agent shells. Writes its model cache under $HERMES_HOME/cache/cliproxyapi/, plus lock files and a rejected-key marker (salted HMAC, never a key) under $HERMES_HOME/cache/cliproxyapi/locks/.

duu2614Modelsv0.7.3Updated 55 minutes ago

About

CLIProxyAPI as native Hermes model providers: discovers each CPA provider group (Claude, Codex, xAI, Gemini, Kiro and others) and registers one profile per group on the wire its CPA executor accepts (Anthropic Messages, Responses or Chat Completions), with context windows and reasoning levels from CPA. Disclosure — sends model-list and inference requests, authenticated with the API key env var you name, to the CPA base_url you configure; with an optional management key it also makes bounded read-only GETs to CPA's management API; with an optional billing route it sends inference, and a model-list GET, to the gateway URL you configure, authenticated with the gateway key env var you name. Known limit: Hermes strips from agent subprocesses only the key env vars a registered provider declares, so the management key env var, and on a routed instance the CPA key env var, stay readable by agent shells. Writes its model cache under $HERMES_HOME/cache/cliproxyapi/, plus lock files and a rejected-key marker (salted HMAC, never a key) under $HERMES_HOME/cache/cliproxyapi/locks/.

hermes-cliproxyapi-provider

English | Tiếng Việt | 简体中文

Hermes Agent plugins for
CLIProxyAPI (CPA): a
model-provider, and a companion /cpa
chat command for pool health and live quota.

CPA is a gateway: one instance fronts many providers (Claude, Codex, Gemini,
xAI, Kimi, Devin, OpenAI-compatible upstreams, plugin providers such as Kiro)
and owns their accounts, OAuth, rotation and translation. Hermes alone sees
such a gateway as one custom endpoint on one wire with hand-pinned metadata.

This plugin mirrors CPA into Hermes instead. Point it at a CPA instance and it
registers one Hermes provider per CPA provider, each on the wire that CPA's
executor for that provider accepts with the least translation, with the model
list and the model capabilities CPA publishes (context window, max output,
image input, reasoning levels). It adds nothing CPA does not serve.

The companion /cpa shows each pool's accounts in chat (active, limited,
cooling, error, disabled) and, on request, each account's live quota (Claude,
Codex, xAI, Antigravity, Devin, Kimi, Kiro). Read-only and lockout-safe.

Install

From the Hermes plugin catalog
(recommended):

hermes plugins install cliproxyapi-provider

This installs the commit the catalog maintainers reviewed.
hermes plugins update cliproxyapi-provider moves to a newer release only
after its catalog pin is bumped.

Development (latest main, not reviewed by the catalog):

hermes plugins install duu261/hermes-cliproxyapi-provider

Requires Hermes 0.21.7 or newer. Model-provider plugins are active once
installed; there is nothing to enable. Restart running Hermes gateways so they
load the plugin.

Both plugins, provider and /cpa, in one
step with the pinned pack (interactive terminal; it asks once to confirm):

curl -fsSLO https://raw.githubusercontent.com/duu261/hermes-cliproxyapi-provider/main/hermes-pack.yaml
hermes plugins pack show ./hermes-pack.yaml
hermes plugins pack install ./hermes-pack.yaml

The pack pins both plugins to the release commit and enables them; a pack
also lists the provider under plugins.enabled, which changes nothing for a
model-provider. Already installed (upgrading)? Add --force:
hermes plugins pack install --force ./hermes-pack.yaml.

Configure

Zero config: set CPA_LOCAL_API_KEY (a CPA client key) in ~/.hermes/.env.
That gives cpa-local for a CPA at http://127.0.0.1:8317; override the URL
with CPA_LOCAL_BASE_URL.

For named or remote instances, add to ~/.hermes/config.yaml:

cliproxyapi:
  instances:
    main:
      base_url: https://cpa.example.com   # with or without /v1
      key_env: CPA_MAIN_API_KEY           # env var holding a CPA client key
      mgmt_key_env: CPA_MAIN_MGMT_KEY     # optional, see "Public mode or management mode"

Then run hermes model (or anything that lists models) once. The plugin reads
the instance's model lists, registers the providers it finds, and caches them,
so later runs register them at startup with no network calls:

  • cpa-main: every model on the instance, on the chat wire.
  • cpa-main-<provider>: one per CPA provider, for example cpa-main-claude,
    cpa-main-codex, cpa-main-xai, cpa-main-kimi.

hermes doctor and multi-process setups (plugins.isolation: host) see
providers that appeared after startup only after a restart.

A new instance on the same CPA base_url as an instance already cached starts
from that cache, so its providers register at the next startup without a
listing. It writes its own cache after its first successful listing.

Wire per provider

| CPA provider | Hermes api_mode | CPA source |
|---|---|---|
| claude | anthropic_messages | Claude executor posts Anthropic Messages |
| kimi | anthropic_messages | Kimi executor passes Claude format to Kimi's /v1/messages |
| kiro (plugin) | anthropic_messages | Kiro plugin takes Claude input |
| codex, xai, meta (Muse) | codex_responses | executors post CPA's Responses format |
| gemini, vertex, aistudio, gemini-interactions, antigravity, devin | chat_completions | Gemini and Interactions wires are not available to Hermes for non-Google hosts; CPA translates |
| OpenAI-compatible and anything else | chat_completions | accepted by every CPA executor |

Override per provider with api_mode (see below). When two providers serve the
same model id, it appears in both and CPA picks the account; the wire is then a
best match.

Keep xai on codex_responses. Grok 4.7 returns its reasoning as an
encrypted item that the client must send back on the next turn
(xAI docs).
Hermes does that on the Responses wire. Chat Completions has no field for it,
and CPA (checked at v8.0.44) replays cached xAI reasoning only for Claude and
Responses clients. Without it, Grok 4.7 stops reasoning after a few tool rounds
and tends to say it will call a tool, then end the turn without calling it.

Public mode or management mode

Public mode is the default and needs only a client key. Management mode adds
mgmt_key_env and reads CPA's own provider map and model definitions.

| | Public (client key) | Management (mgmt_key_env) |
|---|---|---|
| Provider per model | owned_by on /v1/models: the vendor label | the account provider that serves it |
| Devin, google (several Gemini executors) | grouped by vendor label | exact provider |
| Id served by two providers | one group | every group that serves it |
| Context window, named reasoning levels | yes | yes |
| Image input | only when /v1beta/models lists the model's input types; else unknown | from model definitions |
| Reasoning on budget models (no named levels) | not detected | yes |
| Max output | yes, except models whose real limit is exactly 64,000 | yes, all |
| Plugin providers (Kiro and others) | grouped; metadata only from public lists | model definitions from the plugin (CPA v8.0.34+) |
| API-key and OpenAI-compatible channels | yes | kept from public mode (the management API cannot see them) |
| Key held by Hermes | client key | client key plus a full-admin CPA key |

Public mode is enough when each model has one provider and CPA's vendor labels
match its providers. Management mode is the precise one; its cost is the key.
A CPA management key can change config and add or remove accounts. The plugin
only sends the reads below, but Hermes does not strip mgmt_key_env from agent
shells (see Security), so any agent tool that can read your environment can
read it too.

What management mode sends:

  • GET only, to the credentials list, a few sampled accounts' model lists per
    provider, and the model-definitions list per provider (built-in providers
    first, then plugin providers by name; CPA before v8.0.34 has none for
    plugin providers and the plugin skips them). Never quota, usage,
    downloads, OAuth or any write.
  • At most 32 requests and 20 seconds per pass, at most one pass per 15 minutes
    per instance, never on the request path.
  • The plugin stops at the first 401 and never retries that key against that
    CPA, from any instance, either plugin or across restarts, until the key
    changes. See Never get locked out of CPA.
    Any other failure falls back to public grouping.
  • CPA must allow management from the plugin's address (remote-management
    in CPA's config) unless both run on the same host.

Overrides

cliproxyapi:
  instances:
    main:
      base_url: http://127.0.0.1:8317
      key_env: CPA_MAIN_API_KEY
      groups:
        kimi:
          api_mode: chat_completions      # change one provider's wire
        fast:
          models: ["gpt-*-mini", "claude-haiku-*"]   # your own group
          display_name: Fast models

A group with models replaces that provider's membership with the matching
ids from the live list (shell-style patterns, case-sensitive).

Billing route (gateway in front of your CPA)

If you run a billing gateway such as New API in front of the same CPA, the
plugin can send inference through it while still learning everything from
CPA:

cliproxyapi:
  instances:
    main:
      base_url: http://127.0.0.1:8317     # discovery: model list, providers, metadata
      key_env: CPA_MAIN_API_KEY
      route_via: https://gateway.example  # inference goes here and is billed there
      route_key_env: GATEWAY_KEY          # the gateway's key
      groups:
        xai:
          route_key_env: GATEWAY_GROK_KEY # optional: a key for another billing group
          api_mode: codex_responses       # how this gateway channel expects requests
  • Profiles point at route_via and use the gateway key. The CPA key is used
    only for CPA's model lists and never sent to the gateway; the gateway key is
    never sent to CPA. They must be different env vars.
  • Only models the gateway lists for that key (GET /v1/models) are kept. If
    the gateway list fails, the last known list is kept. Until the first list
    for a key is read, its profiles use CPA's list: routed providers register
    at startup from the instance's cached CPA list, or from another configured
    instance's cache on the same CPA base_url. A routed instance on a CPA no
    instance has listed yet needs one model listing first, as above. A call to
    a model the key does not sell fails at the gateway until the next refresh
    narrows the list. A known list, even an empty one, filters strictly.
  • Gateways often convert request formats per channel unless body pass-through
    is on. Profiles keep the CPA wire from the table above; set api_mode per
    group where the gateway channel needs a different one.
  • Context windows and reasoning levels describe CPA's model, not limits the
    gateway may add.
  • The gateway may fail over to other channels it sells under the same model
    name. The plugin cannot see or prevent that.
  • The plugin uses only the gateway's client endpoints, never its admin,
    channel, pricing or billing APIs.
  • Known limit: Hermes strips from agent subprocesses only the key names a
    registered provider declares. Routed providers declare the gateway key, so
    the CPA key_env (needed for discovery) stays visible to agent shells on a
    routed instance. mgmt_key_env is never declared on a provider, so it is
    not stripped on routed or unrouted instances. Hermes has no plugin hook to
    declare a secret without making it an inference credential yet.

Metadata

Context window, max output, image input, reasoning support and reasoning-effort
levels come only from CPA: management model definitions when available, else
CPA's public model lists matched by exact id. Values CPA does not publish stay
unknown. Without a management key, max output comes from CPA's Anthropic-format
model list, which covers every model. CPA writes 64,000 there for a model with
no limit, so the plugin treats exactly 64,000 as unknown and Hermes falls back
to models.dev; a model whose real limit is 64,000 loses it the same way.

Hermes /model shows max output, PDF and structured output only from
models.dev; a plugin cannot set them, and CPA's model definitions have no PDF
or structured-output field. To see them, add vendor metadata from models.dev:

providers:
  cpa-main-claude:
    catalog_provider: anthropic

Precedence, highest first: your model_overrides, this plugin, models.dev.

Security

  • Keys are referenced by environment variable name and resolved by Hermes.
  • Hermes strips from agent subprocesses only the env names a registered
    provider declares. Every profile declares its inference key (key_env, or
    the gateway key on a routed instance), so mgmt_key_env, and on a routed
    instance the CPA key_env, stay readable by agent shells.
  • Plain http:// is allowed only when every address the host resolves to is
    loopback, RFC 1918, 100.64/10 or IPv6 ULA. Anything else needs https://.
  • No redirects, capped responses, and failures reported as an HTTP status and
    category only, never bodies, URLs or keys.
  • Catalog requests send User-Agent: hermes-cliproxyapi-provider/<version>.
    One extra /v1/models request appends grok-shell-compatible, because that is
    the client CPA publishes context windows and reasoning levels to, and another
    sends Anthropic-Version: 2023-06-01, the format that carries output limits.
    Their ids are matched against the normal list, so they add metadata, never
    models. Inference requests carry Hermes' own headers; the plugin sets none.
  • The cache at $HERMES_HOME/cache/cliproxyapi/ (mode 0600) holds model ids,
    owners, provider membership and metadata. No keys, no account names. Its
    locks/ subdirectory holds one empty lock file per CPA and
    rejected.json, the rejected management keys as salted HMACs, not keys.

Never get locked out of CPA

CPA counts failed management logins per client IP, in memory, per CPA
process. A missing or wrong management key adds one; the fifth in a row bans
that IP for 30 minutes, localhost included, which also locks out CPA's web UI
and any other tool on the same IP. A successful management login resets the
count, a CPA restart clears it, and an IP with no failures for two hours is
forgotten. Failures do not expire after 30 minutes. Answers remote management disabled and key not set (403) do not count.

What both plugins do, per HERMES_HOME on Linux and macOS:

  • One management check per CPA at a time, across the provider, /cpa and
    every Hermes process (CLI and gateway). The provider skips its check when
    /cpa is busy and tries again on the next refresh; /cpa waits up to 25
    seconds, then says busy.
  • A key that is already bad costs one try. The rejection is remembered (salted
    HMAC) across restarts and both plugins, and that key is not sent to that
    CPA again until it changes.
  • A key revoked in the middle of /cpa quota can cost up to 4: the requests
    already in flight. /cpa quota first sends one request alone, so a key
    that is already bad never reaches the parallel requests.
  • On Windows only the in-process lock applies; two Hermes processes there are
    coordinated by the remembered rejections alone.

What you do:

  1. Set the key through mgmt_key_env only, and log in to CPA's web UI once
    with it before Hermes starts. A good login also resets the count.
  2. Rotate in one step: change CPA's key, update the env var, restart the
    gateway. The old key stays remembered as rejected, so Hermes goes quiet
    instead of retrying it.
  3. Run Hermes on the same host as CPA, or set CPA's server.trusted-proxies
    (older configs: top-level trusted-proxies) to your reverse proxy's
    address. Otherwise every client shares the proxy's IP and one bad key bans
    all of them.
  4. Other tools on the same IP count too (CPA Usage Keeper, scripts, a browser
    on the web UI). Fix their keys first.
  5. Each Hermes profile remembers rejections on its own. With five or more
    profiles holding the same bad key on one host, fix it before starting
    them.
  6. Use one spelling per CPA in base_url (127.0.0.1 or localhost, not
    both): the plugins coordinate by URL.
  7. Upgrade both plugins together; 0.4 and earlier do not share the lock.
  8. If banned: wait 30 minutes or restart CPA, and fix the key before Hermes
    tries again (/cpa shows key rejected).

/cpa: pool status (companion plugin)

The repo also ships cpa-status, a second plugin with one slash command,
/cpa, that shows account health for every configured instance. Model-provider
plugins cannot register commands, so it installs and enables separately:

hermes plugins install duu261/hermes-cliproxyapi-provider#cpa-status
hermes plugins enable cpa-status

It needs mgmt_key_env on the instances it reports on; instances without one
show no management key, unless another instance on the same CPA base_url
has one: then they are listed under it as same CPA. Restart running
gateways after enabling.

/cpa                    every instance: accounts per provider
/cpa pre                one instance, plus the last hour of requests
/cpa pre codex          one line per account
/cpa quota pre          live usage of every account with quota
/cpa quota pre codex    Codex only
pre · v8.0.51
  codex 4: 3 active · 1 cooling (next 17:20)
  xai 2: 2 active
CPA v8.0.52 available (running v8.0.51)
pre / codex · 4 accounts
codex-al…@…  active · 1h 173/71 · 5h 22% · wk 0% (1m ago)
codex-bo…@…  cooling until 17:20 (quota)
  • Read-only: one GET /v8/management/credentials per instance per run (v0
    auth-files only after a 404), and only when you type /cpa. No timers, no
    retries. A repeat within 20 seconds answers from memory.
  • The CPA version next to each instance is the X-CPA-VERSION header of that
    same reply. On the plain /cpa overview, CPA <version> available comes
    from CPA's own update route (GET /v8/management/server/latest-version,
    which asks GitHub): one request per Hermes process every 6 hours, 10
    minutes after a failure. A failure only hides the line.
  • Last-seen quota (5h and weekly) comes from what CPA recorded on real traffic
    for Claude and Codex accounts. CPA records none for other providers. Plain
    /cpa never asks CPA to check quota upstream; /cpa quota does.
  • Emails in account names and messages are masked; email, account,
    project_id and path are never shown (/cpa quota uses the Antigravity
    project_id only to build its request).
  • Works when the chat is idle. Sent while an agent turn is running, it goes to
    Hermes' busy handling (queued or sent to the agent) like any other plugin
    command.
  • Lockout: see Never get locked out of CPA.

/cpa quota: live usage

pre quota · live 21:40
codex · 4 accounts: 3 have room · 1 out (next free 22:10)
codex-xy…@…  plus  5h 100% → 22:10 · wk 60% → Nov 02  OUT
codex-bd…@…  pro  wk 31% → Oct 30
codex-ab…@…  plus  5h 23% → 22:40 · wk 69% → Oct 29
codex-cu…@…  pro  wk 40% → Nov 01

/cpa quota <pool> asks each vendor how much of each account is used, the way
CPA's own web UI quota page does. For the built-in vendors, CPA's api-call
route sends the web UI's request with that account's token (CPA fills it in;
Hermes never sees it). Accounts of other providers are read from their CPA
quota plugin when CPA lists one. Every request, and when it is sent:

| Provider | Requests per account | What you see |
|---|---|---|
| Claude | GET https://api.anthropic.com/api/oauth/usage | 5h, wk; weekly model and app limits when sent (fable, opus, sonnet, apps, cowork); extra usage when on, with spend/limit; credit pools ($ left) |
| Codex | GET https://chatgpt.com/backend-api/wham/usage | windows by their own length (5h, wk, mo), plan, credits when the account has them |
| xAI | GET https://cli-chat-proxy.grok.com/v1/billing?format=credits, then GET https://cli-chat-proxy.grok.com/v1/billing | weekly credits wk (wk no figure yet until xAI reports a percent); monthly spend mo and plan (supergrok / supergrok_heavy) only when xAI reports a monthly limit |
| Antigravity | POST https://daily-cloudcode-pa.googleapis.com/v1internal:retrieveUserQuotaSummary with the account's project_id; the daily-cloudcode-pa.sandbox and cloudcode-pa hosts only when the one before failed at the vendor or returned no quota | per model group, 5h and wk |
| Devin | POST https://server.codeium.com/exa.seat_management_pb.SeatManagementService/GetUserStatus | day, wk, plan |
| Kimi | GET https://api.kimi.com/coding/v1/usages (api.kimi.ai when CPA lists the account as kimi-ai) | each limit window, weekly, mo |
| CPA plugin quota (e.g. Kiro) | GET /v8/management/plugins/<id>/quota on CPA; the plugin asks its vendor | the plugin's meters and plan |

None of these cost money or use up quota: they are the same usage reads the
web UI makes. Left out on purpose: xAI's paid 1-token chat check (the web UI's
fallback for paid API-key accounts, which then show the billing error),
identity and plan lookups, downloading account files, and every reset.

The headers, including each vendor's CLI User-Agent, are the web UI's. The
percent is what is used (vendors that report what is left are converted);
there are no totals across plans. An account is OUT when a window is at 100%
or the vendor says it is blocked. Antigravity is per model group: CPA holds back
only the models that ran out, so an account is OUT only when every group is
full; otherwise the full groups show as out: <group>. Claude's model-scoped
weekly limits (Fable, Opus, Sonnet, apps, Cowork) work the same way: a full one
shows as out: fable and the account keeps serving other models.

  • Only when you type it. At most 20 accounts and 3 requests per account per
    run. The first request goes alone, then at most 4 at a time; a repeat within
    60 seconds answers from memory. Disabled accounts are skipped.
  • /cpa quota <pool> <provider> takes claude, codex, xai,
    antigravity, devin, kimi, plugin, or a plugin's provider such as
    kiro.
  • An expired account token shows token rejected by vendor and never counts
    against CPA's lockout. A rejected management key stops the run.
  • CPA's account index, the Codex account id, the Antigravity project id and
    the CPA plugin id are used only to build requests and are never shown,
    logged or cached. Vendor replies are read field by field; bodies and
    headers are never shown.
  • Not covered: Meta (the web UI reads its raw credential file), Kimi .ai
    accounts that CPA lists only as kimi (they get the .com URL and show
    token rejected by vendor), Codex code-review and per-model extra limits,
    plugin summary figures.

CPA versions

The plugins follow CPA releases and set no maximum. Features that need a
newer CPA:

| Feature | CPA |
|---|---|
| Public grouping by owned_by (/v1/models) | v4.1.1+ |
| Management mode (credentials, credential models, model definitions) | v6.7.26+ (v8 routes from v8.0.0) |
| Model definitions for plugin providers (Kiro and others) | v8.0.34+ |
| /cpa | v5.0.0+ (v0 auth-files; v8 credentials from v8.0.0) |
| /cpa last-seen quota | v7.2.142+ |
| /cpa CPA version | v6.3.36+ |
| /cpa update hint | v6.5.42+ |
| /cpa quota built-in vendors (api-call with $TOKEN$) | v6.6.63+ |
| /cpa quota plugin quota (e.g. Kiro) | v8.0.25+ |

Older releases answer the missing route with 404, and that feature is
skipped.

Development

python -m unittest discover -s tests -v          # core tests, no Hermes needed
PYTHONPATH=/path/to/hermes-agent python -m unittest discover -s tests -v
python -m unittest discover -s cpa-status/tests -v
cmp cpa.py cpa-status/cpa.py                     # the companion ships a copy
hermes plugins doctor . --ci
hermes plugins validate .
hermes plugins doctor ./cpa-status --ci
hermes plugins validate ./cpa-status

Contributions: see CONTRIBUTING.md for the safety rules
every change keeps, and SECURITY.md to report a problem
privately.

License

MIT

README from the reviewed commit 08fdae8; it updates when the author re-pins.

More by duu261

3 plugins by duu261 in the catalog.

duu261openai-compatibleGPT Image through CLIProxyAPI, New API, or any OpenAI Images-compatible gateway, with gateway-aware errors and requested-vs-returned size reporting. Disclosure — sends image prompts and any source images (local files, data URLs or public HTTPS URLs) to the OpenAI-compatible gateway base_url you configure, authenticated with OPENAI_COMPAT_IMAGE_API_KEY.Communitytools5duu261cpa-status/cpa in chat for CLIProxyAPI (CPA) pools: account health per provider (active, limited, cooling, error, disabled), the CPA version with an update hint, and on request each account's live quota (Claude, Codex, xAI, Antigravity, Devin, Kimi, Kiro), the same usage reads as CPA's own web UI. Companion to cliproxyapi-provider and reads the same cliproxyapi config. Disclosure — only when you type /cpa, and with the management key env var you name per instance: GETs the credentials list from your configured CPA and CPA's own update check (at most once per 6 hours); for /cpa quota, POSTs CPA's api-call so CPA sends each built-in vendor's private usage request (Anthropic, ChatGPT/Codex, xAI, Google Antigravity, Codeium/Devin, Kimi) with that account's token, using the vendor clients' own User-Agent and client headers as CPA's web UI does (Antigravity and Devin are vendor POSTs, the rest GETs), and GETs CPA plugin quota for Kiro; at most 20 accounts, 4 requests in flight. Stops at the first rejected key: one failed try, or up to 4 if the key is revoked mid-run; CPA bans an IP after five failed management logins. Writes only lock files and a rejected-key marker (salted HMAC, never a key) under $HERMES_HOME/cache/cliproxyapi/locks/. Known limit: Hermes strips from agent subprocesses only the key env vars a registered provider declares, so the management key env var stays readable by agent shells.Communitymodels4