hermes-configuration-guide
Skill6 starsChanged 8 days agoMITView on GitHub
This skill is the map: where each Hermes extension surface is configured, how conflicts resolve, and which diagnosing-* skill to load when something breaks. Hermes is configured in YAML (config.yaml), not JSON — if you are migrating from Claude Code or Cursor, mcpServers becomes mcp_servers: and hermes import-agent claude-code migrates servers, skills, and instructions automatically. Never guess where Hermes reads its files. The home directory differs by platform and profile:
- Reads credentials
In this repository32 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- diagnosing-authSkill
- diagnosing-backupSkill
- diagnosing-bot-modeSkill
- diagnosing-browserSkill
- diagnosing-cli-tuiSkill
- diagnosing-commandsSkill
- diagnosing-configSkill
- diagnosing-cronSkill
- diagnosing-desktopSkill
- diagnosing-gatewaySkill
- diagnosing-hooksSkill
- diagnosing-host-pressureSkill
- diagnosing-mcpSkill
- diagnosing-memoriesSkill
- diagnosing-memorySkill
- diagnosing-pathSkill
- diagnosing-pluginsSkill
- diagnosing-profilesSkill
- diagnosing-providersSkill
- diagnosing-runtimeSkill
- diagnosing-secretsSkill
- diagnosing-sessionsSkill
- diagnosing-skillsSkill
- diagnosing-storageSkill
- diagnosing-triageSkill
- diagnosing-updateSkill
- diagnosing-voiceSkill
- hermes-post-updateSkill
- installing-hermesSkill
- plugin-authoringSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
14 rules. About 0 are common, 4 are distinctive, and 10 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈4
Distinctive · estimate
This author's own choices. Worth a look.
10
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 17
Never guess where Hermes reads its files.
- Very specific: line 24
Ground truth: run hermes config path — it prints the active config file's full path.
- Very specific: line 108
When a diagnosis behaves as if part of config.yaml is invisible, audit for orphans before suspecting the model: inert keys produce exactly …
- Very specific: line 122
Update lock stale, dead owner, or update failures → diagnosing-update
- Very specific: line 148
Skill not discovered vs
/commandmissing: if the skill itself is missing from the index, see diagnosing-skills first. - Very specific: line 150
Plugin not loading vs provider sub-category: if a plugin is discovered but not enabled, see diagnosing-plugins.
- Very specific: line 156
Launch/UI failure vs command surface vs app build: if the desktop app fails to launch or shows a blank window, see diagnosing-desktop.
- Very specific: line 157
Which venv/home applies where: if the wrong Python interpreter is active or the dual-venv layout is confusing, see diagnosing-path.
- Distinctive: line 161
After resolving a configuration issue, confirm the fix landed:
- Distinctive: line 173
Every diagnostic skill reports findings in this format.
- Very specific: line 199
Check disk health: smartctl -a /dev/sda (Linux) or wmic diskdrive get status (Windows)
- Distinctive: line 200
If disk is failing, replace it — no Hermes config change will fix this
- Very specific: line 201
If disk is healthy, run hermes gateway restart and check if plugins load within budget
- Very specific: line 211
Every diagnosis should end in a concrete action: a hermes <subcommand> command or a specific file + field edit, then a restart or /reload-* …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Hermes Configuration Guide
This skill is the map: where each Hermes extension surface is configured, how conflicts resolve, and which diagnosing-* skill to load when something breaks. Hermes is configured in YAML (config.yaml), not JSON — if you are migrating from Claude Code or Cursor, mcpServers becomes mcp_servers: and hermes import-agent claude-code migrates servers, skills, and instructions automatically.
Step 0 — Resolve $HERMES_HOME first
Never guess where Hermes reads its files. The home directory differs by platform and profile:
- POSIX / WSL:
~/.hermes - Native Windows:
%LOCALAPPDATA%\hermes(e.g.C:\Users\<you>\AppData\Local\hermes) —~/.hermesmay also exist there and is NOT the active home - Named profiles: each profile has its own home;
hermes -p <profile> ...andHERMES_HOME=<dir>override it profiles/default/is not the default profile:hermes_cli/profiles.py::get_profile_dir("default")returns the home root itself, never aprofiles/default/directory — and the roster only lists dirs carrying identity markers (config.yaml,.env,SOUL.md,profile.yaml,auth.json,state.db; seehermes_cli/profiles.py), explicitly skippingdefault. Do not create such a directory, read from it, or treat its contents as the default profile's state (verified live: removing one changedprofile list,-p default, andguide skillsnot at all).- Two different things are called "platform" in this guide set: the operating system (POSIX vs Windows — as above, and the
platforms:frontmatter field in skills) and the chat/messaging platform (Telegram, Discord, Slack — in slash-command permissions and pluginplatforms/sub-categories). Check which one a sentence means before acting. - Ground truth: run
hermes config path— it prints the active config file's full path.hermes config showdumps the merged config;hermes config set <section.key> <value>edits it safely. - Headless / one-shot mode: skill auto-discovery does not fire in
hermes -zruns — name the skill explicitly (hermes -z "Use the diagnosing-path skill: …"). Slash commands (/hermes-doctor) and/reload-*steps work only in a live session; headless, usehermes guide <scope>for every check and verify step. - Guide or agent? This repo (
hermes-guide) only inspects Hermes — it ships no Hermes source and is not a fork ofhermes-agent. A failure that reproduces with the plugin disabled does not by itself identify the owner; confirm thathermes-agentis responsible before filing upstream. The plugin can also surface results from Hermes commands, and disabling it can hide failures that require the integration. File defects inhermes-guide's own behavior toiap/hermes-guide.
The five surfaces at a glance
| Surface | Configured in | Inspect with |
| MCP servers | $HERMES_HOME/config.yaml → mcp_servers: (stdio: command/args/env; http: url/headers) | hermes mcp, /reload-mcp |
| Skills | $HERMES_HOME/skills/<category>/<name>/SKILL.md (source of truth); extra dirs via skills.external_dirs; hub installs via hermes skills | hermes skills list, /skills list, /reload-skills |
| Slash commands | No standalone command files. Built-in registry + every installed skill (/<skill-name>) + skill bundles ($HERMES_HOME/skill-bundles/*.yaml) + plugin commands | Type / for autocomplete, hermes bundles list |
| Hooks | Four systems: gateway hooks ($HERMES_HOME/hooks/<name>/HOOK.yaml + handler.py, gateway-only); plugin hooks (ctx.register_hook()); shell hooks (hooks: block in config.yaml); outbound webhooks (hooks.outbound:) | hermes hooks list / test / doctor |
| Plugins | $HERMES_HOME/plugins/<name>/ with plugin.yaml + register(ctx); opt-in via plugins.enabled | hermes plugins, /plugins |
| Credential pool | $HERMES_HOME/auth.json (persisted pool entries); env vars from .env / process env; $HERMES_HOME/.env for API keys | hermes auth list, hermes auth add, hermes auth status |
Instruction files (a separate system)
SOUL.md($HERMES_HOME/SOUL.md) — agent persona, always loaded as prompt slot #1. You edit it.USER.md/MEMORY.md($HERMES_HOME/memories/) — agent-written memory, injected as a frozen snapshot at session start; mid-session saves appear only next session. This is the usual cause of "it forgot what I just told it."- Project context — each source is looked up differently, and the difference decides where you must put the file (
agent/prompt_builder.py::discover_context_files, verified):
| Source | Where it is read from |
.hermes.md / HERMES.md | walked from cwd up to the git root; cwd only when there is no git root (agent/prompt_builder.py::_find_hermes_md — so a file planted in a parent like /tmp cannot be picked up) |
AGENTS.md (AGENTS.override.md wins, agents.md accepted) | merged directory chain, git root → cwd — every directory's file is injected, deeper wins |
CLAUDE.md | cwd only |
.cursorrules (+ .cursor/rules/*.mdc) | cwd only, concatenated |
The practical consequence: CLAUDE.md/.cursorrules at a repository root are ignored when you launch from a subdirectory, while AGENTS.md is not. Exactly one source wins per session, first match in the order above.
Key $HERMES_HOME inventory
config.yaml (main config + platforms:/gateway: messaging settings) · .env (secrets; documented vars override config) · gateway.json (legacy gateway fallback) · skills/ · skill-bundles/ · hooks/ (gateway hooks) · agent-hooks/ (shell-hook script convention) · plugins/ · shell-hooks-allowlist.json (shell-hook consent) · mcp-tokens/ (OAuth caches) · logs/ · state.db (sessions).
Display, attachments, and LSP notes
- Display defaults resolve per key:
display.platforms.<p>.<key>beatsdisplay.<key>, which beats built-in platform/global defaults — so a globaldisplay:block overrides only the keys it sets; unset keys still use tier defaults. Set global keys deliberately, preferdisplay.platforms.<p>for surface-specific tweaks. - Attachments stage under
attachments.storage(hermes-homeor workspace root) — a "missing attachment" report starts by checking which root is configured. - LSP post-write lint runs by default (
lsp.enabled: True) — trust covers launched/session workspaces plustrusted_workspacesentries (agent/lsp/manager.py); lint doing nothing can meanlsp.enabled: false, an unlisted non-session tree, a non-git tree, a disabled server, or missing tooling; check in that order before calling LSP broken.
Credential pool
The credential pool is Hermes's multi-credential failover system for model providers. Each provider can hold multiple credentials; when one fails (rate limit, auth error, cooldown), the pool tries the next.
Where it lives: $HERMES_HOME/auth.json (persisted entries) + environment variables from .env and the process environment.
How to inspect:
hermes auth list # all providers and their pooled credentials
hermes auth status <provider> # detailed status for one providerHow to add a credential:
hermes auth add <provider> --type api-key --label "name" # prompts securelyEnv var discovery: for API-key providers, the pool reads the provider's declared env vars plus numbered siblings. Setting OPENAI_API_KEY, OPENAI_API_KEY_2, OPENAI_API_KEY_3 in .env gives you a three-key rotation pool with no config changes. The env scanner (agent/credential_pool.py::_env_key_var_candidates) auto-discovers _2, _3, etc.
Provider IDs for API-key auth: openai-api, anthropic, openrouter, gemini, copilot, lmstudio, ollama-cloud, and others. Run hermes auth list to see which are configured.
Custom provider pools: a custom endpoint in providers: gets its own pool key. hermes auth add <custom-provider-id> adds credentials to that pool.
Common operations:
hermes auth priority <provider> <index> 0— move a credential to the front of the rotation (positional args;--priorityis not a flag here)hermes auth reset <provider>— clear exhaustion/cooldown for all of a provider's credentialshermes auth remove <provider> <index>— remove a credential from the pool
For pool credential failures (auth errors, exhaustion, cooldown), see diagnosing-providers Step 5.
Orphaned & legacy settings
Config keys that Hermes silently stopped reading are inert: they look meaningful in config.yaml, but no code consumes them — and their presence proves nothing. Temporary: the suspected key may stay while you confirm it is inert — but do not treat its presence as evidence that Hermes reads it, and do not leave it in place during an active diagnosis (an inert disabled: true on an MCP server reads as "server off" while the loader keeps it on). Permanent: move to the live replacement below and delete the dead key so it misleads neither the current investigation nor the next reader. Before trusting a key, verify it against the installed source: search for actual readers (e.g. grep -rn 'get("profile")' <hermes-agent-source>), and check whether it appears in the shipped cli-config.yaml.example (the documented schema). Known cases, last checked against the installed source at commit 8d3745a99b (present in history; 2026-09-04). Re-check before quoting a key as orphaned — the honest test is a reader grep plus the shipped cli-config.yaml.example; a key absent from that example and with no reader is inert, but a key that has gained a reader since this list was written is live again:
| Setting | Status | Live replacement |
profile: block in config.yaml (e.g. profile.description) | Orphaned — written by an older scheme, zero readers today | Per-profile profile.yaml metadata: hermes profile describe <name> --text "…" |
mcpServers (top-level, Claude-Code-style paste) | Silently not read | mcp_servers: |
disabled: inside an MCP server entry | Silently ignored (server stays enabled) — the loader reads enabled only (hermes_cli/mcp_config.py) | enabled: false |
Notes:
hermes migratecovers retired models and deprecated settings (currently the xAI migration); the siblinghermes config migrateapplies new config options. Neither detects arbitrary orphaned keys — audit for those by hand.- Profile descriptions reach a model in only two contexts: kanban task routing (the decomposer's profile roster) and dispatch guidance. Normal sessions and
hermes guide/hermes doctornever see them. - When a diagnosis behaves as if part of
config.yamlis invisible, audit for orphans before suspecting the model: inert keys produce exactly that symptom.
Routing — when something is wrong
- Vague description ("something is wrong", "it's slow", "it crashed") without naming a subsystem →
diagnosing-triage(meta-skill that routes to the correct diagnostic skill) - Runtime/launch substrate (interpreter and venv, PM tool store under
$HERMES_HOME/tools/, update locks and completion markers) →diagnosing-runtime - MCP server not connecting, tools missing, OAuth failing →
diagnosing-mcp - A skill not discovered, not triggering, shadowed, or stuck "user-modified" →
diagnosing-skills - A
/commandmissing, wrong, or overridden →diagnosing-commands - A hook not firing, blocked consent, or behaving unexpectedly →
diagnosing-hooks - A plugin not loading, not enabled, or missing capabilities →
diagnosing-plugins - Config file missing, unparseable, or orphaned settings →
diagnosing-config - Storage / disk pressure, state.db bloat, or cleanup →
diagnosing-storage - Session runaway, loop signature, or context bloat →
diagnosing-sessions - Update lock stale, dead owner, or update failures →
diagnosing-update - Memory store over-limit, duplicates, or mis-targeted entries →
diagnosing-memories - Backup creation failures, restore errors, checkpoint corruption, or import/export problems →
diagnosing-backup - Multi-profile issues — profile not found, config not isolated, profile switching failures, clone/sync-imports problems →
diagnosing-profiles - Secret and credential management issues — secret sources not resolving, vault locked, egress firewall blocking, credential pool failures →
diagnosing-secrets - Auth/API failures on hub installs (
Could not fetch from any source, GitHub 401, rate-limit 403) →diagnosing-auth; model-provider credential pool issues (OpenAI/Anthropic/OpenRouter key failures, exhaustion, cooldown) →diagnosing-providersStep 5 - Memory not persisting ("it forgot"), an external memory provider silently unavailable, or
MEMORY.md/USER.mderrors →diagnosing-memory - Desktop app build/launch failures, wrong backend, or blank window →
diagnosing-desktop; terminal/TUI rendering issues arediagnosing-cli-tui, not desktop - Model provider issues — custom endpoints flooding the picker with hundreds of models,
discover_modelsmisbehaving, persisted catalogs bloatingconfig.yaml, or provider/auth failures →diagnosing-providers - Script/path/venv problems (wrong interpreter — on PM-era installs the launcher runs the PM-store Python, not the shell's; on older checkouts
venv/bin/pythonmissing or the dual.venv/venvlayout) →diagnosing-path - Terminal/TUI issues on native Windows (misrendering, themes, indicators, launch failures) →
diagnosing-cli-tui; on POSIX/WSL there is no dedicated skill yet — start withhermes doctorand thedisplay:block ofconfig.yaml - A bot/agent profile not answering, a per-bot
config.yamlproblem, or a routine not firing for a bot →diagnosing-bot-mode - Browser automation not connecting, Chrome/CDP version problems, or a missing Playwright →
diagnosing-browser - A scheduled job not firing, running at the wrong time, or failing to deliver →
diagnosing-cron - Messaging-platform connectivity, allowlists, or a platform not receiving replies →
diagnosing-gateway - Several surfaces failing at once, or adapters discarded after a load timeout — suspect host resource pressure before per-surface config →
diagnosing-host-pressure - Voice mode not transcribing or replying, or voice-message handling problems →
diagnosing-voice
Disambiguation — when two skills can claim the same symptom
Canonical list: when several skills match, load the first-named skill first, then the second — order here is priority, not prose. Multi-surface faults go to host-pressure before any feature row below, no matter which symptom matched first.
- Several faults at once, intermittently: load
diagnosing-host-pressurefirst — intermittent multi-surface failures are the signature of resource pressure, which mimics unrelated config bugs. - Skill not discovered vs
/commandmissing: if the skill itself is missing from the index, seediagnosing-skillsfirst; if the skill is present but its/commandis missing or shadowed, seediagnosing-commandsinstead. - MCP server up but no tools vs provider configured but unavailable: load
diagnosing-mcpfirst (the MCP server is the more specific failure); if the MCP server connects fine but the model provider is the problem, loaddiagnosing-providers. - Plugin not loading vs provider sub-category: if a plugin is discovered but not enabled, see
diagnosing-plugins; if a provider sub-category (e.g.context.engine,image_gen.provider) is misconfigured, seediagnosing-providers. - Memory not persisting vs provider store unavailable: load
diagnosing-memory(it owns both built-in and external memory diagnosis). - Hub install failing with "not found": load
diagnosing-authfirst — a dead token degrades every source adapter to "not found" at once. - Wrong interpreter or confusing venv layout: load
diagnosing-pathbefore any feature skill — path issues cascade into feature-looking failures. - Hermes itself broken (won't start, crashes on launch): load
installing-hermesbefore anydiagnosing-*skill — a broken install cannot be diagnosed. - Bot not responding: load
diagnosing-gatewaybeforediagnosing-bot-mode— gateway connectivity is a prerequisite for bot profiles. - Launch/UI failure vs command surface vs app build: if the desktop app fails to launch or shows a blank window, see
diagnosing-desktop; if the TUI misrenders or shows unreadable indicators on native Windows, seediagnosing-cli-tui; if a/commandis missing or overridden, seediagnosing-commands. - Which venv/home applies where: if the wrong Python interpreter is active or the dual-venv layout is confusing, see
diagnosing-path; if the desktop app's backend resolution is wrong, seediagnosing-desktop; if the install itself is broken, seeinstalling-hermes.
Verification
After resolving a configuration issue, confirm the fix landed:
hermes config path
hermes doctor
hermes plugins listPass: hermes config path points to the expected $HERMES_HOME/config.yaml; hermes doctor reports no errors; plugins list shows expected plugins.
Fail: Config path unexpected — check HERMES_HOME env var and profile selection; doctor errors — follow the matching diagnosing-* skill from the routing table above.
Every diagnostic skill reports findings in this format. The model uses this structure when presenting results to the user.
Summary
One or two sentences in plain language. What is wrong, in terms the user understands. Quote the upstream error text exactly whenever it is the evidence — rewording it hides what the surface actually said; keep bare file paths and command output below the headline, not inside the summary. For broken/unknown findings, carry the stable finding id and the envelope's impact copy too.
Example: "Your Hermes gateway is not responding because the Telegram plugin failed to load. The plugin timed out during startup, likely due to high disk latency."
Findings
Severity-ordered list. Each finding has:
- Severity: HIGH (blocks core functionality), MEDIUM (degraded but usable), LOW (cosmetic or informational)
- What: The specific problem
- Evidence: The command output, file content, or log line that proves it
Example:
| Severity | What | Evidence |
| HIGH | Telegram plugin discarded after load timeout | Plugin 'telegram-platform' called register_platform() after its load timed out; ignored |
| MEDIUM | Disk latency causing plugin load failures | probe wall time: 47s (threshold: 20s) |
Recommended Fix
One concrete action the user can take. Include the exact command or file edit. If the fix is not obvious, explain why this action and not another.
Example:
- Check disk health:
smartctl -a /dev/sda(Linux) orwmic diskdrive get status(Windows) - If disk is failing, replace it — no Hermes config change will fix this
- If disk is healthy, run
hermes gateway restartand check if plugins load within budget
References
File paths, line numbers, and command output that support the findings. This is for the user to verify, not for the model to re-run.
Example:
$HERMES_HOME/logs/errors.log— plugin load timeout linesskills/diagnosing-host-pressure/scripts/host_pressure_probe.sh— probe output
Every diagnosis should end in a concrete action: a hermes <subcommand> command or a specific file + field edit, then a restart or /reload-* to apply.
Facts re-verified 2026-10-13 against upstream source at the declared baseline cedf4a3d78675283fa93e4e6ea2d6212bf414667: the earlier-cited commit 8d3745a99b exists in history (2026-09-04); the profile: block has no config reader (the profile hits in the tree are session records, not this block); an MCP entry's disabled: key is unread — enabled is the control (hermes_cli/mcp_config.py); project context is looked up per source, not by one rule — .hermes.md/HERMES.md walk cwd→git root (agent/prompt_builder.py::_find_hermes_md), AGENTS.md is a merged chain git root→cwd, and CLAUDE.md/.cursorrules are cwd-only (agent/prompt_builder.py::discover_context_files, _hermes_md_candidates/_find_hermes_md); the former bare line citation for project-context discovery was re-pointed to those symbols at 2f6170bf (2026-09-22, drift #103); mcp-tokens/, profile describe, and import-agent all exist. Credential pool (re-verified 2026-10-13 against the pinned baseline f97608f): agent/credential_pool.py — numbered-sibling discovery plus _seed_from_env ingesting API-key providers from env vars into the pool; pool entries persist in auth.json as env:-sourced references re-hydrated on load. Provider registry (hermes_cli/auth.py, openai-api entry): API-key provider keyed on OPENAI_API_KEY with optional OPENAI_BASE_URL override. hermes auth subcommands (list/add/status/reset/priority/remove, all positional — --priority is an add flag only) verified against the installed CLI. Profile behavior re-checked 2026-10-15 (hermes_cli/profiles.py::get_profile_dir, roster skips marker-less dirs and default) plus live ghost-dir removal. Display/attachments/LSP notes verified 2026-10-15 against the installed source (per-surface code defaults, attachments.storage, default-enabled lsp: block with optional trusted_workspaces list). Disambiguation list canonical as of 2026-10-16 (absorbed the triage §4 priority rules verbatim). Report-format wording amended 2026-10-23 (#334): upstream error text is evidence and is quoted verbatim; file paths and command output stay below the headline; broken/unknown findings also carry the stable finding id and the envelope's impact copy. Wording change only — no host facts re-checked, footer date not advanced. Re-verify before reuse.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

