Skip to content

Hermes — tiers, install, config & provider runbook

Hermes (NousResearch/hermes-agent) is a self-hosted, terminal-native AI agent with its own provider chain, profiles, memory, and pre-tool guards. himmel drives it in three tiers (config lives OUTSIDE this repo, so hermes is part of himmel even when a checkout doesn’t show it):

TierWhat it doesStatus
CR criticIndependent model-family reviewer over a branch diff, wired into /pr-check (scripts/cr/hermes-critic.sh + critic-first-pass.sh → scripts/hermes/invoke.sh). No free critic is registered (scripts/cr/critics.json); the panel defaults straight to the paid codex/gpt-6.1-sol anchor — set CR_PROFILE=none for claude-only. A second paid row, claude (claude-opus-5-5, effort medium), runs the official claude binary read-only, not hermes: provider claude-api (default, per-token key through scripts/api-lane/claude-api.sh) or claude-subscription (behind bank-preflight and the native-auth pin). A missing key, closed lane, exhausted credit or non-PROCEED usage is a clean skip (critic-first-pass.sh exit 5), never a red panel. It is same-family, so it never counts toward CR_REQUIRE_CROSS_MODEL. Tune with CR_CLAUDE_CRITIC_EFFORT / CR_CLAUDE_CRITIC_MAX_USD; turn it off with a drop:true row for slug claude in critics.local.json. Fail-closed verdict, fail-open transport. Routes + the proven invocation: CR critic: routes + proven invocation.Working — the production hermes lane today.
JuniorChore-shaped work (vault inbox capture, summaries, note-taking) on free inference, behind a read-only luna_vault_guard write fence.Working.
himmel_agent main tierA full-control orchestrator (Codex / gpt-6.1-sol) carrying parity_guard instead of the junior fence. It does real engineering / research / vault work.Alpha - guard parity now tests green; still treat as experimental until more live mileage.

See the registry row in docs/tool-adoption/registry.md (tool-adoption rubric) for the adoption rationale and trust posture. The rest of this runbook is the install + configure + provider-wiring reference. Config lives OUTSIDE this repo, so a machine rebuild reproduces it from here.

Quick start: install & configure (new user)

himmel ships no base-hermes installer and never writes your hermes identity (SOUL.md, config.yaml, .env, profiles). You install and configure hermes itself with hermes’s own tooling; himmel only adds the optional himmel_agent profile on top. There are four steps: steps 1–3 give you the working CR-critic and junior tiers, and step 4 is the alpha main tier.

1. Install hermes (upstream)

Use the official installer (quickstart):

Terminal window
# Linux / macOS:
curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash
source ~/.bashrc # or ~/.zshrc — reload PATH

This installs a hermes CLI and a config home (upstream default ~/.hermes/; see Install layout below). Hermes requires a model with ≥64K context.

2. Configure hermes (provider + keys)

Hermes keeps secrets in <home>/.env, everything else in <home>/config.yaml (config docs); hermes config set KEY VAL auto-routes (API keys → .env, the rest → config.yaml). Pick one path:

Terminal window
hermes setup --portal # fastest: one OAuth → Nous provider + Tool Gateway
hermes model # or: interactive provider/model picker
# or wire a key + model by hand (secrets land in .env automatically):
hermes config set OPENROUTER_API_KEY sk-or-...
hermes config set model.default <provider/model>

The model: block in config.yaml is {default, provider, base_url}, with an ordered fallback_providers: list for resilience. himmel’s live chain and fallback policy are in Provider routes below. For himmel’s automated review paid-escalation lane (codex / gpt-6.1-sol), log in to Codex once:

Terminal window
hermes auth # choose Codex (ChatGPT) — saved to <home>/auth.json

Verify with hermes doctor (provider connectivity) and hermes config check (missing settings after an upgrade).

3. Point himmel at your hermes

himmel’s hermes scripts do not all fall back to the same install root, so export both vars in the shell that launches Claude:

  • HERMES_HOME: install root; used by /himmel-update, the profile provisioner and invoke.sh’s profile lookup. Fallback: ~/.hermes for /himmel-update and the provisioner, ~/.local/share/hermes for invoke.sh and parity_guard.
  • HERMES_PY: the venv python; used by the CR lane (scripts/hermes/invoke.sh). Fallback: the interpreter the upstream launcher reports, else <home>/hermes-agent/venv/bin/python (scripts/lib/resolve-hermes-py.sh).
  • HERMES_INVOKE_TIMEOUT: wall-clock watchdog budget in seconds for invoke.sh (default 1800; ceiling 86400). A parity_guard DENY is not terminal to hermes, so this bounds a stuck deny-retry loop and kills the process tree on expiry (rc 124). PARITY_GUARD_DENY_ESCALATE_N (default 3) additionally aborts early (rc 125) after N identical denies in a row; see docs/internals/harness-compat.md.
Terminal window
export HERMES_HOME="$HOME/.hermes"
export HERMES_PY="$HERMES_HOME/hermes-agent/venv/bin/python"

Smoke-test the automated review’s sanctioned script (spends your provider’s free credits, not paid budget):

Terminal window
bash scripts/hermes/invoke.sh "Reply with exactly: OK"

A clean OK means /pr-check’s hermes critic is wired. That is the whole working setup: the CR-critic and junior tiers need nothing further.

4. (Optional, alpha) add the himmel_agent main tier

The full-control orchestrator tier is experimental. Its parity_guard tests green for the guard-parity set, but it still has less live mileage than the Claude/himmel path. It is not required for the CR-critic or junior tiers. If you want it, provision the additive profile per Profiles below.

Install layout

  • Install root: ~/.hermes/ (or HERMES_HOME): config.yaml, SOUL.md, agent-hooks/luna_vault_guard.py (fail-closed vault write fence), .env (API keys), and the hermes-agent/ checkout.
  • Hermes reads its OWN .env (~/.hermes/.env); shell env and himmel’s repo-root .env are irrelevant to it.

Profiles: your default + himmel’s himmel_agent main tier

Alpha. The himmel_agent main tier is experimental. Its parity_guard now tests green for the guard-parity set in docs/internals/lane-parity.md, but it still has less live mileage than the Claude/himmel path. The working, production hermes lanes today are the CR critic and junior tiers (top of this doc). Use himmel_agent knowingly.

Hermes supports named profiles (hermes profile create|list|use|show), each an isolated workspace at <home>/profiles/<name>/ with its own SOUL.md, config.yaml, .env, memories, and hooks. himmel uses this to add a capable main tier without touching your existing setup:

  • default (and any profile you already have) is yours, never touched. himmel ships no SOUL.md and has no hermes installer; it never creates, writes, or overwrites your SOUL.md, config.yaml, profiles, or .env. A fresh hermes with no SOUL.md uses hermes’s own built-in identity.
  • himmel_agent is an additive profile provisioned on demand by scripts/hermes/install-himmel-profile.sh. It is himmel’s main-tier orchestrator (Codex / gpt-6.1-sol): a generalist that does real engineering, research, vault, and writing work: the “main puller” when Claude capacity is scarce. It carries agent-hooks/parity_guard.py instead of the junior luna_vault_guard.py: the write/repo fence and routine git/gh/rm blocks are dropped, but the secret-read fence, self-protection (it can’t rewrite its own guard/config/SOUL), and catastrophic-shell blocks (rm -rf, force-push, scheduler/disk mutation, curl|sh) stay, for parity with what Claude/himmel themselves enforce.
# provision (or refresh) the himmel_agent profile AND wire parity_guard into
# EVERY hermes profile by default (universal guard) — additive,
# idempotent, non-clobbering (swaps a luna_vault_guard, or ADDS the guard where
# a profile has none, preserving any other hooks it carries):
bash scripts/hermes/install-himmel-profile.sh
# narrow the universal pass to named profiles only:
bash scripts/hermes/install-himmel-profile.sh --parity-guard=default,research

The provisioner clones your default (for working keys), then overwrites only the new profile’s SOUL.md (himmel owns that one) and wires its hook. After running it, hermes gateway restart and approve the new hook once. Reach the profile with hermes profile use himmel_agent (or the generated wrapper). SOUL.md is identity only; project specifics (repo conventions, vault rules) stay in each context’s AGENTS.md / CLAUDE.md / vault _CLAUDE.md.

hermes profile use is sticky, and hermes config set follows it. Once a profile is active, hermes config set KEY VAL without -p writes to that profile (for example himmel_agent), not to default. Pass -p default (or the profile you mean) every time. To update hermes itself, run hermes update --yes --no-gateway-restart: it never starts a gateway you have stopped. A plain git fetch inside the install checkout can crash, because the install is a tree:0 partial clone and git’s pack-objects hits an internal BUG there.

Tier coupling — capability follows the model, not the other way round. A weaker free-tier model holding the full parity_guard (write code, run git, open PRs) is risky, and the pre-tool guard can’t tell at call time which model will answer. So couple them structurally instead:

  • The himmel_agent (full control) runs on the trusted premium model only (Codex / gpt-6.1-sol) with no free fallback (fallback_providers: []). If the premium model is rate-limited, the main tier simply pauses; it does not degrade into a powerful agent backed by a free model.
  • The free tier lives on the read-only junior (your default / luna_vault_guard profile) on a free model (e.g. OpenRouter nvidia/nemotron-3-ultra-550b-a55b:free, which draws no paid budget). It runs in parallel as always-available, low-stakes capacity, so when the premium model is down you still have a safe agent, just not a writing one.

In short: fall back to free only by also dropping to read-only; never pair a free model with write/git/PR control.

CR critic: routes + proven invocation

scripts/cr/hermes-critic.sh reviews a branch diff with a model family that did not produce it. Two reviewer routes:

RouteReviewerCost
hermes (default)scripts/hermes/invoke.sh with no --model (the himmel_agent profile default)free today (see below)
claude (opt-in)claude -p print-mode, --permission-mode plan --output-format json --max-turns 1 --strict-mcp-config in a scratch cwdspends the Claude subscription usage budget — gated by scripts/lib/bank-preflight.sh: a SKIPPED-BANK verdict refuses the route (exit 3, fall back to another reviewer); BANK-STALE / BANK-UNKNOWN are fail-open

Route selection: an explicit --route / CRITIC_ROUTE always wins; otherwise it is derived from --implementer:

--implementerRouteWhy
(none)hermesdefault: free front-tier profile model, no subscription usage budget spend
hermesclaudehermes wrote it, so Claude reviews it
codexhermescross-family only while the hermes reviewer is not codex
claudehermescross-family, but a claude-family hermes reviewer leaves no cross-family route, so the script exits 2 instead of returning a verdict that looks cross-family and is not; pass --route to override deliberately
otherhermescross-family

The codex → hermes cell depends on the profile default. The himmel_agent profile default is ox-alpha today: free, front-tier, and temporary (operator ruling 2026-08-22; lane profiling is a planned follow-up). ox-alpha is a different family from codex, so the cell holds. The script infers the reviewer family from the resolved model id (gpt-*/o<N>*/codex* → codex) and falls back to claude for a codex implementer when the hermes reviewer is codex. Pin the answer with HERMES_CRITIC_FAMILY when the profile default moves and that inference stops holding; pin the model itself with HERMES_CRITIC_MODEL (--provider openai-codex is then applied only for codex-family ids).

Invocation (the route was live-verified 2026-08-22 with a real JSON verdict, exit 1, no rc=3):

Terminal window
HERMES_PY="$HOME/.hermes/hermes-agent/venv/bin/python" \
timeout 300 bash scripts/cr/hermes-critic.sh \
--repo . --base origin/main --goal "review this diff"
  • HERMES_PY: the hermes venv interpreter; needed when resolve-hermes-py.sh cannot find it under HERMES_HOME.
  • node must be on PATH (the verdict parser).
  • Exit 0 pass / 1 findings / 2 usage / 3 transport (fail-open: fall back to another review route). rc=3 also logs the first ~300 chars of the raw model response to stderr, which is what makes a dead-model default (the 2026-06-12 nemotron one) diagnosable in one run instead of an hour.

Tests: bash scripts/cr/test-hermes-critic.sh is fully stubbed (HERMES_PY for the default route, a claude shim on PATH for --route claude), so it never spends the subscription usage budget. It is in the run-shell-tests.sh SKIP_LIST; run it directly.

Free-tier SOUL tuning (559)

Himmel ships one tuned free-tier identity as an opt-in asset: scripts/hermes/assets/free-tier.SOUL.md. It is tuned for the open-model free anchor (read live from scripts/cr/critics.json; the anchor model drifts as free quotas exhaust, so do not hardcode it here). It adds rigid JSON / format-obedience scaffolding, a declared Context budget: line, and fewer hedges. Open models drift from the output contract and over-report, so the free SOUL compensates where the premium GPT-anatomy prompt would instead rely on contradiction resolution. It is identity-only: project specifics stay in each context’s AGENTS.md / CLAUDE.md / vault _CLAUDE.md, never in the SOUL.

How you apply it (operator action, not himmel’s): copy the asset into the SOUL.md of your existing read-only junior profile (the default / luna_vault_guard profile from the tier-coupling section above):

Terminal window
# <home> = your hermes config home (upstream default: ~/.hermes)
cp scripts/hermes/assets/free-tier.SOUL.md <home>/profiles/<your-junior-profile>/SOUL.md
hermes gateway restart # pick up the new identity, when no session is running

Himmel never overwrites your default profile SOUL for you, and this path ships no install-himmel-profile.sh edit. The provisioner knows wire_parity_guard set / ensure / swap, all of which wire the write-allowed parity_guard; it has no supported way to wire a READ-ONLY luna_vault_guard fence onto a fresh profile (and luna_vault_guard is a hermes-side artifact himmel does not ship), so a himmel-created --free-tier profile could not be safely fenced. Applying the tuned SOUL to your existing read-only junior keeps the tier-coupling invariant intact (the free model stays read-only) without himmel wiring a fence it cannot ship.

The premium half of 559 is the himmel_agent SOUL (scripts/hermes/assets/himmel-agent.SOUL.md), which carries the GPT-anatomy markers: an explicit Precedence ladder + <spec> tags. The free SOUL deliberately carries the JSON-obedience markers instead (Context budget: + a fenced format-contract block); the two differ on those named markers by design, asserted by scripts/hermes/test-soul-markers.sh (T11).

Keeping it updated

hermes-agent is an editable git checkout (pip install -e) of NousResearch/hermes-agent living at <install-root>/hermes-agent, so a himmel git pull never updates it. /himmel-update (and /himmel-update-all) now pulls that checkout and re-runs the editable install as one of its steps; /himmel-update --check reports whether a hermes update is available without applying it. The step resolves the install root from HERMES_HOME (else ~/.hermes) and operates on its hermes-agent/ subdir; it skips cleanly and never fails the himmel update when hermes isn’t installed. After an update, restart the hermes gateway (hermes gateway restart, when no session is running) to pick up changes. On Linux, /himmel-update now does this for you: it restarts any running hermes-gateway.service (multiplexer) or hermes-gateway-*.service (per-profile) user units once the checkout actually moves, or prints the command to run by hand when systemctl isn’t available.

Gateway topology: multiplexed vs per-profile

hermes runs its gateway one of two ways:

  • Multiplexed (opt-in; this station’s shape). ONE systemd user unit, hermes-gateway.service, serves default plus every named profile out of the default profile’s home; status, PID and process state all live there. Not hermes’ default: you opt in with hermes gateway migrate --multiplex, or via hermes update’s auto-migration when nothing blocks it. hermes status shows a Serves: … line naming the profiles it is multiplexing, and hermes -p <profile> gateway status reports “running via the default-profile multiplexer” for any profile it is serving instead of duplicating the process/PID info.

  • Per-profile (rollback shape). One unit per profile, hermes-gateway-<profile>.service, each its own process. Restore it with:

    Terminal window
    hermes gateway migrate --standalone # rolls back to one unit per profile

Restart commands for both shapes:

Terminal window
systemctl --user restart hermes-gateway.service # multiplexer
systemctl --user restart hermes-gateway-<profile>.service # per-profile

A bot token belongs to exactly one profile. Two profiles polling the same TELEGRAM_BOT_TOKEN fight over getUpdates, so hermes’ migration preflight refuses to multiplex while a token is duplicated across profiles. On this station default runs no bot, so its .env carries no TELEGRAM_* keys.

Multiplexer caveat: hactl role fallback (LUNA-208). ggs-local’s hactl still honours GGS_ROLE from the environment first, but the multiplexer sets terminal children’s HERMES_HOME to the served profile’s home without forwarding that profile’s non-secret .env vars, so GGS_ROLE simply isn’t there, and hactl then falls back to reading $HERMES_HOME/ggs_role, failing closed to read-only if that file is missing.

Upstream force-pushes main. So the checkout regularly stops being a fast-forward of upstream through no fault of ours, and the update step would otherwise fail permanently and abort the whole chain. It now resyncs instead, printing upstream rewrote history — resynced <old> -> <new>, but only when the working tree is clean and no commit in the checkout was authored or committed by its own configured user.email. Anything else (local edits, a commit of yours, an unreadable repo) still FAILs and stops the chain, so your own work is never silently discarded. The pre-resync HEAD is kept at the rolling tag himmel-pre-resync. To recover, check git status first and commit or stash anything uncommitted, then git reset --hard himmel-pre-resync (it discards uncommitted work in the checkout, same as any hard reset). himmel keeps nothing inside the checkout: its tailoring is the himmel_agent profile at <install-root>/profiles/, a sibling directory, which is what makes discarding orphaned upstream commits safe.

Provider routes (wired 2026-06-12)

SUPERSEDED: since 2026-06-24 the live route is Codex via the openai-codex provider, today gpt-6.1-sol (the impl/junior profiles; the CR critic pins its own model, gpt-6.1-sol, independently; see the tier table above), not the NVIDIA/OpenRouter chain documented below. The Nemotron block is kept for history; a full re-doc of the current routing is tracked. Verify the live model with hermes profile list (Model column) or hermes model.

Context-window budgeting for multi-model lanes (2026-07-07)

Do not assume a model slug’s marketing maximum applies on every backend. Hermes budgets against the provider-enforced context window, and that value can differ for the same slug across providers. Upstream issue NousResearch/hermes-agent#27918 closed the Codex/GPT-5.5 “should be 1M” report as not a bug: live openai-codex reports and enforces gpt-5.5 at 272000 tokens, while direct OpenAI API gpt-5.5 can resolve around 1050000. Pinning Codex to 1M would over-budget prompts that the Codex backend rejects.

Operational rule: every lane that can be triggered as its own model/provider must carry its own verified maximum context window, not inherit the parent lane’s expectation.

  • himmel_agent main tier: openai-codex + gpt-5.5 was a 272K Codex window when measured on 2026-07-07. This is expected even though the direct OpenAI API slug is larger.
  • GLM / Z.ai lanes (GLM lane dormant, HIMMEL-1967): request the explicit long-context model id glm-5.2[1m] on Claude Code-compatible launchers. Bare glm-5.2 can run capped below the advertised maximum, so it is not the desired full-control lane.
  • Hermes /model and delegation switches recalculate context for the new provider/model. A top-level model.context_length override applies to that profile’s active model; it is not a generic guarantee for aliases or sibling external launchers. For custom endpoints that need explicit per-model windows, prefer custom_providers[].models.<model>.context_length in Hermes config.

Verification snippets (zero/near-zero inference):

Terminal window
hermes --profile himmel_agent profile show himmel_agent
"<hermes-venv-python>" - <<'PY'
from agent.model_metadata import get_model_context_length
print(get_model_context_length('gpt-6.1-sol', provider='openai-codex',
base_url='https://chatgpt.com/backend-api/codex', api_key=''))
print(get_model_context_length('glm-5.2[1m]', provider='custom',
base_url='https://api.z.ai/api/anthropic', api_key=''))
PY

If a context number changes, update this runbook and any lane launcher/config that budgets or summarizes context. Do not “fix” a lower provider-enforced window by hardcoding a larger one unless a live request proves the larger window is accepted on that exact backend.

Routing policy per the ticket: free routes first, fail-open down the chain with a visible note. API-key routes only.

The live config.yaml block:

model:
default: nvidia/nemotron-3-ultra-550b-a55b
provider: nvidia
base_url: https://integrate.api.nvidia.com/v1
providers: {}
fallback_providers:
- provider: openrouter
model: nvidia/nemotron-3-ultra-550b-a55b:free
#RouteProvider nameModelKey (env name in hermes .env)Why this position
1 (primary)NVIDIA NIMnvidia (built-in; aliases nim, nemotron)nvidia/nemotron-3-ultra-550b-a55bNVIDIA_API_KEYFree NIM credits; current Nemotron Ultra flagship. NIM model ids ARE vendor-prefixed; hermes doctor’s “vendor-prefixed slug” warning is a false-positive heuristic here.
2OpenRouteropenrouter (built-in)nvidia/nemotron-3-ultra-550b-a55b:freeOPENROUTER_API_KEYSame model via a different aggregator, so the NIM quota/outage fallback keeps behavior comparable.

Not wired, with reasons (recorded so a rebuild doesn’t “fix” them):

  • DeepSeek: planned but no DEEPSEEK_API_KEY on the machine yet. Add - provider: deepseek + model when a key lands.
  • Ollama local: Ollama is not installed on this machine (PATH stub only). If installed later: provider custom with base_url: http://localhost:11434/v1, no key.

providers: {} stays empty on purpose: both routes are built-in provider names, so endpoint + key-env resolution comes from hermes’s internal registry; a providers: entry is only needed for custom endpoints or per-provider timeout overrides.

Fallback semantics (hermes docs fallback-providers.md): entries tried in list order on 429-after-retries / 5xx-after-retries / immediate 401/403/404; fallback is per-turn, so the primary is retried on each new user message.

Alibaba (Model Studio) free lane — activation + wiring (2026-07-06)

A free parallel implementation/critic lane on Alibaba Cloud Model Studio (international, Singapore ap-southeast-1) running qwen models over the OpenAI-compatible endpoint. Codex stays hermes’s main/default provider; this lane never replaces it, it adds free capacity alongside. The free tier is a PAYG 90-day trial with per-model free quotas (not every model gets 1M tokens), so enable stop-on-exhaust when you activate.

Activation (chief-side, one-time)

A 403 AccessDenied.Unpurchased from the API means the Model Studio service has not been activated. It is not an identity, key, URL, or region problem. Fix it in the Singapore-pinned Model Studio console (https://modelstudio.console.alibabacloud.com/ap-southeast-1):

  1. Accept the service agreement; this auto-activates the service and grants the 90-day free quota (Singapore only).
  2. Batch-enable the models you alias below.
  3. Set stop-on-exhaust on each.

After that, the same key + URL that returned 403 returns HTTP 200.

Provider (hermes built-in)

hermes ships an alibaba-coding-plan provider, so no new provider code is needed. Key env vars (read in order): ALIBABA_CODING_PLAN_API_KEY, then DASHSCOPE_API_KEY; base override: ALIBABA_CODING_PLAN_BASE_URL (set in ~/.hermes/.env).

Workspace-endpoint caveat. The provider’s built-in default base https://coding-intl.dashscope.aliyuncs.com/v1 does not work with a workspace MaaS key (401). Only the workspace endpoint works, and it must include the /compatible-mode/v1 path: https://ws-<your-workspace-id>.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1. The China-region dashscope.aliyuncs.com endpoint 401s on an international key.

Routing (model_aliases is the lever)

hermes’s -z one-shot path auto-detects the provider from -m and overrides the config default; a bare model name like qwen3-coder-plus is not auto-detected and would fall through to the default (codex) and fail. There is no provider-qualified -m syntax. model_aliases: in ~/.hermes/config.yaml is checked first, before auto-detect, so wire aliases as a top-level block (do not touch model.default / model.provider):

model_aliases:
qwen3-coder-plus:
model: qwen3-coder-plus
provider: alibaba-coding-plan
base_url: https://ws-<your-workspace-id>.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1

Add one alias per tier you want reachable. Claude-tier parity map:

Claude tierqwen model
haikuqwen-flash
sonnetqwen-plus
opusqwen3-max / qwen3.7-max
thinking / fableqwq-plus / qwen3-235b-a22b-thinking
CR criticanchor row in scripts/cr/critics.json (per-account quota state, e.g. exhausted models swapped out, lives in the gitignored scripts/cr/critics.local.json overlay)

Validate THROUGH hermes

Don’t just probe the raw endpoint; run a one-shot through hermes so the alias + provider resolution is exercised end to end:

Terminal window
bash scripts/hermes/invoke.sh --model qwen3-coder-plus "say PONG"

Expect PONG. If it errors on codex, the alias didn’t take: check the block is top-level and the key is in .env. Do not use the -p profile route: one-shot auto-detect on -m re-overrides a profile’s provider.

Consumers

The automated review panel’s free critic is anchored via this lane to the model in the registry’s anchor row. The shipped scripts/cr/critics.json carries UNIVERSAL defaults; when YOUR account’s free quotas exhaust, record the swap in the gitignored scripts/cr/critics.local.json overlay (auto-picked-up); do not edit the shipped registry for account state (an earlier change did, and was reverted). Free-quota exhaustion is why a quota guard is tracked separately — it needs a dynamic API pull (dashboard screenshots are not automatable).

Verify after a rebuild (zero inference cost)

hermes fallback list # chain resolves: nvidia primary + 1 fallback
hermes auth list # one credential per provider, sourced from env
hermes doctor # API Connectivity: ✓ OpenRouter ✓ NVIDIA NIM

Then one paid-nothing smoke: hermes --cli -z "Reply with exactly: OK" (NIM free credits). The hermes gateway (Telegram bot) reads config at start, so restart it (hermes gateway restart, when no session is running) to pick up route changes.

Recover a broken venv pip (“No module named pip”)

uv-created venvs (the default hermes install uses uv venv) ship without pip, so the editable refresh (and any manual pip install -e .) fails with No module named pip. /himmel-update now bootstraps pip automatically (ensurepip) before the refresh; to repair by hand (older checkout, or the gateway is misbehaving after a pull):

# <venv-py> = …/hermes/hermes-agent/venv/bin/python
"<venv-py>" -m ensurepip --upgrade # restore pip into the venv
cd …/hermes/hermes-agent
"<venv-py>" -m pip install -e . # editable reinstall (picks up pulled code)
hermes gateway restart # restart the gateway to load the changes

Wiring verified 2026-06-12: all connectivity probes green (3 routes at the time, now 2); config backup at config.yaml.bak.20260612_overnight.