A named profile with no credentials of its own silently resolved the root
profile's provider state and credential pool, and a token refresh inside
that profile (xAI, Codex, Anthropic PKCE, Nous) wrote the rotated chain back
into the root store. An isolated service profile therefore acted, and
rotated tokens, as the owner with no way to switch it off.
Maintainer ruling: profiles without credentials are asked to set a provider,
never handed another profile's auth. Profiles are independent islands.
What changes
- `hermes_cli/auth.py`: `_load_provider_state*`, `read_credential_pool` and
`_provider_state_transaction` read the active store only; the global-root
resolver, its mtime memo and `_persist_provider_state_to_store` are gone.
- xAI / Codex / Nous-guest / pool refresh paths persist to the active store;
the root write-through, the borrowed-row bookkeeping
(`_borrowed_root_ids`, `persist_pool_entries`, `_update_root_pool_rows`)
and the forked-grant heal are removed. `_write_hermes_oauth_credentials`
loses its root `target`.
- `resolve_provider` / `agent_init` name the profile in the
no-provider error and print `hermes -p <name> model` guidance.
- `hermes update` prints a one-time notice listing every named profile that
has no provider of its own (`hermes_cli/profile_credential_audit.py`) so a
bot never goes quiet unannounced.
- Desktop create dialog: the "Share keys & accounts" checkbox described the
removed inheritance; it now mirrors API keys (`mirror_credentials`) and
says OAuth logins need a sign-in. `share_auth` is accepted from older
clients and ignored; `ProfileMirrored.auth` is a bool again.
- Docs: profiles.md, multi-profile-gateways.md isolation table,
hermes_cli/AGENTS.md.
The fallback was added in 33bf5f62 so kanban/cron workers under a named
profile did not die with "No LLM provider configured" when the credential
lived only at root; that convenience is exactly the isolation hole the
ruling closes, and `--clone` / dashboard mirroring still copy API keys.
Tests: fallback/write-through/heal pins deleted; 4 invariants proven red on
base (profile never reads root; profile refresh never writes root; Nous
connector gate reads only the profile store; Anthropic pool never borrows or
rotates the root grant, root control still refreshes).
Website
This website is built using Docusaurus, a modern static website generator.
Installation
yarn
Local Development
yarn start
This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.
Build
yarn build
This command generates static content into the build directory and can be served using any static contents hosting service.
Deployment
Using SSH:
USE_SSH=true yarn deploy
Not using SSH:
GIT_USER=<Your GitHub username> yarn deploy
If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the gh-pages branch.
Diagram Linting
CI runs ascii-guard to lint docs for ASCII box diagrams. Use Mermaid (````mermaid`) or plain lists/tables instead of ASCII boxes to avoid CI failures.