Auth Cloudflare Workers AI model-provider plugin for Hermes Agent - pure Python provider + Rust core executable. Live account-aware catalog discovery, OpenAI-compatible inference, 22-model fallback.
auth-hermes-cloudflare registers the auth-cloudflare-workers-ai provider
(display name Auth Cloudflare Workers AI) against Cloudflare's
OpenAI-compatible Workers AI surface. The account ID is injected from the environment, the catalog is
fetched from /ai/models/search in the OpenRouter format, and the provider
shows up in hermes model with zero custom_providers wiring. All
endpoint/auth logic lives in the Rust core; Python is a thin provider.
git clone https://github.com/PlayForm/Auth-Hermes-Cloudflare.git
ln -s "$(pwd)/Auth-Hermes-Cloudflare" ~/.hermes/plugins/auth-hermes-cloudflare
hermes plugins enable auth-hermes-cloudflare
hermesThen export the two env vars the provider reads:
export CLOUDFLARE_ACCOUNT_ID="<your account id>" # Workers & Pages → Overview
export CLOUDFLARE_API_TOKEN="<scoped token>" # Account → Workers AI → Write
hermes model # pick: Auth Cloudflare Workers AIThe account ID is operational metadata, not a secret. The API token is a secret - scope it to Account → Workers AI → Write (some dashboard versions label the same permission Workers AI → Edit) and nothing else. Do not request DNS, Workers Scripts, R2, D1, KV, Pages, Zero Trust, or account administration permissions.
The provider path is pure Python - no Rust toolchain, no binary download,
no compiled dependencies. The optional download.sh flow (the prebuilt
auth-cloudflare executable) is only needed for the diagnostics and
conformance commands, not for using Auth Cloudflare Workers AI in Hermes.
After installing and launching Hermes once:
~/.hermes/
├── plugins/
│ └── auth-hermes-cloudflare → /path/to/Auth-Hermes-Cloudflare ← symlink to this repo
└── profiles/<name>/
└── plugins/
└── auth-hermes-cloudflare → ~/.hermes/plugins/auth-hermes-cloudflare
The plugin also adds to your Hermes config:
# Added automatically on enable
plugins:
enabled:
- auth-hermes-cloudflare
# Provider block (manual or via the setup wizard)
providers:
cloudflare:
api_key_env: CLOUDFLARE_API_TOKEN
base_url: https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/ai/v1
api_mode: chat_completionsNo proxy processes are launched - the provider runs in-process.
# In a Hermes session:
hermes model # pick: Auth Cloudflare Workers AI
# Or via CLI - token health check:
curl https://api.cloudflare.com/client/v4/user/tokens/verify \
-H "Authorization: Bearer $CLOUD...OKEN"
# → {"success":true,"result":{"id":"...","status":"active",...}}hermes plugins disable auth-hermes-cloudflare
rm ~/.hermes/plugins/auth-hermes-cloudflarePython (provider registration) Rust core (single source of truth)
__init__.py 233L auth-cloudflare (executable)
register_provider(cloudflare) ├─ auth: account/token → endpoints
lazy base_url / models_url ├─ catalog: ModelRecord, ModelRole, CapabilityState
fetch_models() (OpenRouter fallback) ├─ cache: account-scoped cache slug
└─ policy: model policy + capability table
auth-hermes-cloudflare (Rust crate)
└─ re-exports core types for hooks/tools
The Rust core owns the canonical endpoint/auth/catalog/policy logic and ships
as a single executable, auth-cloudflare. The Python provider mirrors it
in-process so the picker and wizard work with or without the executable. URLs
are computed lazily from os.environ at access time, because plugin
discovery runs before the profile .env is loaded.
| Item | Value |
|---|---|
| Provider name | auth-cloudflare-workers-ai |
| Aliases | auth-cloudflare, cloudflare, cloudflare-workers-ai, workers-ai, cf-workers-ai, cf |
| Display name | Auth Cloudflare Workers AI |
| API mode | chat_completions |
| Auth type | api_key |
| Signup | dash.cloudflare.com/profile/api-tokens |
| Health check | disabled - Cloudflare has no /models endpoint; token verify is used instead |
| Fixed base URL | yes - derived from the account ID, the wizard never prompts |
| Default model | @cf/deepseek-ai/deepseek-v4-flash-0731 |
| Fallback models | 22 curated chat models compiled into the profile |
Two environment variables drive everything. The AUTH_CLOUDFLARE_* names
are canonical; the CLOUDFLARE_* names are the legacy Hermes-compatible
aliases - the Rust core owns the resolution precedence.
| Variable | Role |
|---|---|
CLOUDFLARE_ACCOUNT_ID / AUTH_CLOUDFLARE_ACCOUNT_ID |
account ID - operational metadata, not a secret |
CLOUDFLARE_API_TOKEN / AUTH_CLOUDFLARE_API_TOKEN |
API token - a secret, only ever sent as a Bearer header |
export CLOUDFLARE_ACCOUNT_ID="<your account id>"
export CLOUDFLARE_API_TOKEN="<scoped token>" # Account → Workers AI → WriteThe provider path is pure Python, so this is optional. The auth-cloudflare
executable backs the full command surface - hermes cloudflare doctor / catalog refresh / catalog export / model inspect, catalog caching, and the
conformance commands (model verify --suite smoke|tool-loop, model health). download.sh installs it from GitHub Releases:
Terminal
bash download.sh [version] [target-triple]- Version auto-detection order:
BINARY_VERSION→Cargo.toml(monorepo) → latestCloudflare/v*GitHub release tag. - Release tag convention:
Cloudflare/v<version>- theBuildworkflow attaches the per-target archives (aarch64/x86_64macOS + Linux) on that tag. - Installs
auth-cloudflareinto~/.hermes/bin/auth-cloudflareby default (override withBINARY_DIRorAUTH_CLOUDFLARE_BIN). - SHA256SUMS-verified: the archive checksum must match the per-target
SHA256SUMS-<target>.txtbefore extraction, and the extracted binary self-validates viaauth-cloudflare version --format json. - Atomic + fail-closed: installs via copy-then-rename through a temp file,
with an
EXITtrap that removes every temp artifact on any failure.
Discovery order (locate_auth_cloudflare_binary): AUTH_CLOUDFLARE_BIN
env → PATH → ~/.hermes/bin → plugin bin/ → plugin binaries/.
The auth-hermes-cloudflare binary (cargo install auth-hermes-cloudflare --locked) manages the engine executable:
auth-hermes-cloudflare status # JSON: plugin + binary state
auth-hermes-cloudflare install [options] # run download.sh, then doctor
auth-hermes-cloudflare upgrade [options] # alias of install (re-run download.sh)
auth-hermes-cloudflare doctor # run 'auth-cloudflare doctor --format json'
auth-hermes-cloudflare uninstall # remove ~/.hermes/bin/auth-cloudflare (alias: unlink)
auth-hermes-cloudflare link --source <path> # symlink/copy <path> → ~/.hermes/bin/auth-cloudflareinstall options: --plugin-dir <dir> (where to find download.sh),
--binary <path> (exact install path, sets AUTH_CLOUDFLARE_BIN), and
--no-download (print manual install instructions instead). upgrade
re-runs download.sh with the latest BINARY_VERSION, so updating is the
same atomic, checksum-verified flow as a fresh install.
Note
Without the executable the picker still works pure-Python through the
in-process fallback, but the diagnostics and conformance commands are
unavailable. download.sh fetches the checksum-verified auth-cloudflare
release asset from the Cloudflare/v<version> GitHub release built by the
Build workflow - no Rust toolchain required.
git clone https://github.com/PlayForm/Auth-Cloudflare.git
cd Cloudflare
git submodule update --init --recursive
cargo build --release -p auth-cloudflare -p auth-hermes-cloudflare
# auth-cloudflare executable at target/release/auth-cloudflareAuth-Hermes-Cloudflare/
├── __init__.py ← 233-line Python provider (register_provider, lazy URLs)
├── plugin.yaml ← model-provider manifest (env vars, min Hermes version)
├── download.sh ← Prebuilt executable installer (checksum-verified, atomic)
├── BINARY_VERSION ← Expected executable version
├── PROTOCOL_VERSION ← JSON CLI protocol version
├── README.md ← This file
└── .gitignore