hermes-agent
Skill75 starsChanged 4 months agoMITView on GitHub
hermes-agent — Configure, extend, or contribute to Hermes Agent.
- Pipes a download into a shell
- Reads credentials
- Deletes or force-pushes
- Installs packages
We split this skill into the rules it gives an agent
58 rules. 0 are common, 26 are distinctive, and 32 are very specific to this project.
0
Common
Most of the 19 edited versions we read keep these.
26
Distinctive
This author's own choices. Worth a look.
32
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 90
No subcommand defaults to chat.
- Distinctive: line 199
When a cron job reports errors:
- Very specific: line 403
If target_ratio is too low relative to threshold (OEM's 0.20 vs 0.50 = 4x gap), every compression cycle eats a big chunk of context.
- Distinctive: line 408
Avoid equal values — they produce wasted compute on minimal gain.
- Distinctive: line 588
Run additional Hermes processes as fully independent subprocesses — separate sessions, tools, and environments.
- Very specific: line 663
Use
-w(worktree mode): when spawning agents that edit code — prevents git conflicts - Very specific: line 687
Not durable: If the parent is interrupted, the child is cancelled.
- Very specific: line 723
Scope: only touches skills with created_by: "agent" provenance.
- Very specific: line 790
Diagnosing keybindings: Run python scripts/keystroke_diagnostic.py (user-local — verify it exists) (repo root) to see exactly how …
- Very specific: line 833
Use -n 0, not -n 4 — pyproject.toml's default addopts already includes -n, and the wrapper's CI-parity guarantees don't apply off POSIX.
- Very specific: line 842
Use the existing skip-pattern style (sys.platform == "win32" or sys.platform.startswith("win")) to stay consistent with the rest of the …
- Very specific: line 861
Check stt.enabled: true in config.yaml
- Very specific: line 862
Verify provider: pip install faster-whisper or set API key
- Very specific: line 873
Check .env has the right API key
- Very specific: line 880
If you want true auto behavior, leave model.context_length unset.
- Very specific: line 881
If you need to force a fixed window, set model.context_length explicitly.
- Very specific: line 886
Remove model.context_length from config.yaml, or set it to 0/null if the current code path treats those as "unset".
- Distinctive: line 887
Start a new session after the change.
- Very specific: line 895
Do NOT set model.context_length: auto unless the current Hermes version explicitly supports that literal.
- Very specific: line 897
When a user asks for "auto," do not overwrite their config with a fresh fixed number while troubleshooting.
- Very specific: line 898
If the displayed context length does not match expectations, inspect the live config and remember that .env model/provider overrides can …
- Distinctive: line 922
Discord bot silent: Must enable Message Content Intent in Bot → Privileged Gateway Intents.
- Very specific: line 923
Slack bot only works in DMs: Must subscribe to message.channels event.
- Distinctive: line 934
If you see repeated POST /v1/chat/completions with 2-message conversations on the same model, this is almost always a stuck agent loop or …
- Very specific: line 939
Check Hermes gateway logs: tail ~/.hermes/logs/gateway.log | grep "chat/completions"
- Distinctive: line 940
If nothing shows up recently, the local Hermes instance isn't the source.
- Distinctive: line 943
Look for stuck processes:
- Distinctive: line 946
If you're using Hermes Desktop in remote-gateway mode, close it temporarily to see if the spam stops.
- Distinctive: line 950
If logs show repeated internal calls to /v1/chat/completions from the backend process, that's a bug — disable or kill the backend until …
- Very specific: line 955
If the pattern persists after killing obvious culprits, escalate to checking config.yaml and .env for any custom health-check or probe …
- Very specific: line 956
If auxiliary tasks (vision, compression, session_search) fail silently, the auto provider can't find a backend.
- Very specific: line 965
If the local vision model has parallel: 1, a timed-out uncapped request can occupy its only slot and make later tests queue.
- Very specific: line 971
If you set a local compression/summary model (e.g., via compression.summary_model) but Hermes still uses the old provider or silently fails:
- Distinctive: line 978
No log entry appears for compression
- Distinctive: line 979
No API call is made
- Very specific: line 1072
All handlers must return JSON strings.
- Very specific: line 1076
Add CommandDef to COMMAND_REGISTRY in hermes_cli/commands.py
- Very specific: line 1077
Add handler in cli.py → process_command()
- Distinctive: line 1080
All consumers (help text, autocomplete, Telegram menu, Slack mapping) derive from the central registry automatically.
- Distinctive: line 1102
Run full suite before pushing any change
- Very specific: line 1103
Use -o 'addopts=' to clear any baked-in pytest flags
- Very specific: line 1112
Use -n 0 (not -n 4) because pyproject.toml's default addopts already includes -n, and the wrapper's CI-parity story doesn't apply off-POSIX.
- Very specific: line 1136
Key fact for prompt authoring: when TERMINAL_ENV != "local", *every* file tool (read_file, write_file, patch, search_files) runs inside the …
- Very specific: line 1157
Use get_hermes_home() from hermes_constants for all paths (profile-safe)
- Distinctive: line 1167
Always use one of these for configuration changes:
- Distinctive: line 1173
Update auxiliary.<task>.provider and .model to target the new provider.
- Distinctive: line 1174
Always leave vision unchanged unless explicitly asked.
- Distinctive: line 1177
Use this when routing auxiliary tasks (compression, web_extract, skills_hub, etc.) to a specific provider/endpoint.
- Very specific: line 1178
If direct writes to config.yaml are blocked, use:
- Distinctive: line 1184
When adding a new provider (e.g., Unsloth on another machine):
- Distinctive: line 1185
Use a clear key like custom:my-local-server.
- Distinctive: line 1197
Update config to reflect the actual model name from the endpoint.
- Distinctive: line 1202
After config changes, verify via:
- Distinctive: line 1220
Verify with readback before reporting success.
- Distinctive: line 1228
Before declaring any Hermes config/setup task complete:
- Distinctive: line 1231
Run the command/query and confirm it matches what you promised (hermes status, hermes tools, etc.).
- Very specific: line 1235
Do not overwrite canonical docs solely on agent reasoning.
- Distinctive: line 1246
Wait for explicit go-ahead before executing.
“Common” is measured: kept by at least 6 in 10 of the 19 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Hermes Agent
Hermes Agent is an open-source AI agent framework by Nous Research that runs in your terminal, messaging platforms, and IDEs. It belongs to the same category as Claude Code (Anthropic), Codex (OpenAI), and OpenClaw — autonomous coding and task-execution agents that use tool calling to interact with your system. Hermes works with any LLM provider (OpenRouter, Anthropic, OpenAI, DeepSeek, local models, and 15+ others) and runs on Linux, macOS, and WSL.
What makes Hermes different:
- Self-improving through skills — Hermes learns from experience by saving reusable procedures as skills. When it solves a complex problem, discovers a workflow, or gets corrected, it can persist that knowledge as a skill document that loads into future sessions. Skills accumulate over time, making the agent better at your specific tasks and environment.
- Persistent memory across sessions — remembers who you are, your preferences, environment details, and lessons learned. Pluggable memory backends (built-in, Honcho, Mem0, and more) let you choose how memory works.
- Multi-platform gateway — the same agent runs on Telegram, Discord, Slack, WhatsApp, Signal, Matrix, Email, and 10+ other platforms with full tool access, not just chat.
- Provider-agnostic — swap models and providers mid-workflow without changing anything else. Credential pools rotate across multiple API keys automatically.
- Profiles — run multiple independent Hermes instances with isolated configs, sessions, skills, and memory.
- Extensible — plugins, MCP servers, custom tools, webhook triggers, cron scheduling, and the full Python ecosystem.
People use Hermes for software development, research, system administration, data analysis, content creation, home automation, and anything else that benefits from an AI agent with persistent context and full system access.
This skill helps you work with Hermes Agent effectively — setting it up, configuring features, spawning additional agent instances, troubleshooting issues, finding the right commands and settings, and understanding how the system works when you need to extend or contribute to it.
Docs: https://hermes-agent.nousresearch.com/docs/
Quick Start
# Install
curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash
# Interactive chat (default)
hermes
# Single query
hermes chat -q "What is the capital of France?"
# Setup wizard
hermes setup
# Change model/provider
hermes model
# Check health
hermes doctorCLI Reference
Global Flags
hermes [flags] [command]
--version, -V Show version
--resume, -r SESSION Resume session by ID or title
--continue, -c [NAME] Resume by name, or most recent session
--worktree, -w Isolated git worktree mode (parallel agents)
--skills, -s SKILL Preload skills (comma-separate or repeat)
--profile, -p NAME Use a named profile
--yolo Skip dangerous command approval
--pass-session-id Include session ID in system promptNo subcommand defaults to chat.
Chat
hermes chat [flags]
-q, --query TEXT Single query, non-interactive
-m, --model MODEL Model (e.g. anthropic/claude-sonnet-4)
-t, --toolsets LIST Comma-separated toolsets
--provider PROVIDER Force provider (openrouter, anthropic, nous, etc.)
-v, --verbose Verbose output
-Q, --quiet Suppress banner, spinner, tool previews
--checkpoints Enable filesystem checkpoints (/rollback)
--source TAG Session source tag (default: cli)Configuration
hermes setup [section] Interactive wizard (model|terminal|gateway|tools|agent)
hermes model Interactive model/provider picker
hermes config View current config
hermes config edit Open config.yaml in $EDITOR
hermes config set KEY VAL Set a config value
hermes config path Print config.yaml path
hermes config env-path Print .env path
hermes config check Check for missing/outdated config
hermes config migrate Update config with new options
hermes auth Interactive credential manager
hermes auth add PROVIDER Add OAuth or API-key credential (e.g. nous, openai-codex, qwen-oauth)
hermes auth list List stored credentials
hermes auth remove PROVIDER Remove a stored credential
hermes doctor [--fix] Check dependencies and config
hermes status [--all] Show component statusTools & Skills
hermes tools Interactive tool enable/disable (curses UI)
hermes tools list Show all tools and status
hermes tools enable NAME Enable a toolset
hermes tools disable NAME Disable a toolset
hermes skills list List installed skills
hermes skills search QUERY Search the skills hub
hermes skills install ID Install a skill (ID can be a hub identifier OR a direct https://…/SKILL.md URL; pass --name to override when frontmatter has no name)
hermes skills inspect ID Preview without installing
hermes skills config Enable/disable skills per platform
hermes skills check Check for updates
hermes skills update Update outdated skills
hermes skills uninstall N Remove a hub skill
hermes skills publish PATH Publish to registry
hermes skills browse Browse all available skills
hermes skills tap add REPO Add a GitHub repo as skill sourceMCP Servers
hermes mcp serve Run Hermes as an MCP server
hermes mcp add NAME Add an MCP server (--url or --command)
hermes mcp remove NAME Remove an MCP server
hermes mcp list List configured servers
hermes mcp test NAME Test connection
hermes mcp configure NAME Toggle tool selectionGateway (Messaging Platforms)
hermes gateway run Start gateway foreground
hermes gateway install Install as background service
hermes gateway start/stop Control the service
hermes gateway restart Restart the service
hermes gateway status Check status
hermes gateway setup Configure platformsSupported platforms: Telegram, Discord, Slack, WhatsApp, Signal, Email, SMS, Matrix, Mattermost, Home Assistant, DingTalk, Feishu, WeCom, BlueBubbles (iMessage), Weixin (WeChat), API Server, Webhooks. Open WebUI connects via the API Server adapter.
Platform docs: https://hermes-agent.nousresearch.com/docs/user-guide/messaging/
Sessions
hermes sessions list List recent sessions
hermes sessions browse Interactive picker
hermes sessions export OUT Export to JSONL
hermes sessions rename ID T Rename a session
hermes sessions delete ID Delete a session
hermes sessions prune Clean up old sessions (--older-than N days)
hermes sessions stats Session store statisticsCron Jobs
hermes cron list List jobs (--all for disabled)
hermes cron create SCHED Create: '30m', 'every 2h', '0 9 * * *'
hermes cron edit ID Edit schedule, prompt, delivery
hermes cron pause/resume ID Control job state
hermes cron run ID Trigger on next tick
hermes cron remove ID Delete a job
hermes cron status Scheduler statusTroubleshooting Cron Errors
When a cron job reports errors:
- Check if the script exists. For
no_agent: truejobs, the script path is absolute — verify it withls <path>. If missing, the job is orphaned and should be removed. - Check the last run status.
cronjob action='list'showslast_statusandlast_run_at— a pattern of repeated errors on a stale job means it's abandoned. - Distinguish ghost jobs from real failures. A cron job that references a non-existent script (e.g.,
mission-tick.sh) is not a runtime bug — it's an orphaned job from a deleted project. Remove it withcronjob action='remove'. - Check for paused vs active state. Paused jobs won't run; scheduled jobs will. Don't waste time debugging a paused job.
Webhooks
hermes webhook subscribe N Create route at /webhooks/<name>
hermes webhook list List subscriptions
hermes webhook remove NAME Remove a subscription
hermes webhook test NAME Send a test POSTProfiles
hermes profile list List all profiles
hermes profile create NAME Create (--clone, --clone-all, --clone-from)
hermes profile use NAME Set sticky default
hermes profile delete NAME Delete a profile
hermes profile show NAME Show details
hermes profile alias NAME Manage wrapper scripts
hermes profile rename A B Rename a profile
hermes profile export NAME Export to tar.gz
hermes profile import FILE Import from archiveCredential Pools
hermes auth add Interactive credential wizard
hermes auth list [PROVIDER] List pooled credentials
hermes auth remove P INDEX Remove by provider + index
hermes auth reset PROVIDER Clear exhaustion statusOther
hermes insights [--days N] Usage analytics
hermes update Update to latest version
hermes pairing list/approve/revoke DM authorization
hermes plugins list/install/remove Plugin management
hermes honcho setup/status Honcho memory integration (requires honcho plugin)
hermes memory setup/status/off Memory provider config
hermes completion bash|zsh Shell completions
hermes acp ACP server (IDE integration)
hermes claw migrate Migrate from OpenClaw
hermes uninstall Uninstall HermesSlash Commands (In-Session)
Type these during an interactive chat session. New commands land fairly
often; if something below looks stale, run /help in-session for the
authoritative list or see the live slash commands reference.
The registry of record is hermes_cli/commands.py for the classic Python CLI and gateway surfaces. The separate TypeScript --tui also has its own slash registry under ui-tui/src/app/slash/commands/; check both before adding or renaming a command. As of the current TUI, /switch is an alias of /sessions (along with /session and /resume). Registering /switch as a Python-side model command creates a split-brain collision: autocomplete/help may describe model switching while hermes --tui executes the session picker. Use /model for model switching or choose a non-conflicting command name.
Session Control
/new (/reset) Fresh session
/clear Clear screen + new session (CLI)
/retry Resend last message
/undo Remove last exchange
/title [name] Name the session
/compress Manually compress context
/stop Kill background processes
/rollback [N] Restore filesystem checkpoint
/snapshot [sub] Create or restore state snapshots of Hermes config/state (CLI)
/background <prompt> Run prompt in background
/queue <prompt> Queue for next turn
/steer <prompt> Inject a message after the next tool call without interrupting
/agents (/tasks) Show active agents and running tasks
/resume [name] Resume a named session
/goal [text|sub] Set a standing goal Hermes works on across turns until achieved
(subcommands: status, pause, resume, clear)
/redraw Force a full UI repaint (CLI)Configuration
/config Show config (CLI)
/model [name] Show or change model
/personality [name] Set personality
/reasoning [level] Set reasoning (none|minimal|low|medium|high|xhigh|show|hide)
/verbose Cycle: off → new → all → verbose
/voice [on|off|tts] Voice mode
/yolo Toggle approval bypass
/busy [sub] Control what Enter does while Hermes is working (CLI)
(subcommands: queue, steer, interrupt, status)
/indicator [style] Pick the TUI busy-indicator style (CLI)
(styles: kaomoji, emoji, unicode, ascii)
/footer [on|off] Toggle gateway runtime-metadata footer on final replies
/skin [name] Change theme (CLI)
/statusbar Toggle status bar (CLI)Tools & Skills
/tools Manage tools (CLI)
/toolsets List toolsets (CLI)
/skills Search/install skills (CLI)
/skill <name> Load a skill into session
/reload-skills Re-scan ~/.hermes/skills/ for added/removed skills
/reload Reload .env variables into the running session (CLI)
/reload-mcp Reload MCP servers
/cron Manage cron jobs (CLI)
/curator [sub] Background skill maintenance (status, run, pin, archive, …)
/kanban [sub] Multi-profile collaboration board (tasks, links, comments)
/plugins List plugins (CLI)Gateway
/approve Approve a pending command (gateway)
/deny Deny a pending command (gateway)
/restart Restart gateway (gateway)
/sethome Set current chat as home channel (gateway)
/update Update Hermes to latest (gateway)
/topic [sub] Enable or inspect Telegram DM topic sessions (gateway)
/platforms (/gateway) Show platform connection status (gateway)Utility
/branch (/fork) Branch the current session
/fast Toggle priority/fast processing
/browser Open CDP browser connection
/history Show conversation history (CLI)
/save Save conversation to file (CLI)
/copy [N] Copy the last assistant response to clipboard (CLI)
/paste Attach clipboard image (CLI)
/image Attach local image file (CLI)Info
/help Show commands
/commands [page] Browse all commands (gateway)
/usage Token usage
/insights [days] Usage analytics
/gquota Show Google Gemini Code Assist quota usage (CLI)
/status Session info (gateway)
/profile Active profile info
/debug Upload debug report (system info + logs) and get shareable linksExit
/quit (/exit, /q) Exit CLIKey Paths & Config
~/.hermes/config.yaml Main configuration
~/.hermes/.env API keys and secrets
| `~/.hermes/skills/` | Installed skills |
| `~/.hermes/skills/DIRECTORY.md` | Generated index of installed skills; regenerate with `python ~/.hermes/scripts/regen_skill_directory.py` (user-local — verify it exists) |
| `~/.hermes/sessions/` | Gateway routing index, request dumps, *.jsonl transcripts (and optional per-session JSON snapshots when sessions.write_json_snapshots: true) |
~/.hermes/state.db Canonical session store (SQLite + FTS5)
~/.hermes/logs/ Gateway and error logs
~/.hermes/auth.json OAuth tokens and credential pools
~/.hermes/hermes-agent/ Source code (if git-installed)Profiles use ~/.hermes/profiles/<name>/ with the same layout.
Config Sections
Edit with hermes config edit or hermes config set section.key value.
| Section | Key options |
model | default, provider, base_url, api_key, context_length |
agent | max_turns (90), tool_use_enforcement |
terminal | backend (local/docker/ssh/modal), cwd, timeout (180) |
compression | enabled, threshold (0.50), target_ratio (0.20) — see Context Compression Tuning below |
display | skin, tool_progress, show_reasoning, show_cost |
stt | enabled, provider (local/groq/openai/mistral) |
tts | provider (edge/elevenlabs/openai/minimax/mistral/neutts) |
memory | memory_enabled, user_profile_enabled, provider |
security | tirith_enabled, website_blocklist |
delegation | model, provider, base_url, api_key, max_iterations (50), reasoning_effort |
checkpoints | enabled, max_snapshots (50) |
Full config reference: https://hermes-agent.nousresearch.com/docs/user-guide/configuration
Context Compression Tuning
Hermes compresses older messages when context nears the model's limit. Two settings control this — they serve different purposes and should NOT be equal:
threshold(OEM default 0.50) — when compression activates. Context usage exceeds this ratio ofcontext_length, and Hermes starts summarizing older messages to make room.target_ratio(OEM default 0.20) — how aggressively to compress down to. A lower number means more aggressive compression, but setting it too low causes constant re-triggering because context fills back up quickly after each summary cycle.
The relationship matters: threshold must be higher than target_ratio. If they're equal (e.g., both 0.80), compression triggers at the threshold and tries to compress to the same value — it does summarization work with almost zero gain, wasting tokens on summaries that barely move the needle.
If target_ratio is too low relative to threshold (OEM's 0.20 vs 0.50 = 4x gap), every compression cycle eats a big chunk of context. This creates constant churn: compress → fill up again quickly → compress again, burning tokens on repeated summaries.
Tuning for long-context models (96K+ effective):
- Set
thresholdclose to where your model's quality starts degrading (the "long context tail"). For Qwen3.6-27B at 96K effective: 0.85–0.90. - Set
target_ratiobelow threshold with enough gap to create meaningful room, but not so low that it causes thrashing. 0.65–0.75 is reasonable for most setups. - Avoid equal values — they produce wasted compute on minimal gain.
Example tuned config:
compression:
enabled: true
threshold: 0.85 # wait until context is genuinely full
target_ratio: 0.70 # compress down to leave room before next cycleProviders
20+ providers supported. Set via hermes model or hermes setup.
| Provider | Auth | Key env var |
| OpenRouter | API key | OPENROUTER_API_KEY |
| Anthropic | API key | ANTHROPIC_API_KEY |
| Nous Portal | OAuth | hermes auth |
| OpenAI Codex | OAuth | hermes auth |
| GitHub Copilot | Token | COPILOT_GITHUB_TOKEN |
| Google Gemini | API key | GOOGLE_API_KEY or GEMINI_API_KEY |
| DeepSeek | API key | DEEPSEEK_API_KEY |
| xAI / Grok | API key | XAI_API_KEY |
| Hugging Face | Token | HF_TOKEN |
| Z.AI / GLM | API key | GLM_API_KEY |
| MiniMax | API key | MINIMAX_API_KEY |
| MiniMax CN | API key | MINIMAX_CN_API_KEY |
| Kimi / Moonshot | API key | KIMI_API_KEY |
| Alibaba / DashScope | API key | DASHSCOPE_API_KEY |
| Xiaomi MiMo | API key | XIAOMI_API_KEY |
| Kilo Code | API key | KILOCODE_API_KEY |
| OpenCode Zen | API key | OPENCODE_ZEN_API_KEY |
| OpenCode Go | API key | OPENCODE_GO_API_KEY |
| Qwen OAuth | OAuth | hermes auth add qwen-oauth |
| Custom endpoint | Config | model.base_url + model.api_key in config.yaml |
| GitHub Copilot ACP | External | COPILOT_CLI_PATH or Copilot CLI |
Full provider docs: https://hermes-agent.nousresearch.com/docs/integrations/providers
Toolsets
Enable/disable via hermes tools (interactive) or hermes tools enable/disable NAME.
| Toolset | What it provides |
web | Web search and content extraction |
search | Web search only (subset of web) |
browser | Browser automation (Browserbase, Camofox, or local Chromium) |
terminal | Shell commands and process management |
file | File read/write/search/patch |
code_execution | Sandboxed Python execution where the active profile permits it; unavailable in the default profile |
vision | Image analysis |
image_gen | AI image generation |
video | Video analysis and generation |
tts | Text-to-speech |
skills | Skill browsing and management |
memory | Persistent cross-session memory |
session_search | Search past conversations |
delegation | Subagent task delegation |
cronjob | Scheduled task management |
clarify | Ask user clarifying questions |
messaging | Cross-platform message sending |
todo | In-session task planning and tracking |
kanban | Multi-agent work-queue tools (gated to workers) |
debugging | Extra introspection/debug tools (off by default) |
safe | Minimal, low-risk toolset for locked-down sessions |
spotify | Spotify playback and playlist control |
homeassistant | Smart home control (off by default) |
discord | Discord integration tools |
discord_admin | Discord admin/moderation tools |
feishu_doc | Feishu (Lark) document tools |
feishu_drive | Feishu (Lark) drive tools |
yuanbao | Yuanbao integration tools |
rl | Reinforcement learning tools (off by default) |
moa | Mixture of Agents (off by default) |
Full enumeration lives in toolsets.py as the TOOLSETS dict; _HERMES_CORE_TOOLS is the default bundle most platforms inherit from.
Tool changes take effect on /reset (new session). They do NOT apply mid-conversation to preserve prompt caching.
Security & Privacy Toggles
Common "why is Hermes doing X to my output / tool calls / commands?" toggles — and the exact commands to change them. Most of these need a fresh session (/reset in chat, or start a new hermes invocation) because they're read once at startup.
Secret redaction in tool output
Secret redaction is on by default — tool output (terminal stdout, read_file, web content, subagent summaries, etc.) is scanned for strings that look like API keys, tokens, and secrets before it enters the conversation context and logs. Leave it enabled for normal use:
hermes config set security.redact_secrets true # keep enabled globallyRestart required. security.redact_secrets is snapshotted at import time — toggling it mid-session (e.g. via export HERMES_REDACT_SECRETS=false from a tool call) will NOT take effect for the running process. Tell the user to change it in config from a terminal, then start a new session. This is deliberate — it prevents an LLM from flipping the toggle on itself mid-task.
Disable only when you deliberately need raw credential-like strings for debugging or redactor development:
hermes config set security.redact_secrets falseCredential-bearing file edits: Do not use patch on files such as voice configs, cron JSON, or integration settings when nearby lines may contain plaintext credentials. Unified diffs can echo unchanged surrounding secrets even when ordinary read output is redacted. Use a narrowly scoped script that changes the exact JSON/YAML field without printing file contents, then verify only the non-secret field value or a boolean comparison.
PII redaction in gateway messages
Separate from secret redaction. When enabled, the gateway hashes user IDs and strips phone numbers from the session context before it reaches the model:
hermes config set privacy.redact_pii true # enable
hermes config set privacy.redact_pii false # disable (default)Command approval prompts
By default (approvals.mode: manual), Hermes prompts the user before running shell commands flagged as destructive (rm -rf, git reset --hard, etc.). The modes are:
manual— always prompt (default)smart— use an auxiliary LLM to auto-approve low-risk commands, prompt on high-riskoff— skip all approval prompts (equivalent to--yolo)
hermes config set approvals.mode smart # recommended middle ground
hermes config set approvals.mode off # bypass everything (not recommended)Per-invocation bypass without changing config:
hermes --yolo …export HERMES_YOLO_MODE=1
Note: YOLO / approvals.mode: off does NOT turn off secret redaction. They are independent.
Shell hooks allowlist
Some shell-hook integrations require explicit allowlisting before they fire. Managed via ~/.hermes/shell-hooks-allowlist.json — prompted interactively the first time a hook wants to run.
Disabling the web/browser/image-gen tools
To keep the model away from network or media tools entirely, open hermes tools and toggle per-platform. Takes effect on next session (/reset). See the Tools & Skills section above.
Voice & Transcription
STT (Voice → Text)
Voice messages from messaging platforms are auto-transcribed.
Provider priority (auto-detected):
- Local faster-whisper — free, no API key:
pip install faster-whisper - Groq Whisper — free tier: set
GROQ_API_KEY - OpenAI Whisper — paid: set
VOICE_TOOLS_OPENAI_KEY - Mistral Voxtral — set
MISTRAL_API_KEY
Config:
stt:
enabled: true
provider: local # local, groq, openai, mistral
local:
model: base # tiny, base, small, medium, large-v3TTS (Text → Voice)
| Provider | Env var | Free? |
| Edge TTS | None | Yes (default) |
| ElevenLabs | ELEVENLABS_API_KEY | Free tier |
| OpenAI | VOICE_TOOLS_OPENAI_KEY | Paid |
| MiniMax | MINIMAX_API_KEY | Paid |
| Mistral (Voxtral) | MISTRAL_API_KEY | Paid |
| NeuTTS (local) | None (pip install neutts[all] + espeak-ng) | Free |
Voice commands: /voice on (voice-to-voice), /voice tts (always voice), /voice off.
Spawning Additional Hermes Instances
Run additional Hermes processes as fully independent subprocesses — separate sessions, tools, and environments.
When to Use This vs delegate_task
delegate_task | Spawning hermes process | |
| Isolation | Separate conversation, shared process | Fully independent process |
| Duration | Minutes (bounded by parent loop) | Hours/days |
| Tool access | Subset of parent's tools | Full tool access |
| Interactive | No | Yes (PTY mode) |
| Use case | Quick parallel subtasks | Long autonomous missions |
One-Shot Mode
terminal(command="hermes chat -q 'Research GRPO papers and write summary to ~/research/grpo.md'", timeout=300)
# Background for long tasks:
terminal(command="hermes chat -q 'Set up CI/CD for ~/myapp'", background=true)Interactive PTY Mode (via tmux)
Hermes uses prompt_toolkit, which requires a real terminal. Use tmux for interactive spawning:
# Start
terminal(command="tmux new-session -d -s agent1 -x 120 -y 40 'hermes'", timeout=10)
# Wait for startup, then send a message
terminal(command="sleep 8 && tmux send-keys -t agent1 'Build a FastAPI auth service' Enter", timeout=15)
# Read output
terminal(command="sleep 20 && tmux capture-pane -t agent1 -p", timeout=5)
# Send follow-up
terminal(command="tmux send-keys -t agent1 'Add rate limiting middleware' Enter", timeout=5)
# Exit
terminal(command="tmux send-keys -t agent1 '/exit' Enter && sleep 2 && tmux kill-session -t agent1", timeout=10)Multi-Agent Coordination
# Agent A: backend
terminal(command="tmux new-session -d -s backend -x 120 -y 40 'hermes -w'", timeout=10)
terminal(command="sleep 8 && tmux send-keys -t backend 'Build REST API for user management' Enter", timeout=15)
# Agent B: frontend
terminal(command="tmux new-session -d -s frontend -x 120 -y 40 'hermes -w'", timeout=10)
terminal(command="sleep 8 && tmux send-keys -t frontend 'Build React dashboard for user management' Enter", timeout=15)
# Check progress, relay context between them
terminal(command="tmux capture-pane -t backend -p | tail -30", timeout=5)
terminal(command="tmux send-keys -t frontend 'Here is the API schema from the backend agent: ...' Enter", timeout=5)Session Resume
# Resume most recent session
terminal(command="tmux new-session -d -s resumed 'hermes --continue'", timeout=10)
# Resume specific session interactively
terminal(command="tmux new-session -d -s resumed 'hermes --resume <session-id>'", timeout=10)
# Resume a specific session with a one-shot follow-up query.
# Global flags must precede the `chat` subcommand; `-q` belongs to `chat`.
terminal(command="hermes --profile <profile> --resume <session-id> chat -q 'Continue from the previous blocker and verify the result.'", timeout=300)Tips
- Prefer
delegate_taskfor quick subtasks — less overhead than spawning a full process - Use
-w(worktree mode) when spawning agents that edit code — prevents git conflicts - Set timeouts for one-shot mode — complex tasks can take 5-10 minutes
- Use
hermes chat -qfor fire-and-forget — no PTY needed - Use tmux for interactive sessions — raw PTY mode has
\rvs\nissues with prompt_toolkit - For scheduled tasks, use the
cronjobtool instead of spawning — handles delivery and retry
Durable & Background Systems
Four systems run alongside the main conversation loop. Quick reference
here; full developer notes live in AGENTS.md, user-facing docs under
website/docs/user-guide/features/ in the upstream Hermes repo.
Delegation (delegate_task)
Synchronous subagent spawn — the parent waits for the child's summary before continuing its own loop. Isolated context + terminal session.
- Single:
delegate_task(goal, context, toolsets). - Batch:
delegate_task(tasks=[{goal, ...}, ...])runs children in parallel, capped bydelegation.max_concurrent_children(default 3). - Roles:
leaf(default; cannot re-delegate) vsorchestrator(can spawn its own workers, bounded bydelegation.max_spawn_depth). - Not durable. If the parent is interrupted, the child is
cancelled. For work that must outlive the turn, use
cronjoborterminal(background=True, notify_on_complete=True).
Config: delegation.* in config.yaml.
Cron (scheduled jobs)
Durable scheduler — cron/jobs.py + cron/scheduler.py. Drive it via
the cronjob tool, the hermes cron CLI (list, add, edit,
pause, resume, run, remove), or the /cron slash command.
- Schedules: duration (
"30m","2h"), "every" phrase ("every monday 9am"), 5-field cron ("0 9 * * *"), or ISO timestamp. - Per-job knobs:
skills,model/provideroverride,script(pre-run data collection;no_agent=Truemakes the script the whole job),context_from(chain job A's output into job B),workdir(run in a specific dir with itsAGENTS.md/CLAUDE.mdloaded), multi-platform delivery. - Invariants: 3-minute hard interrupt per run,
.tick.lockfile prevents duplicate ticks across processes, cron sessions passskip_memory=Trueby default, and cron deliveries are framed with a header/footer instead of being mirrored into the target gateway session (keeps role alternation intact).
User docs: https://hermes-agent.nousresearch.com/docs/user-guide/features/cron
Curator (skill lifecycle)
Background maintenance for agent-created skills. Tracks usage, marks idle skills stale, archives stale ones, keeps a pre-run tar.gz backup so nothing is lost.
- CLI:
hermes curator <verb>—status,run,pause,resume,pin,unpin,archive,restore,prune,backup,rollback. - Slash:
/curator <subcommand>mirrors the CLI. - Scope: only touches skills with
created_by: "agent"provenance. Bundled + hub-installed skills are off-limits. Never deletes — max destructive action is archive. Pinned skills are exempt from every auto-transition and every LLM review pass. - Telemetry: sidecar at
~/.hermes/skills/.usage.jsonholds per-skilluse_count,view_count,patch_count,last_activity_at,state,pinned.
Config: curator.* (enabled, interval_hours, min_idle_hours,
stale_after_days, archive_after_days, backup.*).
User docs: https://hermes-agent.nousresearch.com/docs/user-guide/features/curator
Kanban (multi-agent work queue)
Durable SQLite board for multi-profile / multi-worker collaboration.
Users drive it via hermes kanban <verb>; dispatcher-spawned workers
see a focused kanban_* toolset gated by HERMES_KANBAN_TASK, and
orchestrator profiles can opt into the broader kanban toolset. Normal
sessions still have zero kanban_* schema footprint unless configured.
- CLI verbs (common):
init,create,list(aliasls),show,assign,link,unlink,comment,complete,block,unblock,archive,tail. Less common:watch,stats,runs,log,dispatch,daemon,gc. - Worker/orchestrator toolset:
kanban_show,kanban_complete,kanban_block,kanban_heartbeat,kanban_comment,kanban_create,kanban_link; profiles that explicitly enable thekanbantoolset outside a dispatcher-spawned task also getkanban_listandkanban_unblockfor board routing. - Dispatcher runs inside the gateway by default
(
kanban.dispatch_in_gateway: true) — reclaims stale claims, promotes ready tasks, atomically claims, spawns assigned profiles. Auto-blocks a task afterfailure_limitconsecutive spawn failures (default 2; configurable viakanban.failure_limitor per-taskmax_retries). - Isolation: board is the hard boundary (workers get
HERMES_KANBAN_BOARDpinned in env); tenant is a soft namespace within a board for workspace-path + memory-key isolation.
User docs: https://hermes-agent.nousresearch.com/docs/user-guide/features/kanban
Windows-Specific Quirks
Hermes runs natively on Windows (PowerShell, cmd, Windows Terminal, git-bash mintty, VS Code integrated terminal). Most of it just works, but a handful of differences between Win32 and POSIX have bitten us — document new ones here as you hit them so the next person (or the next session) doesn't rediscover them from scratch.
Input / Keybindings
Alt+Enter doesn't insert a newline. Windows Terminal intercepts Alt+Enter
at the terminal layer to toggle fullscreen — the keystroke never reaches
prompt_toolkit. Use Ctrl+Enter instead. Windows Terminal delivers
Ctrl+Enter as LF (c-j), distinct from plain Enter (c-m / CR), and the
CLI binds c-j to newline insertion on win32 only (see
_bind_prompt_submit_keys + the Windows-only c-j binding in cli.py).
Side effect: the raw Ctrl+J keystroke also inserts a newline on Windows —
unavoidable, because Windows Terminal collapses Ctrl+Enter and Ctrl+J to
the same keycode at the Win32 console API layer. No conflicting binding
existed for Ctrl+J on Windows, so this is a harmless side effect.
mintty / git-bash behaves the same (fullscreen on Alt+Enter) unless you disable Alt+Fn shortcuts in Options → Keys. Easier to just use Ctrl+Enter.
Diagnosing keybindings. Run python scripts/keystroke_diagnostic.py (user-local — verify it exists)
(repo root) to see exactly how prompt_toolkit identifies each keystroke
in the current terminal. Answers questions like "does Shift+Enter come
through as a distinct key?" (almost never — most terminals collapse it
to plain Enter) or "what byte sequence is my terminal sending for
Ctrl+Enter?" This is how the Ctrl+Enter = c-j fact was established.
Config / Files
HTTP 400 "No models provided" on first run. config.yaml was saved
with a UTF-8 BOM (common when Windows apps write it). Re-save as UTF-8
without BOM. hermes config edit writes without BOM; manual edits in
Notepad are the usual culprit.
execute_code / Sandbox
WinError 10106 ("The requested service provider could not be loaded
or initialized") from the sandbox child process — it can't create an
AF_INET socket, so the loopback-TCP RPC fallback fails before
connect(). Root cause is usually not a broken Winsock LSP; it's
Hermes's own env scrubber dropping SYSTEMROOT / WINDIR / COMSPEC
from the child env. Python's socket module needs SYSTEMROOT to locate
mswsock.dll. Fixed via the _WINDOWS_ESSENTIAL_ENV_VARS allowlist in
tools/code_execution_tool.py. If you still hit it, inspect the child
environment through an approved terminal diagnostic in a profile that permits
host-side execution, or use a dedicated no-agent diagnostic script; do not
invoke the blocked sandbox from the default profile. Full diagnostic
recipe: follow the sandbox recovery steps in this skill.
Testing / Contributing
scripts/run_tests.sh (user-local — verify it exists) doesn't work as-is on Windows — it looks for
POSIX venv layouts (.venv/bin/activate). The Hermes-installed venv at
venv/Scripts/ has no pip or pytest either (stripped for install size).
Workaround: install pytest + pytest-xdist + pyyaml into a system Python
3.11 user site, then invoke pytest directly with PYTHONPATH set:
"/c/Program Files/Python311/python" -m pip install --user pytest pytest-xdist pyyaml
export PYTHONPATH="$(pwd)"
"/c/Program Files/Python311/python" -m pytest tests/foo/test_bar.py -v --tb=short -n 0Use -n 0, not -n 4 — pyproject.toml's default addopts already
includes -n, and the wrapper's CI-parity guarantees don't apply off POSIX.
POSIX-only tests need skip guards. Common markers already in the codebase:
- Symlinks — elevated privileges on Windows
0o600file modes — POSIX mode bits not enforced on NTFS by defaultsignal.SIGALRM— Unix-only (seetests/conftest.py::_enforce_test_timeout)- Winsock / Windows-specific regressions —
@pytest.mark.skipif(sys.platform != "win32", ...)
Use the existing skip-pattern style (sys.platform == "win32" or
sys.platform.startswith("win")) to stay consistent with the rest of the
suite.
Path / Filesystem
Line endings. Git may warn LF will be replaced by CRLF the next time
Git touches it. Cosmetic — the repo's .gitattributes normalizes. Don't
let editors auto-convert committed POSIX-newline files to CRLF.
Forward slashes work almost everywhere. C:/Users/... is accepted by
every Hermes tool and most Windows APIs. Prefer forward slashes in code
and logs — avoids shell-escaping backslashes in bash.
Troubleshooting
Voice not working
- Check
stt.enabled: truein config.yaml - Verify provider:
pip install faster-whisperor set API key - In gateway:
/restart. In CLI: exit and relaunch.
Tool not available
hermes tools— check if toolset is enabled for your platform- Some tools need env vars (check
.env) /resetafter enabling tools
Model/provider issues
hermes doctor— check config and dependencieshermes auth— re-authenticate OAuth providers (orhermes auth add <provider>)- Check
.envhas the right API key - Copilot 403:
gh auth logintokens do NOT work for Copilot API. You must use the Copilot-specific OAuth device code flow viahermes model→ GitHub Copilot.
Context length resolution
Hermes resolves context length from the active runtime model/provider unless you pin model.context_length in config.yaml. A pinned value wins immediately and bypasses auto-resolution for the main model. That is why context can appear "stuck" across model/provider switches even when the runtime changes.
Practical rule:
- If you want true auto behavior, leave
model.context_lengthunset. - If you need to force a fixed window, set
model.context_lengthexplicitly.
For local servers (LM Studio, Ollama, vLLM, llama.cpp), Hermes can often query the endpoint and infer the active model's context window. For remote/cloud providers, behavior depends on what the provider exposes and what Hermes knows about that provider/model. If detection fails, Hermes falls back to configured/default values rather than guessing perfectly.
To enable true auto-detection again:
- Remove
model.context_lengthfromconfig.yaml, or set it to0/nullif the current code path treats those as "unset". - Start a new session after the change. Existing sessions keep the context window they started with.
To intentionally override auto-detection:
- Set
model.context_lengthundermodel:. - Example:
hermes config set model.context_length 128000 - Then start a new session so the new window is picked up.
Pitfalls:
- Do NOT set
model.context_length: autounless the current Hermes version explicitly supports that literal. In current practice, true auto means the key is absent (or sometimes0/null), not the stringauto. settings.context_lengthdoes NOT control the main runtime context window. It is easy to write that key and think you changed the limit when you did not.- When a user asks for "auto," do not overwrite their config with a fresh fixed number while troubleshooting. First inspect whether
model.context_lengthis pinned and remove that pin if true auto is the goal. - If the displayed context length does not match expectations, inspect the live config and remember that
.envmodel/provider overrides can change the active runtime while a pinnedmodel.context_lengthstill forces the window.
Changes not taking effect
- Tools/skills:
/resetstarts a new session with updated toolset - Config changes: In gateway:
/restart. In CLI: exit and relaunch. - Code changes: Restart the CLI or gateway process
Skills not showing
hermes skills list— verify installedhermes skills config— check platform enablement- Load explicitly:
/skill nameorhermes -s name
Gateway issues
Check logs first:
grep -i "failed to send\|error" ~/.hermes/logs/gateway.log | tail -20Common gateway problems:
- Gateway dies on SSH logout: Enable linger:
sudo loginctl enable-linger $USER - Gateway dies on WSL2 close: WSL2 requires
systemd=truein/etc/wsl.conffor systemd services to work. Without it, gateway falls back tonohup(dies when session closes). - Gateway crash loop: Reset the failed state:
systemctl --user reset-failed hermes-gateway
Platform-specific issues
- Discord bot silent: Must enable Message Content Intent in Bot → Privileged Gateway Intents. For full setup flow (permissions, OAuth2 scopes, guild install), see discord-connect.
- Slack bot only works in DMs: Must subscribe to
message.channelsevent. Without it, the bot ignores public channels. - Windows-specific issues (
Alt+Enternewline, WinError 10106, UTF-8 BOM config, test suite, line endings): see the dedicated Windows-Specific Quirks section above.
Repeated /v1/chat/completions calls (model spam)
Symptom: LM Studio or another local server shows repeated chat completions every few seconds, even when you're not actively chatting.
Key facts (use these first):
- Hermes does NOT run health checks via /v1/chat/completions. A legitimate health check would be a lightweight HTTP GET to an endpoint like /health or /v1/models — never full chat calls.
- The environment_probe flag only probes local toolchain (Python/pip/uv); it does not ping models.
- If you see repeated POST /v1/chat/completions with 2-message conversations on the same model, this is almost always a stuck agent loop or runaway session — not normal behavior.
Diagnosis steps:
- Confirm which machine is sending traffic:
- Check Hermes gateway logs: tail ~/.hermes/logs/gateway.log | grep "chat/completions"
- If nothing shows up recently, the local Hermes instance isn't the source.
- On Windows (the remote node), check LM Studio active connections or network tab to see which client is calling /v1/chat/completions.
- Look for stuck processes:
- Linux/macOS: ps aux | grep -iE "hermes|gateway" | grep -v grep
- Windows: Task Manager → Processes → look for multiple python.exe or hermes instances. End duplicates that aren't intentionally running (e.g., a hung agent loop).
- If you're using Hermes Desktop in remote-gateway mode, close it temporarily to see if the spam stops.
- Check dashboard-backend:
- It has /health endpoints but does NOT use chat completions as health checks.
- If logs show repeated internal calls to /v1/chat/completions from the backend process, that's a bug — disable or kill the backend until fixed.
- Identify by user-agent:
- LM Studio and Hermes logs often include the User-Agent (e.g., "hermes-gateway/...", "dashboard-backend", etc.). Use this to pinpoint which client is spamming.
If the pattern persists after killing obvious culprits, escalate to checking config.yaml and .env for any custom health-check or probe scripts that may have been added manually — Hermes itself does not include one using chat completions.
If auxiliary tasks (vision, compression, session_search) fail silently, the auto provider can't find a backend. Either set OPENROUTER_API_KEY or GOOGLE_API_KEY, or explicitly configure each auxiliary task's provider:
Local custom-provider vision hangs
On current builds, a configured vision route such as auxiliary.vision.provider: custom:<name> can normalize to <name> inside resolve_vision_provider_client(). If both providers.custom:<name> and a legacy providers.<name> block exist, vision may use the legacy block's base URL while ordinary auxiliary calls use the named custom provider correctly.
Diagnosis:
- Resolve or log the actual vision client and inspect
client.base_url; do not trust config readback alone. - Compare it with a direct capped request to the intended endpoint.
- If the local vision model has
parallel: 1, a timed-out uncapped request can occupy its only slot and make later tests queue. Verify slot recovery with a short capped text request before retesting.
A second local-endpoint pitfall is that _build_call_kwargs() currently omits max_tokens for ordinary OpenAI-compatible auxiliary calls. Some multimodal models do not stop promptly on image requests without an output cap. A configuration-level workaround is an explicit intended auxiliary.vision.base_url plus auxiliary.vision.extra_body.max_tokens (choose a practical real-analysis cap, commonly 512–2048). Verify through call_llm(task='vision', ...), not only raw curl. If a small explicit cap makes the same image return immediately, the model/mmproj is healthy and the hang is request shaping or stale endpoint routing.
Compression / summary model issues
If you set a local compression/summary model (e.g., via compression.summary_model) but Hermes still uses the old provider or silently fails:
- Check the provider is fully defined. Setting
compression.summary_provider: custom:<name>is not enough — if that provider block in config.yaml has nobase_url/api_key, Hermes cannot reach it and will ignore the compression model or fall back. Always verify: - providers.
<name>.base_url is set (e.g., your LM Studio endpoint) - providers.
<name>.api_key is set (even if dummy, e.g., "lm-studio") - Compression uses the same provider as the primary model, with a different model name. The internal compressor overrides only the model; it does not switch providers. If your primary model points at LM Studio and your compression model is another model available at that endpoint, ensure both models are actually loaded in LM Studio.
- /compress does nothing if context is too short. Hermes only compresses when token count exceeds a threshold (default ~111k tokens; 0.85 * context_length). If under the threshold:
- No log entry appears for compression
- No API call is made
- The command silently no-ops
- To verify routing:
- Either let a session grow long enough and run
/compress - Or inspect
~/.hermes/logs/gateway.logafter a real compression event for: - "Session split detected" (compression)
- provider / model references that match your local endpoint
hermes config set auxiliary.vision.provider <your_provider>
hermes config set auxiliary.vision.model <model_name>Where to Find Things
| Looking for... | Location |
| Config options | hermes config edit or Configuration docs |
| Available tools | hermes tools list or Tools reference |
| Slash commands | /help in session or Slash commands reference |
| Skills catalog | hermes skills browse or Skills catalog |
| Provider setup | hermes model or Providers guide |
| Platform setup | hermes gateway setup or Messaging docs |
| MCP servers | hermes mcp list or MCP guide |
| Profiles | hermes profile list or Profiles docs |
| Cron jobs | hermes cron list or Cron docs |
| Memory | hermes memory status or Memory docs |
| Env variables | hermes config env-path or Env vars reference |
| CLI commands | hermes --help or CLI reference |
| Gateway logs | ~/.hermes/logs/gateway.log |
| Session files | hermes sessions browse (reads state.db) |
| Source code | ~/.hermes/hermes-agent/ |
Contributor Quick Reference
For occasional contributors and PR authors. Full developer docs: https://hermes-agent.nousresearch.com/docs/developer-guide/
Project Layout
hermes-agent/
├── run_agent.py # AIAgent — core conversation loop
├── model_tools.py # Tool discovery and dispatch
├── toolsets.py # Toolset definitions
├── cli.py # Interactive CLI (HermesCLI)
├── hermes_state.py # SQLite session store
├── agent/ # Prompt builder, context compression, memory, model routing, credential pooling, skill dispatch
├── hermes_cli/ # CLI subcommands, config, setup, commands
│ ├── commands.py # Slash command registry (CommandDef)
│ ├── config.py # DEFAULT_CONFIG, env var definitions
│ └── main.py # CLI entry point and argparse
├── tools/ # One file per tool
│ └── registry.py # Central tool registry
├── gateway/ # Messaging gateway
│ └── platforms/ # Platform adapters (telegram, discord, etc.)
├── cron/ # Job scheduler
├── tests/ # ~3000 pytest tests
└── website/ # Docusaurus docs siteConfig: ~/.hermes/config.yaml (settings), ~/.hermes/.env (API keys).
Adding a Tool (3 files)
1. Create tools/your_tool.py:
import json, os
from tools.registry import registry
def check_requirements() -> bool:
return bool(os.getenv("EXAMPLE_API_KEY"))
def example_tool(param: str, task_id: str = None) -> str:
return json.dumps({"success": True, "data": "..."})
registry.register(
name="example_tool",
toolset="example",
schema={"name": "example_tool", "description": "...", "parameters": {...}},
handler=lambda args, **kw: example_tool(
param=args.get("param", ""), task_id=kw.get("task_id")),
check_fn=check_requirements,
requires_env=["EXAMPLE_API_KEY"],
)2. Add to toolsets.py → _HERMES_CORE_TOOLS list.
Auto-discovery: any tools/*.py file with a top-level registry.register() call is imported automatically — no manual list needed.
All handlers must return JSON strings. Use get_hermes_home() for paths, never hardcode ~/.hermes.
Adding a Slash Command
- Add
CommandDeftoCOMMAND_REGISTRYinhermes_cli/commands.py - Add handler in
cli.py→process_command() - (Optional) Add gateway handler in
gateway/run.py
All consumers (help text, autocomplete, Telegram menu, Slack mapping) derive from the central registry automatically.
Agent Loop (High Level)
run_conversation():
1. Build system prompt
2. Loop while iterations < max:
a. Call LLM (OpenAI-format messages + tool schemas)
b. If tool_calls → dispatch each via handle_function_call() → append results → continue
c. If text response → return
3. Context compression triggers automatically near token limitTesting
python -m pytest tests/ -o 'addopts=' -q # Full suite
python -m pytest tests/tools/ -q # Specific area- Tests auto-redirect
HERMES_HOMEto temp dirs — never touch real~/.hermes/ - Run full suite before pushing any change
- Use
-o 'addopts='to clear any baked-in pytest flags
Windows contributors: scripts/run_tests.sh (user-local — verify it exists) currently looks for POSIX venvs (.venv/bin/activate / venv/bin/activate) and will error out on Windows where the layout is venv/Scripts/activate + python.exe. The Hermes-installed venv at venv/Scripts/ also has no pip or pytest — it's stripped for end-user install size. Workaround: install pytest + pytest-xdist + pyyaml into a system Python 3.11 user site (/c/Program Files/Python311/python -m pip install --user pytest pytest-xdist pyyaml), then run tests directly:
export PYTHONPATH="$(pwd)"
"/c/Program Files/Python311/python" -m pytest tests/tools/test_foo.py -v --tb=short -n 0Use -n 0 (not -n 4) because pyproject.toml's default addopts already includes -n, and the wrapper's CI-parity story doesn't apply off-POSIX.
Cross-platform test guards: tests that use POSIX-only syscalls need a skip marker. Common ones already in the codebase:
- Symlink creation →
@pytest.mark.skipif(sys.platform == "win32", reason="Symlinks require elevated privileges on Windows")(seetests/cron/test_cron_script.py) - POSIX file modes (0o600, etc.) →
@pytest.mark.skipif(sys.platform.startswith("win"), reason="POSIX mode bits not enforced on Windows")(seetests/hermes_cli/test_auth_toctou_file_modes.py) signal.SIGALRM→ Unix-only (seetests/conftest.py::_enforce_test_timeout)- Live Winsock / Windows-specific regression tests →
@pytest.mark.skipif(sys.platform != "win32", reason="Windows-specific regression")
Monkeypatching sys.platform is not enough when the code under test also calls platform.system() / platform.release() / platform.mac_ver(). Those functions re-read the real OS independently, so a test that sets sys.platform = "linux" on a Windows runner will still see platform.system() == "Windows" and route through the Windows branch. Patch all three together:
monkeypatch.setattr(sys, "platform", "linux")
monkeypatch.setattr(platform, "system", lambda: "Linux")
monkeypatch.setattr(platform, "release", lambda: "6.8.0-generic")See tests/agent/test_prompt_builder.py::TestEnvironmentHints for a worked example.
Extending the system prompt's execution-environment block
Factual guidance about the host OS, user home, cwd, terminal backend, and shell (bash vs. PowerShell on Windows) is emitted from agent/prompt_builder.py::build_environment_hints(). This is also where the WSL hint and per-backend probe logic live. The convention:
- Local terminal backend → emit host info (OS,
$HOME, cwd) + Windows-specific notes (hostname ≠ username,terminaluses bash not PowerShell). - Remote terminal backend (anything in
_REMOTE_TERMINAL_BACKENDS:docker, singularity, modal, daytona, ssh, managed_modal) → suppress host info entirely and describe only the backend. A liveuname/whoami/pwdprobe runs inside the backend viatools.environments.get_environment(...).execute(...), cached per process in_BACKEND_PROBE_CACHE, with a static fallback if the probe times out. - Key fact for prompt authoring: when
TERMINAL_ENV != "local", every file tool (read_file,write_file,patch,search_files) runs inside the backend container, not on the host. The system prompt must never describe the host in that case — the agent can't touch it.
Full design notes, the exact emitted strings, and testing pitfalls: .
Refactor-safety pattern (POSIX-equivalence guard): when you extract inline logic into a helper that adds Windows/platform-specific behavior, keep a _legacy_<name> oracle function in the test file that's a verbatim copy of the old code, then parametrize-diff against it. Example: tests/tools/test_code_execution_windows_env.py::TestPosixEquivalence. This locks in the invariant that POSIX behavior is bit-for-bit identical and makes any future drift fail loudly with a clear diff.
Commit Conventions
type: concise subject line
Optional body.Types: fix:, feat:, refactor:, docs:, chore:
Key Rules
- Never break prompt caching — don't change context, tools, or system prompt mid-conversation
- Message role alternation — never two assistant or two user messages in a row
- Use
get_hermes_home()fromhermes_constantsfor all paths (profile-safe) - Config values go in
config.yaml, secrets go in.env - New tools need a
check_fnso they only appear when requirements are met
Hermes configuration and CLI-ecosystem management (consolidated)
The configuration ecosystem previously split across multiple narrow skills (hermes-config-editing, hermes-desktop-config, hermes-provider-switching, hermes-windows) is consolidated here:
IMPORTANT (agent constraint):
- The agent CANNOT write ~/.hermes/config.yaml directly (enforced).
- Always use one of these for configuration changes:
- hermes config set
<key><value>for simple, supported keys. - hermes config edit to open the file in the user's editor; give them exact edits.
- A Python script via terminal that reads/writes config.yaml using yaml.safe_load/dump (preferred for multi-field or nested changes).
- For provider/auxiliary routing:
- Define providers under providers: with a custom:
<name>key, api URL, default_model, etc. - Update auxiliary.
<task>.provider and .model to target the new provider. - Always leave vision unchanged unless explicitly asked; it is pinned separately (Mac LM Studio).
Configuring auxiliary providers (e.g., Unsloth, local endpoints):
- Use this when routing auxiliary tasks (compression, web_extract, skills_hub, etc.) to a specific provider/endpoint.
- If direct writes to config.yaml are blocked, use:
- hermes config edit with precise instructions, or
- A small Python script that:
- Loads config via yaml.safe_load,
- Updates providers + auxiliary entries,
- Dumps back with yaml.dump.
- When adding a new provider (e.g., Unsloth on another machine):
- Use a clear key like custom:my-local-server.
- Set api, default_model, and key_env/api_key as appropriate.
- Wire auxiliary tasks by setting each task’s provider and model to that new provider.
- Always verify live:
- Send a quick test request (curl or requests) to the endpoint.
- Confirm it responds and note the actual "model" in the response. Pitfalls:
- OpenAI image generation backend is separate from OpenAI Codex. For generated images use
image_gen.provider: openaiwithimage_gen.model: gpt-image-2-medium(or low/high). Do not set the main/chat model togpt-image-2-medium; that model is only for theimage_generatebackend and will 400 if used as a chat model. Ifimage_generatereportsOPENAI_API_KEY not setwhilehermes auth listshowsopenai-api, check whether the tool/cron process exported~/.hermes/.env; the OpenAI image plugin may need the local fallback patch reapplied via the apply-patches helper (user-local — verify it exists). - OpenAI Codex auxiliary routing must not set
base_url. Forauxiliary.<task>.provider: openai-codex, setmodelonly. Ifbase_url: https://chatgpt.com/backend-api/codexis present,_resolve_task_provider_model()treats it as acustomendpoint and the OpenAI SDK calls/chat/completions, which hits Cloudflare/HTML instead of the Codex Responses adapter. Fix by removingbase_url,api_key, andapi_modefrom the affected auxiliary task entries, then verify resolution returns('openai-codex', '<model>', None)and a smokecall_llm(task='title_generation', ...)succeeds. - Local-first resolution. When the user names a model that looks like a GGUF filename or a known local model, query every configured local LM Studio / llama.cpp endpoint FIRST before routing through OpenRouter or any cloud provider. Defaulting to OpenRouter for a model the user runs locally is a hard correction — route local models to local endpoints. Check curl http://
<ip>:<port>/v1/models on each local endpoint before touching cloud configs. - Users often say "use gpt-4o-2024-08-06" while their server is actually running a different model under that label (e.g., Unsloth serving an OSS model). Always:
- Trust the live response's "model" field over what the user or UI claims.
- Update config to reflect the actual model name from the endpoint.
- Ensure reachability:
- Ping the host first, then test the port (e.g., 8888) with curl.
- Timeouts mean service not running, wrong bind address, or firewall — do not assume config is at fault.
After config changes, verify via:
- hermes config show (confirm model/auxiliary sections), or
- A small Python script that prints affected config entries.
What this consolidated section covers
- Configure and verify model/provider swaps, including safe full-provider and per-subsystem overrides.
- Edit advanced configuration safely (including compression thresholds and auxiliary provider blocks).
- Handle local/global setup paths for the desktop gateway and dashboard connection.
- Handle Windows reinstall/update/launcher edge cases in a single operational workflow.
Recommended operating flow
- Confirm scope: global runtime switch vs subsystem override before editing.
- Validate current auth/config state and read active profile-specific values.
- If the user names a model that could be local (GGUF filename, no provider prefix, model known to run on a local LM Studio instance), query each configured local endpoint (
curl <ip>:<port>/v1/models) before touching cloud providers. Match the model ID from the live response. - Apply minimal delta edits for the target component (
config.yamlvia supported tooling, not manual scattered edits). - Restart/refresh only where required by process scope (gateway or terminal backend).
- Verify with readback before reporting success.
Consolidated reference files
The historical reference files and templates from the original narrow skills are consolidated into this skill's own references/ and templates/.
Self-Check / Safety (mandatory)
Before declaring any Hermes config/setup task complete:
- Verify externally:
- Run the command/query and confirm it matches what you promised (hermes status, hermes tools, etc.).
- Scope check:
- Confirm the change is exactly in the requested scope; no sneaky global or production changes.
- Memory/skill updates:
- Do not overwrite canonical docs solely on agent reasoning; compare with existing skill/AGENTS.md first.
Human-only gates (do NOT auto-execute without explicit approval):
- Switching provider/model/config values (
model.provider,model.default, aux providers/task overrides). - Editing credentials, API keys, or
.enventries used by live runtime. - Restarting/stopping gateway, services, or terminal/backend workers.
- Removing/enabling/disabling installed skills/tools/skills indexes.
- Running destructive shell operations affecting Hermes code/config or project-critical files.
For these:
- Present the proposed change in 3–6 bullets.
- Wait for explicit go-ahead before executing.
Other versions22 projects use a version of this.
Word for word · 1
- AtlasOmnia/donna-starter★ 136100% same
Edited · 17
- NousResearch/hermes-agent★ 257k11% same
- Tommy-yw/RunbookHermes★ 54669% same
- aivrar/portable-hermes-agent★ 23911% same
- RedWoodOG/Hermes-Desktop★ 17760% same
- delorenj/skills★ 1670% same
- Samin12/skills★ 812% same
- Fahrnetic/engineering-agent-skill-workflow★ 257% same
- john-data-chen/hermes-agent-backup★ 273% same
- barzzly/BarzzLyp_Agent_Skills★ 111% same
- juanmackie/juanskills★ 182% same
7 more not listed
Wrote their own version · 4
- fathah/hermes-desktop★ 14ksame name
- Gopyr/gopyr-skills-hub★ 0same name
- RaghavGanesh7/personal-skills★ 0same name
- rakaarwaky/agents-arwaky★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
Used alongsideProjects with it also use sdlc-review, teams-meeting-pipeline and 9 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
aivrarSkillsdlc-review
Review Kanban handoffs and route verified outcomes.
Also in 5 projects that use this
john-data-chenSkillteams-meeting-pipeline
Operate the Teams meeting summary pipeline via Hermes CLI — summarize meetings, inspect pipeline status, replay jobs, manage Microsoft Graph subscriptions.
Also in 6 projects that use this
aivrarSkillsession-librarian
Organize sessions by prompt: find, rename, archive, prune.
Also in 3 projects that use this
john-data-chenSkilltouchdesigner-mcp
Control a running TouchDesigner instance via twozero MCP — create operators, set parameters, wire connections, execute Python, build real-time visuals. 36 native tools.
Also in 4 projects that use this
tunnckoCoreSkillnode-inspect-debugger
Debug Node.js via --inspect + Chrome DevTools Protocol CLI.
Also in 7 projects that use this
tunnckoCoreSkillpython-debugpy
Debug Python: pdb REPL + debugpy remote (DAP).
Also in 7 projects that use this
- +5 more from aivrar
In this repository74 other files it gives its agents.
- apple-remindersSkill
- application-security-reviewSkill
- browser-harness-authoringSkill
- claude-designSkill
- codebase-inspectionSkill
- coding-worktree-recoverySkill
- computer-useSkill
- content-styleSkill
- cross-browser-typography-qaSkill
- daily-news-digestsSkill
- daily-note-wrapupSkill
- destination-trip-planningSkill
- discord-connectSkill
- dogfoodSkill
- domestic-trip-planningSkill
- dynamic-content-extractionSkill
- evidence-based-repliesSkill
- external-model-reviewSkill
- github-authSkill
- github-code-reviewSkill
- github-issuesSkill
- github-pre-push-gatesSkill
- github-pr-workflowSkill
- github-readme-maintenanceSkill
- github-repo-managementSkill
- github-workflowsSkill
- google-workspaceSkill
- hermes-agent-skill-authoringSkill
- hermes-config-editingSkill
- hermes-context-optimizationSkill
- hermes-desktop-pluginsSkill
- hermes-diagnostic-reviewSkill
- hermes-mnemosyneSkill
- hermes-nightly-self-check-decisionsSkill
- hermes-overnight-autonomySkill
- hermes-plugin-developmentSkill
- hermes-plugin-evaluationSkill
- hermes-self-evaluationSkill
- hermes-session-maintenanceSkill
- hermes-themesSkill
- hf-model-card-researchSkill
- imessageSkill
- inspecting-hermes-desktop-domSkill
- local-app-github-publishingSkill
- local-discoverySkill
- local-model-selectionSkill
- macos-app-automationSkill
- macos-storage-managementSkill
- mapsSkill
- marketing-collateral-designSkill
- marketplace-purchase-vettingSkill
- meal-trackerSkill
- messaging-gateway-troubleshootingSkill
- meta-business-postingSkill
- mnemosyne-maintenanceSkill
- notes-automation-workflowsSkill
- notion-artifact-captureSkill
- notionSkill
- obsidian-memory-architectureSkill
- obsidianSkill
- The first 60 shown.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
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.

