Source Notes: Hermes Agent Setup Guide
Official-doc excerpts, local verification notes, and source material used to draft the Hermes Agent setup guide.
Hermes Agent source notes for ABS guide test
Sources: official Hermes docs llms-full.txt, local Hermes CLI, GitHub README.
Installation
Installation
Get Hermes Agent up and running in under two minutes!
:::tip Platform Support For the full platform support matrix (which OSes, distribution methods, and platform-gated features are supported), see Platform Support. :::
Quick Install
With the Hermes Desktop installer on macOS or Windows (recommended)
To easily install the command-line and desktop applications, download the Hermes Desktop installer from our website and run it.
Without Hermes Desktop:
For a command-line only install without Hermes Desktop, run:
Linux / macOS / WSL2 / Android (Termux)
curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash
Windows (native)
Run in powershell:
iex (irm https://hermes-agent.nousresearch.com/install.ps1)
If you want to install & run Hermes Desktop after a command-line only install, simply run
hermes desktop
What the Installer Does
The installer handles everything automatically — all dependencies (Python, Node.js, ripgrep, ffmpeg), the repo clone, virtual environment, global hermes command setup, and LLM provider configuration. By the end, you’re ready to chat.
Install Layout
Where the installer puts things depends on whether you’re installing as a normal user or as root:
| Installer | Code lives at | hermes binary | Data directory |
|---|---|---|---|
| Per-user (git installer) | ~/.hermes/hermes-agent/ | ~/.local/bin/hermes (symlink) | ~/.hermes/ |
Root-mode (sudo curl … | sudo bash) | /usr/local/lib/hermes-agent/ | /usr/local/bin/hermes | /root/.hermes/ (or $HERMES_HOME) |
The root-mode FHS layout (/usr/local/lib/…, /usr/local/bin/hermes) matches where other system-wide developer tools land on Linux. It’s useful for shared-machine deployments where one system install should serve every user. Per-user config (auth, skills, sessions) still lives under each user’s ~/.hermes/ or explicit HERMES_HOME.
After Installation
Reload your shell and start chatting:
source ~/.bashrc # or: source ~/.zshrc
hermes # Start chatting!
To reconfigure individual settings later, use the dedicated commands:
hermes model # Choose your LLM provider and model
hermes tools # Configure which tools are enabled
hermes gateway setup # Set up messaging platforms
hermes config set # Set individual config values
hermes setup # Or run the full setup wizard to configure everything at once
:::tip Fastest path: Nous Portal One subscription covers 300+ models plus the Tool Gateway (web search, image generation, TTS, cloud browser). Skip the per-tool key juggling:
hermes setup --portal
That logs you in, sets Nous as your provider, and turns on the Tool Gateway in one command. :::
Quickstart
Quickstart
This guide gets you from zero to a working Hermes setup that survives real use. Install, choose a provider, verify a working chat, and know exactly what to do when something breaks.
Prefer to watch?
Onchain AI Garage put together a Masterclass walkthrough of installation, setup, and basic commands — a good companion to this page if you’d rather follow along on video. For more, see the full Hermes Agent Tutorials & Use Cases playlist.
Who this is for
- Brand new and want the shortest path to a working setup
- Switching providers and don’t want to lose time to config mistakes
- Setting up Hermes for a team, bot, or always-on workflow
- Tired of “it installed, but it still does nothing”
The fastest path
Pick the row that matches your goal:
| Goal | Do this first | Then do this |
|---|---|---|
| I just want Hermes working on my machine | hermes setup | Run a real chat and verify it responds |
| I already know my provider | hermes model | Save the config, then start chatting |
| I want a bot or always-on setup | hermes gateway setup after CLI works | Connect Telegram, Discord, Slack, or another platform |
| I want a local or self-hosted model | hermes model → custom endpoint | Verify the endpoint, model name, and context length |
| I want multi-provider fallback | hermes model first | Add routing and fallback only after the base chat works |
Rule of thumb: if Hermes cannot complete a normal chat, do not add more features yet. Get one clean conversation working first, then layer on gateway, cron, skills, voice, or routing.
CLI Interface
CLI Interface
Hermes Agent’s CLI is a full terminal user interface (TUI) — not a web UI. It features multiline editing, slash-command autocomplete, conversation history, interrupt-and-redirect, and streaming tool output. Built for people who live in the terminal.
:::tip First-time setup
One command — hermes setup --portal — and you’re ready to hermes chat. See Nous Portal.
:::
:::tip
Hermes also ships a modern TUI with modal overlays, mouse selection, and non-blocking input. Launch it with hermes --tui — see the TUI guide.
:::
Running the CLI
# Start an interactive session (default)
hermes
# Single query mode (non-interactive)
hermes chat -q "Hello"
# With a specific model
hermes chat --model "anthropic/claude-sonnet-4"
# With a specific provider
hermes chat --provider nous # Use Nous Portal
hermes chat --provider openrouter # Force OpenRouter
# With specific toolsets
hermes chat --toolsets "web,terminal,skills"
# Start with one or more skills preloaded
hermes -s hermes-agent-dev,github-auth
hermes chat -s github-pr-workflow -q "open a draft PR"
# Resume previous sessions
hermes --continue # Resume the most recent CLI session (-c)
hermes --resume <session_id> # Resume a specific session by ID (-r)
# Verbose mode (debug output)
hermes chat --verbose
# Isolated git worktree (for running multiple agents in parallel)
hermes -w # Interactive mode in worktree
hermes -w -z "Fix issue #123" # Single query in worktree
Interface Layout
The Hermes CLI banner, conversation stream, and fixed input prompt rendered as a stable docs figure instead of fragile text art.
The welcome banner shows your model, terminal backend, working directory, available tools, and installed skills at a glance.
Status Bar
A persistent status bar sits above the input area, updating in real time:
⚕ claude-sonnet-4-20250514 │ 12.4K/200K │ [██████░░░░] 6% │ $0.06 │ 15m
| Element | Description |
|---|---|
| Model name | Current model (truncated if longer than 26 chars) |
| Token count | Context tokens used / max context window |
| Context bar | Visual fill indicator with color-coded thresholds |
| Cost | Estimated session cost (or n/a for unknown/zero-priced models) |
| 🗜️ N | Context compression count — how many times the running session has been auto-compressed. Appears once the first compression fires. |
| ▶ N | Active background tasks — how many /background prompts are still running in the current session. Appears whenever at least one task is in flight. |
| Duration | Elapsed session time |
| ⚠ YOLO | YOLO mode warning — shown whenever HERMES_YOLO_MODE is on (either hermes --yolo at launch or /yolo toggled mid-session). Mirrors the banner-line warning so you can’t forget you’re in auto-approve mode. |
The bar adapts to terminal width — full layout at ≥ 76 columns, compact at 52–75, minimal (model + duration, plus the YOLO badge when active) below 52.
Context color coding:
| Color | Threshold | Meaning |
|---|---|---|
| Green | < 50% | Plenty of room |
| Yellow | 50–80% | Getting full |
| Orange | 80–95% | Approaching limit |
| Red | ≥ 95% | Near overflow — consider /compress |
Use /usage for a detailed breakdown including per-category costs (input vs output tokens).
Session Resume Display
When resuming a previous session (hermes -c or hermes --resume <id>), a “Previous Conversation” panel appears between the banner and the input prompt, showing a compact recap of the conversation history. See Sessions — Conversation Recap on Resume for details and configuration.
Keybindings
| Key | Action |
|---|---|
Enter | Send message |
Alt+Enter, Ctrl+J, or Shift+Enter | New line (multi-line input). Shift+Enter requires a terminal that distinguishes it from Enter — see below. On Windows Terminal, Alt+Enter is captured by the terminal (fullscreen toggle); use Ctrl+Enter or Ctrl+J instead. |
Alt+V | Paste an image from the clipboard when supported by the terminal |
Ctrl+V | Paste text and opportunistically attach clipboard images |
Ctrl+B | Start/stop voice recording when voice mode is enabled (voice.record_key, default: ctrl+b) |
Ctrl+G | Open the current input buffer in $EDITOR (vim/nvim/nano/VS Code/etc.). Save and quit to send the edited text as the next prompt — ideal for long, multi-paragraph prompts. |
Ctrl+X Ctrl+E | Emacs-style alternate binding for the external editor (same behavior as Ctrl+G). |
Ctrl+C | Interrupt agent (double-press within 2s to force exit) |
Ctrl+D | Exit |
Ctrl+Z | Suspend Hermes to background (Unix only). Run fg in the shell to resume. |
Tab | Accept auto-suggestion (ghost text) or autocomplete slash commands |
Multiline paste preview. When you paste a multi-line block, the CLI echoes a compact single-line preview ([pasted: 47 lines, 1,842 chars — press Enter to send]) instead of dumping the whole payload into the scrollback. The full content is still what gets sent; this is just display polish.
Markdown stripping in final responses. The CLI strips the most verbose markdown fences and **bold** / *italic* wrappers from final agent replies so they render as readable terminal prose rather than raw source. Code blocks and lists are preserved. This does not affect gateway platforms or tool results — they keep their markdown for native rendering.
Slash Commands
Type / to see the autocomplete dropdown. Hermes supports a large set of CLI slash commands, dynamic skill commands, and user-defined quick commands.
Common examples:
| Command | Description |
|---|---|
/help | Show command help |
/model | Show or change the current model |
/tools | List currently available tools |
/skills browse | Browse the skills hub and official optional skills |
/background <prompt> | Run a prompt in a separate background session |
/skin | Show or switch the active CLI skin |
/voice on | Enable CLI voice mode (press Ctrl+B to record) |
/voice tts | Toggle spoken playback for Hermes replies |
/reasoning high | Increase reasoning effort |
/title My Session | Name the current session |
/status | Show session info — model/profile/tokens/duration — followed by a local Session recap block (recent turn counts, top tools used, files touched, latest user prompt + assistant reply). Pure local compute; no LLM call. |
/sessions | Open an interactive session picker right inside the classic CLI (same surface the TUI uses). Type to filter, arrow keys to |
Configuration
Declarative Settings
The settings option accepts an arbitrary attrset that is rendered as config.yaml. It supports deep merging across multiple module definitions (via lib.recursiveUpdate), so you can split config across files:
# base.nix
services.hermes-agent.settings = {
model.default = "anthropic/claude-sonnet-4";
toolsets = [ "all" ];
terminal = { backend = "local"; timeout = 180; };
};
# personality.nix
services.hermes-agent.settings = {
display = { compact = false; personality = "kawaii"; };
memory = { memory_enabled = true; user_profile_enabled = true; };
};
Both are deep-merged at evaluation time. Nix-declared keys always win over keys in an existing config.yaml on disk, but user-added keys that Nix doesn’t touch are preserved. This means if the agent or a manual edit adds keys like skills.disabled or streaming.enabled, they survive nixos-rebuild switch.
:::note Model naming
settings.model.default uses the model identifier your provider expects. With OpenRouter (the default), these look like "anthropic/claude-sonnet-4" or "google/gemini-3-flash". If you’re using a provider directly (Anthropic, OpenAI), set settings.model.base_url to point at their API and use their native model IDs (e.g., "claude-sonnet-4-20250514"). When no base_url is set, Hermes defaults to OpenRouter.
:::
:::tip Discovering available config keys
Run nix build .#configKeys && cat result to see every leaf config key extracted from Python’s DEFAULT_CONFIG. You can paste your existing config.yaml into the settings attrset — the structure maps 1:1.
:::
Full example: all commonly customized settings
{ config, ... }: {
services.hermes-agent = {
enable = true;
container.enable = true;
# ── Model ──────────────────────────────────────────────────────────
settings = {
model = {
base_url = "https://openrouter.ai/api/v1";
default = "anthropic/claude-opus-4.6";
};
toolsets = [ "all" ];
max_turns = 100;
terminal = { backend = "local"; cwd = "."; timeout = 180; };
compression = {
enabled = true;
threshold = 0.85;
summary_model = "google/gemini-3-flash-preview";
};
memory = { memory_enabled = true; user_profile_enabled = true; };
display = { compact = false; personality = "kawaii"; };
agent = { max_turns = 60; verbose = false; };
};
# ── Secrets ────────────────────────────────────────────────────────
environmentFiles = [ config.sops.secrets."hermes-env".path ];
# ── Documents ──────────────────────────────────────────────────────
documents = {
"USER.md" = ./documents/USER.md;
};
# ── MCP Servers ────────────────────────────────────────────────────
mcpServers.filesystem = {
command = "npx";
args = [ "-y" "@modelcontextprotocol/server-filesystem" "/data/workspace" ];
};
# ── Container options ──────────────────────────────────────────────
container = {
image = "ubuntu:24.04";
backend = "docker";
hostUsers = [ "your-username" ];
extraVolumes = [ "/home/user/projects:/projects:rw" ];
extraOptions = [ "--gpus" "all" ];
};
# ── Service tuning ─────────────────────────────────────────────────
addToSystemPackages = true;
extraArgs = [ "--verbose" ];
restart = "always";
restartSec = 5;
};
}
Escape Hatch: Bring Your Own Config
If you’d rather manage config.yaml entirely outside Nix, use configFile:
services.hermes-agent.configFile = /etc/hermes/config.yaml;
This bypasses settings entirely — no merge, no generation. The file is copied as-is to $HERMES_HOME/config.yaml on each activation.
Customization Cheatsheet
Quick reference for the most common things Nix users want to customize:
| I want to… | Option | Example |
|---|---|---|
| Change the LLM model | settings.model.default | "anthropic/claude-sonnet-4" |
| Use a different provider endpoint | settings.model.base_url | "https://openrouter.ai/api/v1" |
| Add API keys | environmentFiles | [ config.sops.secrets."hermes-env".path ] |
| Give the agent a personality | ${services.hermes-agent.stateDir}/.hermes/SOUL.md | manage the file directly |
| Add MCP tool servers | mcpServers.<name> | See MCP Servers |
| Enable Discord/Telegram/Slack | extraDependencyGroups | [ "messaging" ] |
| Mount host directories into container | container.extraVolumes | [ "/data:/data:rw" ] |
| Pass GPU access to container | container.extraOptions | [ "--gpus" "all" ] |
| Use Podman instead of Docker | container.backend | "podman" |
| Share state between host CLI and container | container.hostUsers | [ "sidbin" ] |
| Make extra tools available to the agent | extraPackages | [ pkgs.pandoc pkgs.imagemagick ] |
| Use a custom base image | container.image | "ubuntu:24.04" |
| Override the hermes package | package | inputs.hermes-agent.packages.${system}.default.override { ... } |
| Change state directory | stateDir | "/opt/hermes" |
| Set the agent’s working directory | workingDirectory | "/home/user/projects" |
Tools & Toolsets
Tools & Toolsets
Tools are functions that extend the agent’s capabilities. They’re organized into logical toolsets that can be enabled or disabled per platform.
Available Tools
Hermes ships with a broad built-in tool registry covering web search, browser automation, terminal execution, file editing, memory, delegation, scheduled tasks, Home Assistant, and more.
:::note
Honcho cross-session memory is available as a memory provider plugin (plugins/memory/honcho/), not as a built-in toolset. See Plugins for installation.
:::
High-level categories:
| Category | Examples | Description |
|---|---|---|
| Web | web_search, web_extract | Search the web and extract page content. |
| X Search | x_search | Search X (Twitter) posts and threads via xAI’s built-in x_search Responses tool — gated on xAI credentials (SuperGrok OAuth or XAI_API_KEY); off by default, opt in via hermes tools → 🐦 X (Twitter) Search. |
| Terminal & Files | terminal, process, read_file, patch | Execute commands and manipulate files. |
| Browser | browser_navigate, browser_snapshot, browser_vision | Interactive browser automation with text and vision support. |
| Media | vision_analyze, image_generate, text_to_speech | Multimodal analysis and generation. |
| Agent orchestration | todo, clarify, execute_code, delegate_task | Planning, clarification, code execution, and subagent delegation. |
| Memory & recall | memory, session_search | Persistent memory and session search. |
| Automation | cronjob | Scheduled tasks with create/list/update/pause/resume/run/remove actions. Outbound delivery is handled by cron’s own delivery, the hermes send CLI, and the gateway notifier — not by an agent-callable tool. |
| Integrations | ha_*, MCP server tools | Home Assistant, MCP, and other integrations. |
For the authoritative code-derived registry, see Built-in Tools Reference and Toolsets Reference.
:::tip Nous Tool Gateway
Paid Nous Portal subscribers can use web search, image generation, TTS, and browser automation through the Tool Gateway — no separate API keys needed. Run hermes model to enable it, or configure individual tools with hermes tools.
:::
Using Toolsets
# Use specific toolsets
hermes chat --toolsets "web,terminal"
# See all available tools
hermes tools
# Configure tools per platform (interactive)
hermes tools
Common toolsets include web, search, terminal, file, browser, vision, image_gen, skills, tts, todo, memory, session_search, cronjob, code_execution, delegation, clarify, homeassistant, messaging, spotify, discord, discord_admin, debugging, and safe.
See Toolsets Reference for the full set, including platform presets such as hermes-cli, hermes-telegram, and dynamic MCP toolsets like mcp-<server>.
Terminal Backends
The terminal tool can execute commands in different environments:
| Backend | Description | Use Case |
|---|---|---|
local | Run on your machine (default) | Development, trusted tasks |
docker | Isolated containers | Security, reproducibility |
ssh | Remote server | Sandboxing, keep agent away from its own code |
singularity | HPC containers | Cluster computing, rootless |
modal | Cloud execution | Serverless, scale |
daytona | Cloud sandbox workspace | Persistent remote dev environments |
Configuration
# In ~/.hermes/config.yaml
terminal:
backend: local # or: docker, ssh, singularity, modal, daytona
cwd: "." # Working directory
timeout: 180 # Command timeout in seconds
Docker Backend
terminal:
backend: docker
docker_image: python:3.11-slim
One persistent container, shared across the whole process. Hermes starts a single long-lived container on first use (docker run -d ... sleep 2h) and routes every terminal, file, and execute_code call through docker exec into that same container. Working-directory changes, installed packages, environment tweaks, and files written to /workspace all carry over from one tool call to the next, across /new, /reset, and delegate_task subagents, for the lifetime of the Hermes process. The container is stopped and removed on shutdown.
This means the Docker backend behaves like a persistent sandbox VM, not a fresh container per command. If you pip install foo once, it’s there for the rest of the session. If you cd /workspace/project, subsequent ls calls see that directory. See Configuration → Docker Backend for the full lifecycle details and the container_persistent flag that controls whether /workspace and /root survive across Hermes restarts.
SSH Backend
Recommended for security — agent can’t modify its own code:
terminal:
backend: ssh
# Set credentials in ~/.hermes/.env
TERMINAL_SSH_HOST=my-server.example.com
TERMINAL_SSH_USER=myuser
TERMINAL_SSH_KEY=~/.ssh/id_rsa
Singularity/Apptainer
# Pre-build SIF for parallel workers
apptainer build ~/python.sif docker://python:3.11-slim
# Configure
hermes config set terminal.backend singularity
hermes config set terminal.singularity_image ~/python.sif
Modal (Serverless Cloud)
uv pip install modal
modal setup
hermes config set terminal.backend modal
Container Resources
Configure CPU, memory, disk, and persistence for all container backends:
terminal:
backend: docker # or singularity, modal, daytona
container_cpu: 1 # CPU cores (default: 1)
container_memory: 5120 # Memory in MB (default: 5GB)
container_disk: 51200 # Disk in MB (default: 50GB)
container_persistent: true # Persist filesystem across sessions (default: true)
When container_persistent: true, installed packages, files, and config survive across sessions.
Container Security
All container backends run with security hardening:
- Read-only root filesystem (Docker)
- All Linux capabilities dropped
- No privilege escalation
- PID limits (256 processes)
- Full namespace isolation
- Persistent workspace via volumes, not writable root layer
Docker can optionally receive an explicit env allowlist via terminal.docker_forward_env, but forwarded variables are visible to commands inside the container and should be treated as exposed to that session.
Background Process Management
Start background processes and manage them:
terminal(command="pytest -v tests/", background=true)
# Returns: {"session_id": "proc_abc123", "pid": 12345}
# Then manage with the process tool:
process(action="list") # Show all running processes
process(action="poll", se
<!-- EXTRACT: # Skills System -->
# Skills System
# Skills System
Skills are on-demand knowledge documents the agent can load when needed. They follow a **progressive disclosure** pattern to minimize token usage and are compatible with the [agentskills.io](https://agentskills.io/specification) open standard.
All skills live in **`~/.hermes/skills/`** — the primary directory and source of truth. On fresh install, bundled skills are copied from the repo. Hub-installed and agent-created skills also go here. The agent can modify or delete any skill.
You can also point Hermes at **external skill directories** — additional folders scanned alongside the local one. See [External Skill Directories](#external-skill-directories) below.
See also:
- [Bundled Skills Catalog](/reference/skills-catalog)
- [Official Optional Skills Catalog](/reference/optional-skills-catalog)
## Starting with a blank slate
By default every profile is seeded with the bundled skill catalog, and each `hermes update` adds any newly bundled skills. If you want a profile with **no bundled skills** — and that stays empty across updates — you have two paths:
**At install time** (applies to the default `~/.hermes` profile):
```bash
curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash -s -- --no-skills
At profile-create time (named profiles):
hermes profile create research --no-skills
On an already-installed profile (default or named), toggle it at runtime:
hermes skills opt-out # stop future seeding — nothing on disk is touched
hermes skills opt-out --remove # also delete UNMODIFIED bundled skills (confirms first)
hermes skills opt-in --sync # undo: remove the marker and re-seed now
All three paths write a .no-bundled-skills marker into the profile directory. While the marker is present, the installer, hermes update, and any skill sync all skip bundled-skill seeding for that profile. Delete the marker (or run hermes skills opt-in) to re-enable.
:::note Safe by default
hermes skills opt-out only stops future seeding — it never deletes anything already on disk. The optional --remove flag deletes bundled skills only when they are unmodified (byte-identical to the version Hermes installed). Skills you have edited, skills installed from the hub, and skills you wrote yourself are always kept.
:::
Using Skills
Every installed skill is automatically available as a slash command:
# In the CLI or any messaging platform:
/gif-search funny cats
/axolotl help me fine-tune Llama 3 on my dataset
/github-pr-workflow create a PR for the auth refactor
/plan design a rollout for migrating our auth provider
# Just the skill name loads it and lets the agent ask what you need:
/excalidraw
Stacking multiple skills in one command
You can invoke several skills in a single message by chaining slash commands
at the start — every leading /skill token (up to 5) is loaded, and the rest
becomes your instruction:
/github-pr-workflow /test-driven-development fix issue #123 and open a PR
Parsing stops at the first token that isn’t an installed skill, so arguments
that happen to start with / (like file paths) are never swallowed:
/ocr-and-documents /tmp/scan.pdf extract the tables # loads one skill; /tmp/scan.pdf is the argument
For combinations you use repeatedly, prefer a skill bundle — same effect under one short command.
The bundled plan skill is a good example. Running /plan [request] loads the skill’s instructions, telling Hermes to inspect context if needed, write a markdown implementation plan instead of executing the task, and save the result under .hermes/plans/ relative to the active workspace/backend working directory.
You can also interact with skills through natural conversation:
hermes chat --toolsets skills -q "What skills do you have?"
hermes chat --toolsets skills -q "Show me the axolotl skill"
Learning a skill from sources (/learn)
/learn is the fast way to turn something you already know — or a pile of
reference material — into a reusable skill, without hand-writing the
SKILL.md. It is open-ended: point it at anything you can describe and the
agent gathers the material with the tools it already has, then authors a skill
that follows the house authoring standards (≤60-char
description, the standard section order, Hermes-tool framing, no invented
commands).
# A local SDK or doc directory — read with read_file / search_files
/learn the REST client in ~/projects/acme-sdk, focus on auth + pagination
# An online doc page — fetched with web_extract
/learn https://docs.example.com/api/quickstart
# The workflow you just walked the agent through in this conversation
/learn how I just deployed the staging server
# Pasted notes / a described procedure
/learn filing an expense: open the portal, New > Expense, attach the receipt, submit
Because the live agent does the sourcing, /learn works the same in the CLI,
the messaging gateway, the TUI, and the dashboard — and on any terminal backend
(local, Docker, remote), since there is no separate ingestion engine. In the
dashboard, the Skills page has a Learn a skill button that opens a panel
with a directory field, a URL field, and an open-ended text box; it composes a
/learn request and runs it in chat.
There is no model-tool footprint: /learn builds a standards-guided prompt and
hands it to the agent as a normal turn. The agent saves the result with the
skill_manage tool, so the write-approval gate
applies if you have it on.
Progressive Disclosure
Skills use a token-efficient loading pattern:
Level 0: skills_list() → [{name, description, category}, ...] (~3k tokens)
Level 1: skill_view(name) → Full content + metadata (varies)
Level 2: skill_view(name, path) → Specific reference file (varies)
The agent only loads the full skill content when it actually needs it.
SKILL.md Format
<!-- EXTRACT: # Memory -->
# Memory Configuration
```yaml
memory:
memory_enabled: true
user_profile_enabled: true
memory_char_limit: 2200 # ~800 tokens
user_char_limit: 1375 # ~500 tokens
write_approval: false # true = require approval before any memory write
With memory.write_approval: true, memory writes need your approval before they land: interactive CLI turns prompt inline; messaging sessions and the background self-improvement review stage the write for /memory pending → /memory approve <id> / /memory reject <id> review. Toggle at runtime with /memory approval on|off. See Controlling memory writes.
Context File Truncation
Controls how much content Hermes loads from each automatic context file before applying head/tail truncation. This applies to files injected into the system prompt such as SOUL.md, .hermes.md, AGENTS.md, CLAUDE.md, and .cursorrules. It does not affect the read_file tool.
context_file_max_chars: 20000 # default
Raise it when you intentionally keep larger identity or project-context files and run models with enough context window to carry them:
context_file_max_chars: 25000
File Read Safety
Controls how much content a single read_file call can return. Reads that exceed the limit are rejected with an error telling the agent to use offset and limit for a smaller range. This prevents a single read of a minified JS bundle or large data file from flooding the context window.
file_read_max_chars: 100000 # default — ~25-35K tokens
Raise it if you’re on a model with a large context window and frequently read big files. Lower it for small-context models to keep reads efficient:
# Large context model (200K+)
file_read_max_chars: 200000
# Small local model (16K context)
file_read_max_chars: 30000
The agent also deduplicates file reads automatically — if the same file region is read twice and the file hasn’t changed, a lightweight stub is returned instead of re-sending the content. This resets on context compression so the agent can re-read files after their content is summarized away.
Tool Output Truncation Limits
Three related caps control how much raw output a tool can return before Hermes truncates it:
tool_output:
max_bytes: 50000 # terminal output cap (chars)
max_lines: 2000 # read_file pagination cap
max_line_length: 2000 # per-line cap in read_file's line-numbered view
max_bytes— When aterminalcommand produces more than this many characters of combined stdout/stderr, Hermes keeps the first 40% and last 60% and inserts a[OUTPUT TRUNCATED]notice between them. Default50000(≈12-15K tokens across typical tokenisers).max_lines— Upper bound on thelimitparameter of a singleread_filecall. Requests above this are clamped so a single read can’t flood the context window. Default2000.max_line_length— Per-line cap applied whenread_fileemits the line-numbered view. Lines longer than this are truncated to this many chars followed by... [truncated]. Default2000.
Raise the limits on models with large context windows that can afford more raw output per call. Lower them for small-context models to keep tool results compact:
# Large context model (200K+)
tool_output:
max_bytes: 150000
max_lines: 5000
# Small local model (16K context)
tool_output:
max_bytes: 20000
max_lines: 500
Global Toolset Disable
To suppress specific toolsets across the CLI and every gateway platform in one
place, list their names under agent.disabled_toolsets:
agent:
disabled_toolsets:
- memory # hide memory tools + MEMORY_GUIDANCE injection
- web # no web_search / web_extract anywhere
This applies after per-platform tool config (platform_toolsets written by
hermes tools), so a toolset listed here is always removed — even if a
platform’s saved config still lists it. Use this when you want a single
switch for “turn X off everywhere” rather than editing 15+ platform rows in
the hermes tools UI.
Leaving the list empty, or omitting the key, is a no-op.
Git Worktree Isolation
Enable isolated git worktrees for running multiple agents in parallel on the same repo:
worktree: true # Always create a worktree (same as hermes -w)
# worktree: false # Default — only when -w flag is passed
When enabled, each CLI session creates a fresh worktree under .worktrees/ with its own branch. Agents can edit files, commit, push, and create PRs without interfering with each other. Clean worktrees are removed on exit; dirty ones are kept for manual recovery.
By default the new worktree branches from the freshly-fetched remote tip (the current branch’s upstream, otherwise the remote’s default branch) so it starts current with the project rather than from the local clone’s possibly-stale HEAD. This keeps a PR’s diff scoped to the actual change instead of inheriting whatever the local clone was behind by. Set worktree_sync: false to branch from local HEAD instead — useful offline, or when you deliberately want the clone’s exact current state as the base. If the remote can’t be reached, it falls back to local HEAD automatically.
worktree_sync: true # Default — branch from the fetched remote tip
# worktree_sync: false # Branch from local HEAD (offline / pinned base)
You can also list gitignored files to copy into worktrees via .worktreeinclude in your repo root:
# .worktreeinclude
.env
.venv/
node_modules/
Context Compression
Hermes automatically compresses long conversations to stay within your model’s context window. The compression summarizer is a separate LLM call — you can point it at any provider or endpoint.
All compression settings live in config.yaml (no environment variables).
Full reference
compression:
enabled: true # Toggle compression on/off
threshold: 0.50 # Compress at this % of context limit
target_ratio: 0.20 # Fraction of threshold to preserve as recent tail
protect_last_n: 20 # Min recent messages to keep uncompressed
protect_first_n: 3 # Non-system head messages pinned across compactions (0 = pin nothing)
hygiene_hard_message_limit: 5000 # Gateway safety valve — see below
# The summarization model/provider is configured under auxiliary:
auxiliary:
compression:
model: "" # Empty = use main chat model. Override with e.g. "google/gemini-3-flash-preview" for cheaper/faster compression.
provider: "auto" # Provider: "auto", "openrouter", "nous", "codex", "main", etc.
base_url: null
<!-- EXTRACT: # Messaging Gateway -->
# Messaging Gateway
# Messaging Gateway
Chat with Hermes from Telegram, Discord, Slack, WhatsApp, Signal, SMS, Email, Home Assistant, Mattermost, Matrix, DingTalk, Feishu/Lark, WeCom, Weixin, BlueBubbles (iMessage), QQ, Yuanbao, Microsoft Teams, LINE, ntfy, or your browser. The gateway is a single background process that connects to all your configured platforms, handles sessions, runs cron jobs, and delivers voice messages.
For the full voice feature set — including CLI microphone mode, spoken replies in messaging, and Discord voice-channel conversations — see [Voice Mode](/user-guide/features/voice-mode) and [Use Voice Mode with Hermes](/guides/use-voice-mode-with-hermes).
:::tip
Bots need both a model provider and tool providers (TTS, web). A [Nous Portal](/integrations/nous-portal) subscription bundles all of them.
:::
## Platform Comparison
| Platform | Voice | Images | Files | Threads | Reactions | Typing | Streaming |
|----------|:-----:|:------:|:-----:|:-------:|:---------:|:------:|:---------:|
| Telegram | ✅ | ✅ | ✅ | ✅ | — | ✅ | ✅ |
| Discord | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Slack | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Google Chat | — | ✅ | ✅ | ✅ | — | ✅ | — |
| WhatsApp | — | ✅ | ✅ | — | — | ✅ | ✅ |
| Signal | — | ✅ | ✅ | — | — | ✅ | ✅ |
| SMS | — | — | — | — | — | — | — |
| Email | — | ✅ | ✅ | ✅ | — | — | — |
| Home Assistant | — | — | — | — | — | — | — |
| Mattermost | ✅ | ✅ | ✅ | ✅ | — | ✅ | ✅ |
| Matrix | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| DingTalk | — | ✅ | ✅ | — | ✅ | — | ✅ |
| Feishu/Lark | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| WeCom | ✅ | ✅ | ✅ | — | — | — | — |
| WeCom Callback | — | — | — | — | — | — | — |
| Weixin | ✅ | ✅ | ✅ | — | — | ✅ | ✅ |
| BlueBubbles | — | ✅ | ✅ | — | ✅ | ✅ | — |
| QQ | ✅ | ✅ | ✅ | — | — | ✅ | — |
| Yuanbao | ✅ | ✅ | ✅ | — | — | ✅ | ✅ |
| Microsoft Teams | — | ✅ | — | ✅ | — | ✅ | — |
| LINE | — | ✅ | ✅ | — | — | ✅ | — |
| ntfy | — | — | — | — | — | — | — |
| Raft | — | — | — | — | — | — | — |
| IRC | — | — | — | — | — | — | — |
**Voice** = TTS audio replies and/or voice message transcription. **Images** = send/receive images. **Files** = send/receive file attachments. **Threads** = threaded conversations. **Reactions** = emoji reactions on messages. **Typing** = typing indicator while processing. **Streaming** = progressive message updates via editing.
## Architecture
```mermaid
flowchart TB
subgraph Gateway["Hermes Gateway"]
subgraph Adapters["Platform adapters"]
tg[Telegram]
dc[Discord]
wa[WhatsApp]
sl[Slack]
gc[Google Chat]
sig[Signal]
sms[SMS]
em[Email]
ha[Home Assistant]
mm[Mattermost]
mx[Matrix]
dt[DingTalk]
fs[Feishu/Lark]
wc[WeCom]
wcb[WeCom Callback]
wx[Weixin]
bb[BlueBubbles]
qq[QQ]
yb[Yuanbao]
ms[Microsoft Teams]
api["API Server<br/>(OpenAI-compatible)"]
wh[Webhooks]
end
store["Session store<br/>per chat"]
agent["AIAgent<br/>run_agent.py"]
cron["Cron scheduler<br/>ticks every 60s"]
end
tg --> store
dc --> store
wa --> store
sl --> store
gc --> store
sig --> store
sms --> store
em --> store
ha --> store
mm --> store
mx --> store
dt --> store
fs --> store
wc --> store
wcb --> store
wx --> store
bb --> store
qq --> store
yb --> store
ms --> store
api --> store
wh --> store
store --> agent
cron --> store
Each platform adapter receives messages, routes them through a per-chat session store, and dispatches them to the AIAgent for processing. The gateway also runs the cron scheduler, ticking every 60 seconds to execute any due jobs.
Intentional Silence Tokens
For group chats, hooks, and automation flows, Hermes supports explicit silence tokens. If the agent’s final response is exactly one supported token, the gateway suppresses outbound delivery and sends nothing to the chat.
Supported tokens:
[SILENT]SILENTNO_REPLYNO REPLY
Whitespace and case are normalized, but the whole final response must be the token. A sentence like “Use [SILENT] when nothing changed” is delivered normally.
Silence is a delivery decision only. Hermes keeps the assistant silence turn in the session transcript, so the conversation still alternates normally:
user: side-channel chatter
assistant: [SILENT] # stored, not delivered
user: next message
Failed turns still surface as errors; Hermes does not hide failures just because the text resembles a silence token.
Quick Setup
The easiest way to configure messaging platforms is the interactive wizard:
hermes gateway setup # Interactive setup for all messaging platforms
This walks you through configuring each platform with arrow-key selection, shows which platforms are already configured, and offers to start/restart the gateway when done.
Gateway Commands
hermes gateway # Run in foreground
hermes gateway setup # Configure messaging platforms interactively
hermes gateway install # Install as a user service (Linux) / launchd service (macOS)
sudo hermes gateway install --system # Linux only: install a boot-time system service
hermes gateway start # Start the default service
hermes gateway stop # Stop the default service
hermes gateway status # Check default service status
hermes gateway status --system # Linux only: inspect the system service explicitly
Chat Commands (Inside Messaging)
| Command | Description |
|---|---|
/new or /reset | Start a fresh conversation |
/model [provider:model] | Show or change the model (supports provider:model syntax) |
/personality [name] | Set a personality |
/retry | Retry the last message |
/undo | Remove the last exchange |
/status | Show session info |
/whoami | Show your slash command access on this scope (admin / user / unrestricted) |
/stop | Stop the running agent |
/approve | Approve a pending dangerous command |
/deny | Reject a pending dangerous command |
/sethome | Set this chat as the home channel |
/compress | Manually compress conversation context |
/title [name] | Set or show the session title |
/resume [name] | Resume a previously named session |
/usage | Show token usage for this session |
/insights [days] | Show usage insights and analytics |
/reasoning [level|show|hide] | Change reasoning effort or toggle reasoning display |
/voice [on|off|tts|join|leave|status] | Control messaging voice replies and Discord voice-channel behavior |
/rollback [number] | List or restore filesystem checkpoints |
/background <prompt> | Run a prompt in a separate background session |
/reload-mcp | Reload MCP servers from config |
/update | Update Hermes Agent to the latest version |
/help | Sho |
Providers
Current provider families include (see plugins/model-providers/ for the complete bundled set):
- OpenRouter
- Nous Portal
- OpenAI Codex
- Copilot / Copilot ACP
- Anthropic (native)
- Google / Gemini (
gemini) - Alibaba / DashScope (
alibaba,alibaba-coding-plan) - DeepSeek
- Z.AI
- Kimi / Moonshot (
kimi-coding,kimi-coding-cn) - MiniMax (
minimax,minimax-cn,minimax-oauth) - Kilo Code
- Hugging Face
- OpenCode Zen / OpenCode Go
- AWS Bedrock
- Azure Foundry
- NVIDIA NIM
- xAI (Grok)
- Arcee
- GMI Cloud
- StepFun
- Qwen OAuth
- Xiaomi
- Ollama Cloud
- LM Studio
- Tencent TokenHub
- Custom (
provider: custom) — first-class provider for any OpenAI-compatible endpoint - Named custom providers (
custom_providerslist in config.yaml)
Output of runtime resolution
The runtime resolver returns data such as:
providerapi_modebase_urlapi_keysource- provider-specific metadata like expiry/refresh info
Why this matters
This resolver is the main reason Hermes can share auth/runtime logic between:
hermes chat- gateway message handling
- cron jobs running in fresh sessions
- ACP editor sessions
- auxiliary model tasks
OpenRouter and custom OpenAI-compatible base URLs
Hermes contains logic to avoid leaking the wrong API key to a custom endpoint when multiple provider keys exist (e.g. OPENROUTER_API_KEY and OPENAI_API_KEY).
Each provider’s API key is scoped to its own base URL:
OPENROUTER_API_KEYis only sent toopenrouter.aiendpointsOPENAI_API_KEYis used for custom endpoints and as a fallback
Hermes also distinguishes between:
- a real custom endpoint selected by the user
- the OpenRouter fallback path used when no custom endpoint is configured
That distinction is especially important for:
- local model servers
- non-OpenRouter OpenAI-compatible APIs
- switching providers without re-running setup
- config-saved custom endpoints that should keep working even when
OPENAI_BASE_URLis not exported in the current shell
Native Anthropic path
Anthropic is not just “via OpenRouter” anymore.
When provider resolution selects anthropic, Hermes uses:
api_mode = anthropic_messages- the native Anthropic Messages API
agent/anthropic_adapter.pyfor translation
Credential resolution for native Anthropic now prefers refreshable Claude Code credentials over copied env tokens when both are present. In practice that means:
- Claude Code credential files are treated as the preferred source when they include refreshable auth
- manual
ANTHROPIC_TOKEN/CLAUDE_CODE_OAUTH_TOKENvalues still work as explicit overrides - Hermes preflights Anthropic credential refresh before native Messages API calls
- Hermes still retries once on a 401 after rebuilding the Anthropic client, as a fallback path
OpenAI Codex path
Codex uses a separate Responses API path:
api_mode = codex_responses- dedicated credential resolution and auth store support
Auxiliary model routing
Auxiliary tasks such as:
- vision
- web extraction summarization
- context compression summaries
- skills hub operations
- MCP helper operations
- memory flushes
can use their own provider/model routing rather than the main conversational model.
When an auxiliary task is configured with provider main, Hermes resolves that through the same shared runtime path as normal chat. In practice that means:
- env-driven custom endpoints still work
- custom endpoints saved via
hermes model/config.yamlalso work - auxiliary routing can tell the difference between a real saved custom endpoint and the OpenRouter fallback
Fallback models
Hermes supports a configured fallback provider chain — a list of (provider, model) entries tried in order when the primary model encounters errors. The legacy single-pair fallback_model dict is still accepted for back-compat (and migrated on first write).
How it works internally
-
Storage:
AIAgent.__init__stores thefallback_modeldict and sets_fallback_activated = False. -
Trigger points:
_try_activate_fallback()is called from three places in the main retry loop inrun_agent.py:- After max retries on invalid API responses (None choices, missing content)
- On non-retryable client errors (HTTP 401, 403, 404)
- After max retries on transient errors (HTTP 429, 500, 502, 503)
-
Activation flow (
_try_activate_fallback):- Returns
Falseimmediately if already activated or not configured - Calls
resolve_provider_client()fromauxiliary_client.pyto build a new client with proper auth - Determines
api_mode:codex_responsesfor openai-codex,anthropic_messagesfor anthropic,chat_completionsfor everything else - Swaps in-place:
self.model,self.provider,self.base_url,self.api_mode,self.client,self._client_kwargs - For anthropic fallback: builds a native Anthropic client instead of OpenAI-compatible
- Re-evaluates prompt caching (enabled for Claude models on OpenRouter)
- Sets
_fallback_activated = True— prevents firing again - Resets retry count to 0 and continues the loop
- Returns
-
Config flow:
- CLI:
cli.pyreadsCLI_CONFIG["fallback_model"]→ passes toAIAgent(fallback_model=...) - Gateway:
gateway/run.py._load_fallback_model()readsconfig.yaml→ passes toAIAgent - Validation: both
providerandmodelkeys must be non-empty, or fallback is disabled
- CLI:
What does NOT support fallback
- Subagent delegation (
tools/delegate_tool.py): subagents inherit the parent’s provider but not the fallback config - Auxiliary tasks: use their own independent provider auto-detection chain (see Auxiliary model routing above)
Cron jobs do support fallback: run_job() reads fallback_providers (or legacy fallback_model) from config.yaml and passes it to AIAgent(fallback_model=...), matching the gateway’s _load_fallback_model() pattern. See Cron Internals.
Test coverage
Fallback behavior is exercised across several suites:
tests/run_agent/test_fallback_credential_isolation.py— credential isolation between primary and fallbacktests/hermes_cli/test_fallback_cmd.py— the/fallbackCLI commandtests/gateway/test_fallback_eviction.py— gateway eviction of failed providers
Related docs
Security
Pre-execution security scanning and secret redaction:
security:
redact_secrets: true # Redact API key patterns in tool output and logs (on by default)
tirith_enabled: true # Enable Tirith security scanning for terminal commands
tirith_path: "tirith" # Path to tirith binary (default: "tirith" in $PATH)
tirith_timeout: 5 # Seconds to wait for tirith scan before timing out
tirith_fail_open: true # Allow command execution if tirith is unavailable
website_blocklist: # See Website Blocklist section below
enabled: false
domains: []
shared_files: []
redact_secrets— whentrue, automatically detects and redacts patterns that look like API keys, tokens, and passwords in tool output before it enters the conversation context and logs. On by default. Set tofalseexplicitly only when you need raw credential-like strings for debugging or redactor development.tirith_enabled— whentrue, terminal commands are scanned by Tirith before execution to detect potentially dangerous operations.tirith_path— path to the tirith binary. Set this if tirith is installed in a non-standard location.tirith_timeout— maximum seconds to wait for a tirith scan. Commands proceed if the scan times out.tirith_fail_open— whentrue(default), commands are allowed to execute if tirith is unavailable or fails. Set tofalseto block commands when tirith cannot verify them.
Website Blocklist
Block specific domains from being accessed by the agent’s web and browser tools:
security:
website_blocklist:
enabled: false # Enable URL blocking (default: false)
domains: # List of blocked domain patterns
- "*.internal.company.com"
- "admin.example.com"
- "*.local"
shared_files: # Load additional rules from external files
- "/etc/hermes/blocked-sites.txt"
When enabled, any URL matching a blocked domain pattern is rejected before the web or browser tool executes. This applies to web_search, web_extract, browser_navigate, and any tool that accesses URLs.
Domain rules support:
- Exact domains:
admin.example.com - Wildcard subdomains:
*.internal.company.com(blocks all subdomains) - TLD wildcards:
*.local
Shared files contain one domain rule per line (blank lines and # comments are ignored). Missing or unreadable files log a warning but don’t disable other web tools.
The policy is cached for 30 seconds, so config changes take effect quickly without restart.
Smart Approvals
Control how Hermes handles potentially dangerous commands:
approvals:
mode: manual # manual | smart | off
| Mode | Behavior |
|---|---|
manual (default) | Prompt the user before executing any flagged command. In the CLI, shows an interactive approval dialog. In messaging, queues a pending approval request. |
smart | Use an auxiliary LLM to assess whether a flagged command is actually dangerous. Low-risk commands are auto-approved with session-level persistence. Genuinely risky commands are escalated to the user. |
off | Skip all approval checks. Equivalent to HERMES_YOLO_MODE=true. Use with caution. |
Smart mode is particularly useful for reducing approval fatigue — it lets the agent work more autonomously on safe operations while still catching genuinely destructive commands.
:::warning
Setting approvals.mode: off disables all safety checks for terminal commands. Only use this in trusted, sandboxed environments.
:::
Deny rules
approvals.deny is a list of glob patterns that block matching terminal commands unconditionally — even under --yolo, /yolo, or mode: off. It’s the user-editable counterpart to the built-in hardline blocklist:
approvals:
deny:
- "git push --force*"
- "*curl*|*sh*"
Patterns are case-insensitive fnmatch globs and must be quoted in YAML (a bare leading * is a parse error). See Security — User-Defined Deny Rules for details.
Checkpoints
Automatic filesystem snapshots before destructive file operations. See the Checkpoints & Rollback for details.
checkpoints:
enabled: false # Enable automatic checkpoints (also: hermes chat --checkpoints). Default: false (opt-in).
max_snapshots: 20 # Max checkpoints to keep per directory (default: 20)
Delegation
Configure subagent behavior for the delegate tool:
delegation:
# model: "google/gemini-3-flash-preview" # Override model (empty = inherit parent)
# provider: "openrouter" # Override provider (empty = inherit parent)
# base_url: "http://localhost:1234/v1" # Direct OpenAI-compatible endpoint (takes precedence over provider)
# api_key: "local-key" # API key for base_url (falls back to OPENAI_API_KEY)
# api_mode: "" # Wire protocol for base_url: "chat_completions", "codex_responses", or "anthropic_messages". Empty = auto-detect from URL (e.g. /anthropic suffix → anthropic_messages). Set explicitly for non-standard endpoints the heuristic can't detect.
max_concurrent_children: 3 # Parallel children per batch (floor 1, no ceiling). Also via DELEGATION_MAX_CONCURRENT_CHILDREN env var.
max_spawn_depth: 1 # Delegation tree depth cap (1-3, clamped). 1 = flat (default): parent spawns leaves that cannot delegate. 2 = orchestrator children can spawn leaf grandchildren. 3 = three levels.
orchestrator_enabled: true # Global kill switch. When false, role="orchestrator" is ignored and every child is forced to leaf regardless of max_spawn_depth.
Subagent provider:model override: By default, subagents inherit the parent agent’s provider and model. Set delegation.provider and delegation.model to route subagents to a different provider:model pair — e.g., use a cheap/fast model for narrowly-scoped subtasks while your primary agent runs an expensive reasoning model.
Direct endpoint override: If you want the obvious custom-endpoint path, set delegation.base_url, delegation.api_key, and delegation.model. That sends subagents directly to that OpenAI-compatible endpoint and takes precedence over delegation.provider. If delegation.api_key is omitted, Hermes falls back to OPENAI_API_KEY only.
Wire protocol (api_mode): Hermes auto-detects the wire protocol from delegation.base_url (e.g. paths ending in /anthropic → anthropic_messages; Codex / native Anthropic / Kimi-coding hostnames keep their existing detection). For endpoints the heuristic can’t classify — for example Azure AI Foundry, MiniMax, Zhipu GLM, or LiteLLM proxies fronting an Anthropic-shaped backend — set delegation.api_mode