# The Hermes Bible — Full Knowledge Base > Unofficial, community-built knowledge base for Hermes Agent by Nous Research. This single document concatenates the full text of every documentation page and community flow. Paste it (or its URL) into an LLM to check whether a Hermes setup is configured correctly. Source: https://hermesbible.com · Index: https://hermesbible.com/llms.txt --- # Documentation ## Installation Section: Getting Started · URL: https://hermesbible.com/docs/getting-started/installation Get Hermes Agent up and running in under two minutes! ## 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](https://hermes-agent.nousresearch.com/) from our website and run it. ### Without Hermes Desktop: For a command-line only install without Hermes Desktop, run: #### Linux / macOS / WSL2 / Android (Termux) ```bash curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash ``` #### Windows (native) Run in powershell: ```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 ```bash 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 | |---|---|---|---| | pip install | Python site-packages | `~/.local/bin/hermes` (console_scripts) | `~/.hermes/` | | 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: ```bash source ~/.bashrc # or: source ~/.zshrc hermes # Start chatting! ``` To reconfigure individual settings later, use the dedicated commands: ```bash 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](/user-guide/features/tool-gateway) (web search, image generation, TTS, cloud browser). Skip the per-tool key juggling: > > ```bash > hermes setup --portal > ``` > > That logs you in, sets Nous as your provider, and turns on the Tool Gateway in one command. --- ## Prerequisites **Installer:** On non-Windows platforms, the only prerequisite is **Git**. The installer automatically handles everything else: - **uv** (fast Python package manager) - **Python 3.11** (via uv, no sudo needed) - **Node.js v22** (for browser automation and WhatsApp bridge) - **ripgrep** (fast file search) - **ffmpeg** (audio format conversion for TTS) > **INFO** > > You do **not** need to install Python, Node.js, ripgrep, or ffmpeg manually. The installer detects what's missing and installs it for you. Just make sure `git` is available (`git --version`). > **TIP — Nix users** > > If you use Nix (on NixOS, macOS, or Linux), there's a dedicated setup path with a Nix flake, declarative NixOS module, and optional container mode. See the **[Nix & NixOS Setup](/docs/getting-started/nix-setup)** guide. --- ## Manual / Developer Installation If you want to clone the repo and install from source — for contributing, running from a specific branch, or having full control over the virtual environment — see the [Development Setup](/docs/developer-guide/contributing#development-setup) section in the Contributing guide. --- ## Non-Sudo / System Service User Installs Running Hermes as a dedicated unprivileged user (e.g. a `hermes` systemd service account, or any user without `sudo` access) is supported. The only thing on the install path that genuinely needs root is Playwright's `--with-deps` step, which `apt`-installs shared libraries (`libnss3`, `libxkbcommon`, etc.) used by Chromium. The installer detects whether sudo is available and gracefully degrades when it isn't — it will install the Chromium binary into the service user's own Playwright cache and print the exact command an administrator needs to run separately. **Recommended split (Debian/Ubuntu):** 1. **One time, as an admin user with sudo**, install the system libraries Chromium needs: ```bash sudo npx playwright install-deps chromium ``` (You can run this from anywhere — `npx` will fetch Playwright on the fly.) 2. **As the unprivileged service user**, run the regular installer. It will detect the missing sudo, skip `--with-deps`, and install Chromium into the user's local Playwright cache: ```bash curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash ``` If you want to skip the Playwright step entirely — for example because you're running headless and don't need browser automation — pass `--skip-browser`: ```bash curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash -s -- --skip-browser ``` 3. **Make `hermes` available to the service user's shells.** The installer writes the launcher to `~/.local/bin/hermes`. System service accounts often have a minimal PATH that doesn't include `~/.local/bin`. Either add it to the user's environment, or symlink the launcher into a system location: ```bash # Option A — add to the service user's profile echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc # Option B — symlink system-wide (run as an admin) sudo ln -s /home/hermes/.hermes/hermes-agent/venv/bin/hermes /usr/local/bin/hermes ``` 4. **Verify:** `hermes doctor` should now run cleanly. If you get `ModuleNotFoundError: No module named 'dotenv'`, you're invoking the repo source `hermes` file (`~/.hermes/hermes-agent/hermes`) with system Python instead of the venv launcher (`~/.hermes/hermes-agent/venv/bin/hermes`) — fix step 3. The same pattern works on Arch (the installer uses pacman with the same sudo-detection logic), Fedora/RHEL, and openSUSE — those distros don't support `--with-deps` at all, so an administrator always installs the system libraries separately. The relevant `dnf`/`zypper` commands are printed by the installer. --- ## Troubleshooting | Problem | Solution | |---------|----------| | `hermes: command not found` | Reload your shell (`source ~/.bashrc`) or check PATH | | `API key not set` | Run `hermes model` to configure your provider, or `hermes config set OPENROUTER_API_KEY your_key` | | Missing config after update | Run `hermes config check` then `hermes config migrate` | For more diagnostics, run `hermes doctor` — it will tell you exactly what's missing and how to fix it. ## Install method auto-detection Hermes auto-detects whether it was installed via `pip`, the git installer, Homebrew, or NixOS, and `hermes update` prints the matching update command for that path. There's no env var to set — the detection is based on the install layout (Python site-packages, `~/.hermes/hermes-agent/`, Homebrew prefix, or Nix store path). `hermes doctor` also surfaces the detected method under its environment summary. --- --- ## Quickstart Section: Getting Started · URL: https://hermesbible.com/docs/getting-started/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](https://www.youtube.com/playlist?list=PLmpUb_PWAkDxewld5ZYyKifuHxgIbiq2d) playlist. > **Video:** [Watch on YouTube](https://www.youtube.com/watch?v=R3YOGfTBcQg) ## 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. --- ## 1. Install Hermes Agent ### With the Hermes Desktop installer on macOS or Windows (recommended) To easily install the command-line and desktop applications, [download the Hermes Desktop installer](https://hermes-agent.nousresearch.com/) from our website and run it. ### Without Hermes Desktop: For a command-line only install without Hermes Desktop, run: #### Linux / macOS / WSL2 / Android (Termux) ```bash curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash ``` #### Windows (native) Run in powershell: ```powershell iex (irm https://hermes-agent.nousresearch.com/install.ps1) ``` > **TIP — Android / Termux** > > If you're installing on a phone, see the dedicated [Termux guide](/docs/getting-started/termux) for the tested manual path, supported extras, and current Android-specific limitations. After it finishes, reload your shell: ```bash source ~/.bashrc # or source ~/.zshrc ``` For detailed installation options, prerequisites, and troubleshooting, see the [Installation guide](/docs/getting-started/installation). ## 2. Choose a Provider The single most important setup step. Use `hermes model` to walk through the choice interactively: ```bash hermes model ``` > **TIP — Easiest path: Nous Portal** > > One subscription covers 300+ models plus the [Tool Gateway](/docs/user-guide/features/tool-gateway) (web search, image generation, TTS, cloud browser). On a fresh install: > > ```bash > hermes setup --portal > ``` > > That logs you in, sets Nous as your provider, and turns on the Tool Gateway in one command. Good defaults: | Provider | What it is | How to set up | |----------|-----------|---------------| | **Nous Portal** | Subscription-based, zero-config | OAuth login via `hermes model` | | **OpenAI Codex** | ChatGPT OAuth, uses Codex models | Device code auth via `hermes model` | | **Anthropic** | Claude models directly — Max plan + extra usage credits (OAuth), or API key for pay-per-token | `hermes model` → OAuth login (requires Max + extra credits), or an Anthropic API key | | **OpenRouter** | Multi-provider routing across many models | Enter your API key | | **Z.AI** | GLM / Zhipu-hosted models | Set `GLM_API_KEY` / `ZAI_API_KEY` (also accepts `Z_AI_API_KEY`) | | **Kimi / Moonshot** | Moonshot-hosted coding and chat models | Set `KIMI_API_KEY` (or the Kimi-Coding-specific `KIMI_CODING_API_KEY`) | | **Kimi / Moonshot China** | China-region Moonshot endpoint | Set `KIMI_CN_API_KEY` | | **Arcee AI** | Trinity models | Set `ARCEEAI_API_KEY` | | **GMI Cloud** | Multi-model direct API | Set `GMI_API_KEY` | | **MiniMax (OAuth)** | MiniMax frontier model via browser OAuth — no API key needed (model name in `hermes_cli/models.py` may change between releases) | `hermes model` → MiniMax (OAuth) | | **MiniMax** | International MiniMax endpoint | Set `MINIMAX_API_KEY` | | **MiniMax China** | China-region MiniMax endpoint | Set `MINIMAX_CN_API_KEY` | | **Alibaba Cloud** | Qwen models via DashScope | Set `DASHSCOPE_API_KEY` (Qwen Coding Plan also accepts `ALIBABA_CODING_PLAN_API_KEY`) | | **Hugging Face** | 20+ open models via unified router (Qwen, DeepSeek, Kimi, etc.) | Set `HF_TOKEN` | | **AWS Bedrock** | Claude, Nova, Llama, DeepSeek via native Converse API | IAM role or `aws configure` ([guide](/docs/guides/aws-bedrock)) | | **Azure Foundry** | Azure AI Foundry-hosted models | Set `AZURE_FOUNDRY_API_KEY` + `AZURE_FOUNDRY_BASE_URL` | | **Google AI Studio** | Gemini models via direct API | Set `GOOGLE_API_KEY` / `GEMINI_API_KEY` | | **Google Gemini (OAuth)** | Gemini via the `google-gemini-cli` OAuth flow — no key needed | `hermes model` → Google Gemini (OAuth) | | **xAI** | Grok models via direct API | Set `XAI_API_KEY` | | **xAI Grok OAuth** | SuperGrok / Premium+ subscription, no API key needed | `hermes model` → xAI Grok OAuth | | **NovitaAI** | Multi-model API gateway | Set `NOVITA_API_KEY` | | **StepFun** | Step Plan models | Set `STEPFUN_API_KEY` | | **Xiaomi MiMo** | Xiaomi-hosted models | Set `XIAOMI_API_KEY` | | **Tencent TokenHub** | Tencent-hosted models | Set `TOKENHUB_API_KEY` | | **Ollama Cloud** | Managed Ollama-hosted models | Set `OLLAMA_API_KEY` | | **LM Studio** | Local desktop app exposing an OpenAI-compatible API | Set `LM_API_KEY` (and `LM_BASE_URL` if non-default) | | **Qwen OAuth** | Qwen Portal browser OAuth — no API key needed | `hermes model` → Qwen OAuth | | **Kilo Code** | KiloCode-hosted models | Set `KILOCODE_API_KEY` | | **OpenCode Zen** | Pay-as-you-go access to curated models | Set `OPENCODE_ZEN_API_KEY` | | **OpenCode Go** | $10/month subscription for open models | Set `OPENCODE_GO_API_KEY` | | **DeepSeek** | Direct DeepSeek API access | Set `DEEPSEEK_API_KEY` | | **NVIDIA NIM** | Nemotron models via build.nvidia.com or local NIM | Set `NVIDIA_API_KEY` (optional: `NVIDIA_BASE_URL`) | | **GitHub Copilot** | GitHub Copilot subscription (GPT-5.x, Claude, Gemini, etc.) | OAuth via `hermes model`, or `COPILOT_GITHUB_TOKEN` / `GH_TOKEN` | | **GitHub Copilot ACP** | Copilot ACP agent backend (spawns local `copilot` CLI) | `hermes model` (requires `copilot` CLI + `copilot login`) | | **Custom Endpoint** | VLLM, SGLang, Ollama, or any OpenAI-compatible API | Set base URL + API key | For most first-time users: choose a provider, accept the defaults unless you know why you're changing them. The full provider catalog with env vars and setup steps lives on the [Providers](/docs/integrations/providers) page. > **CAUTION — Minimum context: 64K tokens** > > Hermes Agent requires a model with at least **64,000 tokens** of context. Models with smaller windows cannot maintain enough working memory for multi-step tool-calling workflows and will be rejected at startup. Most hosted models (Claude, GPT, Gemini, Qwen, DeepSeek) meet this easily. If you're running a local model, set its context size to at least 64K (e.g. `--ctx-size 65536` for llama.cpp or `-c 65536` for Ollama). > **TIP** > > You can switch providers at any time with `hermes model` — no lock-in. For a full list of all supported providers and setup details, see [AI Providers](/docs/integrations/providers). ### How settings are stored Hermes separates secrets from normal config: - **Secrets and tokens** → `~/.hermes/.env` - **Non-secret settings** → `~/.hermes/config.yaml` The easiest way to set values correctly is through the CLI: ```bash hermes config set model anthropic/claude-opus-4.6 hermes config set terminal.backend docker hermes config set OPENROUTER_API_KEY sk-or-... ``` The right value goes to the right file automatically. ## 3. Run Your First Chat ```bash hermes # classic CLI hermes --tui # modern TUI (recommended) ``` You'll see a welcome banner with your model, available tools, and skills. Use a prompt that's specific and easy to verify: > **TIP — Pick your interface** > > Hermes ships with two terminal interfaces: the classic `prompt_toolkit` CLI and a newer [TUI](/docs/user-guide/tui) with modal overlays, mouse selection, and non-blocking input. Both share the same sessions, slash commands, and config — try each with `hermes` vs `hermes --tui`. ``` Summarize this repo in 5 bullets and tell me what the main entrypoint is. ``` ``` Check my current directory and tell me what looks like the main project file. ``` ``` Help me set up a clean GitHub PR workflow for this codebase. ``` **What success looks like:** - The banner shows your chosen model/provider - Hermes replies without error - It can use a tool if needed (terminal, file read, web search) - The conversation continues normally for more than one turn If that works, you're past the hardest part. ## 4. Verify Sessions Work Before moving on, make sure resume works: ```bash hermes --continue # Resume the most recent session hermes -c # Short form ``` That should bring you back to the session you just had. If it doesn't, check whether you're in the same profile and whether the session actually saved. This matters later when you're juggling multiple setups or machines. ## 5. Try Key Features ### Use the terminal ``` ❯ What's my disk usage? Show the top 5 largest directories. ``` The agent runs terminal commands on your behalf and shows results. ### Slash commands Type `/` to see an autocomplete dropdown of all commands: | Command | What it does | |---------|-------------| | `/help` | Show all available commands | | `/tools` | List available tools | | `/model` | Switch models interactively | | `/personality pirate` | Try a fun personality | | `/save` | Save the conversation | ### Multi-line input Press `Alt+Enter`, `Ctrl+J`, or `Shift+Enter` to add a new line. `Shift+Enter` requires a terminal that sends it as a distinct sequence (Kitty / foot / WezTerm / Ghostty by default; iTerm2 / Alacritty / VS Code terminal once the Kitty keyboard protocol is enabled). `Alt+Enter` and `Ctrl+J` work in every terminal. ### Interrupt the agent If the agent is taking too long, type a new message and press Enter — it interrupts the current task and switches to your new instructions. `Ctrl+C` also works. ## 6. Add the Next Layer Only after the base chat works. Pick what you need: ### Bot or shared assistant ```bash hermes gateway setup # Interactive platform configuration ``` Connect [Telegram](/user-guide/messaging/telegram), [Discord](/user-guide/messaging/discord), [Slack](/user-guide/messaging/slack), [WhatsApp](/user-guide/messaging/whatsapp), [Signal](/user-guide/messaging/signal), [Email](/user-guide/messaging/email), or [Home Assistant](/user-guide/messaging/homeassistant), or [Microsoft Teams](/user-guide/messaging/teams). ### Automation and tools - `hermes tools` — tune tool access per platform - `hermes skills` — browse and install reusable workflows - Cron — only after your bot or CLI setup is stable ### Sandboxed terminal For safety, run the agent in a Docker container or on a remote server: ```bash hermes config set terminal.backend docker # Docker isolation hermes config set terminal.backend ssh # Remote server ``` ### Voice mode ```bash # From the Hermes install directory (the curl installer placed it at # ~/.hermes/hermes-agent on Linux/macOS or %LOCALAPPDATA%\hermes\hermes-agent on Windows): cd ~/.hermes/hermes-agent uv pip install -e ".[voice]" # Includes faster-whisper for free local speech-to-text ``` Then in the CLI: `/voice on`. Press `Ctrl+B` to record. See [Voice Mode](/docs/user-guide/features/voice-mode). ### Skills Skills are on-demand instruction documents that teach Hermes how to do a specific task — deploy to Kubernetes, open a GitHub PR, fine-tune a model, search for GIFs. Each is a `SKILL.md` file with a name, a description, and a step-by-step procedure. The agent reads the short descriptions for free and only loads a skill's full content when a task actually calls for it, so adding skills doesn't bloat every request. Hermes ships with a catalog of bundled skills already installed in `~/.hermes/skills/`. You can add more from the Skills Hub, or write your own. **Browse and install from the hub:** ```bash hermes skills browse # list everything available hermes skills search kubernetes # find skills by keyword hermes skills install openai/skills/k8s # install one (runs a security scan first) ``` The install argument is a `source/path` slug from the hub — `openai/skills/k8s` means the `k8s` skill from OpenAI's catalog. `hermes skills browse` shows the exact slugs to use. **Use a skill** — every installed skill becomes a slash command automatically: ```bash /k8s deploy the staging manifest # run the skill with a request /k8s # load it and let Hermes ask what you need ``` This works in the CLI and in any connected messaging platform. You don't have to install everything up front — the agent picks the right bundled skill on its own during normal conversation when a task matches one. See [Skills System](/docs/user-guide/features/skills) for writing your own, external skill directories, and the full hub source list. ### MCP servers ```yaml # Add to ~/.hermes/config.yaml mcp_servers: github: command: npx args: ["-y", "@modelcontextprotocol/server-github"] env: GITHUB_PERSONAL_ACCESS_TOKEN: "ghp_xxx" ``` ### Editor integration (ACP) ACP support ships with the standard `[all]` extras, so the curl installer already includes it. Just run: ```bash hermes acp ``` (If you installed without `[all]`, run `cd ~/.hermes/hermes-agent && uv pip install -e ".[acp]"` first.) See [ACP Editor Integration](/docs/user-guide/features/acp). --- ## Common Failure Modes These are the problems that waste the most time: | Symptom | Likely cause | Fix | |---|---|---| | Hermes opens but gives empty or broken replies | Provider auth or model selection is wrong | Run `hermes model` again and confirm provider, model, and auth | | Custom endpoint "works" but returns garbage | Wrong base URL, model name, or not actually OpenAI-compatible | Verify the endpoint in a separate client first | | Gateway starts but nobody can message it | Bot token, allowlist, or platform setup is incomplete | Re-run `hermes gateway setup` and check `hermes gateway status` | | `hermes --continue` can't find old session | Switched profiles or session never saved | Check `hermes sessions list` and confirm you're in the right profile | | Model unavailable or odd fallback behavior | Provider routing or fallback settings are too aggressive | Keep routing off until the base provider is stable | | `hermes doctor` flags config problems | Config values are missing or stale | Fix the config, retest a plain chat before adding features | ## Recovery Toolkit When something feels off, use this order: 1. `hermes doctor` 2. `hermes model` 3. `hermes setup` 4. `hermes sessions list` 5. `hermes --continue` 6. `hermes gateway status` That sequence gets you from "broken vibes" back to a known state fast. --- ## Quick Reference | Command | Description | |---------|-------------| | `hermes` | Start chatting | | `hermes model` | Choose your LLM provider and model | | `hermes tools` | Configure which tools are enabled per platform | | `hermes setup` | Full setup wizard (configures everything at once) | | `hermes doctor` | Diagnose issues | | `hermes update` | Update to latest version | | `hermes gateway` | Start the messaging gateway | | `hermes --continue` | Resume last session | ## Next Steps - **[CLI Guide](/docs/user-guide/cli)** — Master the terminal interface - **[Configuration](/docs/user-guide/configuration)** — Customize your setup - **[Messaging Gateway](/docs/user-guide/messaging/index)** — Connect Telegram, Discord, Slack, WhatsApp, Signal, Email, Home Assistant, Teams, and more - **[Tools & Toolsets](/docs/user-guide/features/tools)** — Explore available capabilities - **[AI Providers](/docs/integrations/providers)** — Full provider list and setup details - **[Skills System](/docs/user-guide/features/skills)** — Reusable workflows and knowledge - **[Tips & Best Practices](/docs/guides/tips)** — Power user tips --- --- ## Learning Path Section: Getting Started · URL: https://hermesbible.com/docs/getting-started/learning-path Hermes Agent can do a lot — CLI assistant, Telegram/Discord bot, task automation, RL training, and more. This page helps you figure out where to start and what to read based on your experience level and what you're trying to accomplish. > **TIP — Start Here** > > If you haven't installed Hermes Agent yet, begin with the [Installation guide](/getting-started/installation) and then run through the [Quickstart](/getting-started/quickstart). Everything below assumes you have a working installation. > **TIP — First-time provider setup** > > First-time users almost always want `hermes setup --portal` — one OAuth covers a model plus the four Tool Gateway tools (search/image/TTS/browser). See [Nous Portal](/integrations/nous-portal). ## How to Use This Page - **Know your level?** Jump to the [experience-level table](#by-experience-level) and follow the reading order for your tier. - **Have a specific goal?** Skip to [By Use Case](#by-use-case) and find the scenario that matches. - **Just browsing?** Check the [Key Features](#key-features-at-a-glance) table for a quick overview of everything Hermes Agent can do. ## By Experience Level | Level | Goal | Recommended Reading | Time Estimate | |---|---|---|---| | **Beginner** | Get up and running, have basic conversations, use built-in tools | [Installation](/getting-started/installation) → [Quickstart](/getting-started/quickstart) → [CLI Usage](/user-guide/cli) → [Configuration](/user-guide/configuration) | ~1 hour | | **Intermediate** | Set up messaging bots, use advanced features like memory, cron jobs, and skills | [Sessions](/user-guide/sessions) → [Messaging](/user-guide/messaging) → [Tools](/user-guide/features/tools) → [Skills](/user-guide/features/skills) → [Memory](/user-guide/features/memory) → [Cron](/user-guide/features/cron) | ~2–3 hours | | **Advanced** | Build custom tools, create skills, train models with RL, contribute to the project | [Architecture](/developer-guide/architecture) → [Adding Tools](/developer-guide/adding-tools) → [Creating Skills](/developer-guide/creating-skills) → [Contributing](/developer-guide/contributing) | ~4–6 hours | ## By Use Case Pick the scenario that matches what you want to do. Each one links you to the relevant docs in the order you should read them. ### "I want a CLI coding assistant" Use Hermes Agent as an interactive terminal assistant for writing, reviewing, and running code. 1. [Installation](/getting-started/installation) 2. [Quickstart](/getting-started/quickstart) 3. [CLI Usage](/user-guide/cli) 4. [Code Execution](/user-guide/features/code-execution) 5. [Context Files](/user-guide/features/context-files) 6. [Tips & Tricks](/guides/tips) > **TIP** > > Pass files directly into your conversation with context files. Hermes Agent can read, edit, and run code in your projects. ### "I want a Telegram/Discord bot" Deploy Hermes Agent as a bot on your favorite messaging platform. 1. [Installation](/getting-started/installation) 2. [Configuration](/user-guide/configuration) 3. [Messaging Overview](/user-guide/messaging) 4. [Telegram Setup](/user-guide/messaging/telegram) 5. [Discord Setup](/user-guide/messaging/discord) 6. [Voice Mode](/user-guide/features/voice-mode) 7. [Use Voice Mode with Hermes](/guides/use-voice-mode-with-hermes) 8. [Security](/user-guide/security) For full project examples, see: - [Daily Briefing Bot](/guides/daily-briefing-bot) - [Team Telegram Assistant](/guides/team-telegram-assistant) ### "I want to automate tasks" Schedule recurring tasks, run batch jobs, or chain agent actions together. 1. [Quickstart](/getting-started/quickstart) 2. [Cron Scheduling](/user-guide/features/cron) 3. [Batch Processing](/user-guide/features/batch-processing) 4. [Delegation](/user-guide/features/delegation) 5. [Hooks](/user-guide/features/hooks) > **TIP** > > Cron jobs let Hermes Agent run tasks on a schedule — daily summaries, periodic checks, automated reports — without you being present. ### "I want to build custom tools/skills" Extend Hermes Agent with your own tools and reusable skill packages. 1. [Plugins](/user-guide/features/plugins) 2. [Build a Hermes Plugin](/guides/build-a-hermes-plugin) 3. [Tools Overview](/user-guide/features/tools) 4. [Skills Overview](/user-guide/features/skills) 5. [MCP (Model Context Protocol)](/user-guide/features/mcp) 6. [Architecture](/developer-guide/architecture) 7. [Adding Tools](/developer-guide/adding-tools) 8. [Creating Skills](/developer-guide/creating-skills) > **TIP** > > For most custom tool creation, start with plugins. The [Adding Tools](/developer-guide/adding-tools) > page is for built-in Hermes core development, not the usual user/custom-tool path. ### "I want to train models" Use reinforcement learning to fine-tune model behavior with Hermes Agent's RL training pipeline (powered by [Atropos](https://github.com/NousResearch/atropos)). 1. [Quickstart](/getting-started/quickstart) 2. [Configuration](/user-guide/configuration) 3. [Atropos RL Environments](https://github.com/NousResearch/atropos) (external) 4. [Provider Routing](/user-guide/features/provider-routing) 5. [Architecture](/developer-guide/architecture) > **TIP** > > RL training works best when you already understand the basics of how Hermes Agent handles conversations and tool calls. Run through the Beginner path first if you're new. ### "I want to use it as a Python library" Integrate Hermes Agent into your own Python applications programmatically. 1. [Installation](/getting-started/installation) 2. [Quickstart](/getting-started/quickstart) 3. [Python Library Guide](/guides/python-library) 4. [Architecture](/developer-guide/architecture) 5. [Tools](/user-guide/features/tools) 6. [Sessions](/user-guide/sessions) ## Key Features at a Glance Not sure what's available? Here's a quick directory of major features: | Feature | What It Does | Link | |---|---|---| | **Tools** | Built-in tools the agent can call (file I/O, search, shell, etc.) | [Tools](/user-guide/features/tools) | | **Skills** | Installable plugin packages that add new capabilities | [Skills](/user-guide/features/skills) | | **Memory** | Persistent memory across sessions | [Memory](/user-guide/features/memory) | | **Context Files** | Feed files and directories into conversations | [Context Files](/user-guide/features/context-files) | | **MCP** | Connect to external tool servers via Model Context Protocol | [MCP](/user-guide/features/mcp) | | **Cron** | Schedule recurring agent tasks | [Cron](/user-guide/features/cron) | | **Delegation** | Spawn sub-agents for parallel work | [Delegation](/user-guide/features/delegation) | | **Code Execution** | Run Python scripts that call Hermes tools programmatically | [Code Execution](/user-guide/features/code-execution) | | **Browser** | Web browsing and scraping | [Browser](/user-guide/features/browser) | | **Hooks** | Event-driven callbacks and middleware | [Hooks](/user-guide/features/hooks) | | **Batch Processing** | Process multiple inputs in bulk | [Batch Processing](/user-guide/features/batch-processing) | | **Provider Routing** | Route requests across multiple LLM providers | [Provider Routing](/user-guide/features/provider-routing) | ## What to Read Next Based on where you are right now: - **Just finished installing?** → Head to the [Quickstart](/getting-started/quickstart) to run your first conversation. - **Completed the Quickstart?** → Read [CLI Usage](/user-guide/cli) and [Configuration](/user-guide/configuration) to customize your setup. - **Comfortable with the basics?** → Explore [Tools](/user-guide/features/tools), [Skills](/user-guide/features/skills), and [Memory](/user-guide/features/memory) to unlock the full power of the agent. - **Setting up for a team?** → Read [Security](/user-guide/security) and [Sessions](/user-guide/sessions) to understand access control and conversation management. - **Ready to build?** → Jump into the [Developer Guide](/developer-guide/architecture) to understand the internals and start contributing. - **Want practical examples?** → Check out the [Guides](/guides/tips) section for real-world projects and tips. > **TIP** > > You don't need to read everything. Pick the path that matches your goal, follow the links in order, and you'll be productive quickly. You can always come back to this page to find your next step. --- --- ## Updating & Uninstalling Section: Getting Started · URL: https://hermesbible.com/docs/getting-started/updating ## Updating ### Git installs Update to the latest version with a single command: ```bash hermes update ``` This pulls the latest code from `main`, updates dependencies, and prompts you to configure any new options that were added since your last update. ### pip installs PyPI releases track **tagged versions** (major and minor releases), not every commit on `main`. Check for updates and upgrade with: ```bash hermes update --check # see if a newer release is on PyPI hermes update # runs pip install --upgrade hermes-agent ``` Or manually: ```bash pip install --upgrade hermes-agent # or: uv pip install --upgrade hermes-agent ``` > **TIP** > > `hermes update` automatically detects new configuration options and prompts you to add them. If you skipped that prompt, you can manually run `hermes config check` to see missing options, then `hermes config migrate` to interactively add them. ### What happens during an update (git installs) When you run `hermes update`, the following steps occur: 1. **Pairing-data snapshot** — a lightweight pre-update state snapshot is saved (covers `~/.hermes/pairing/`, Feishu comment rules, and other state files that get modified at runtime). Recoverable via the snapshot restore flow described under [Snapshots and rollback](/docs/user-guide/checkpoints-and-rollback), or by extracting the most recent quick-snapshot zip Hermes wrote next to your `~/.hermes/` directory. 2. **Git pull** — pulls the latest code from the `main` branch and updates submodules 3. **Post-pull syntax validation + auto-rollback** — after the pull, Hermes compiles the eight critical files every `hermes` invocation imports at startup. If any fails to parse (e.g. an orphan merge-conflict marker, an accidentally truncated file), Hermes runs `git reset --hard ` to roll the install back so your shell stays bootable. Re-run `hermes update` once the upstream fix lands. 4. **Dependency install** — runs `uv pip install -e ".[all]"` to pick up new or changed dependencies 5. **Config migration** — detects new config options added since your version and prompts you to set them 6. **Gateway auto-restart** — running gateways are refreshed after the update completes so the new code takes effect immediately. Service-managed gateways (systemd on Linux, launchd on macOS) are restarted through the service manager. Manual gateways are relaunched automatically when Hermes can map the running PID back to a profile. ### Updating against a non-default branch: `--branch` By default `hermes update` tracks `origin/main`. Pass `--branch ` to update against a different branch — useful for QA channels, feature branches, or release-candidate testing: ```bash hermes update --branch release-candidate hermes update --check --branch experimental # preview behindness only ``` If your local checkout is on a different branch, Hermes auto-stashes any uncommitted work, switches HEAD to the target branch, and then pulls. Branches that don't exist locally are auto-tracked from `origin/` (`git checkout -B origin/`). Branches that don't exist anywhere fail cleanly — your stashed changes are restored before exit so you're never stranded in a weird state. The `main`-only fork-upstream sync logic is automatically skipped on non-`main` branches. ### Local changes on non-interactive updates When you run `hermes update` in a terminal, Hermes stashes any uncommitted source-tree changes, pulls, then **asks** whether to restore them — exactly as it always has. Nothing changes for interactive updates. When the update runs **without a terminal** — from the desktop/chat app's "Update" button or a gateway-triggered update — there's no prompt to answer. The `updates.non_interactive_local_changes` setting decides what happens to your stashed changes: ```yaml # ~/.hermes/config.yaml updates: non_interactive_local_changes: stash # default: keep + auto-restore # non_interactive_local_changes: discard # throw local source edits away ``` - `stash` (default) — auto-stash, pull, then auto-restore your changes on top of the updated code. Nothing is lost; if a restore hits conflicts they're preserved in a git stash for manual recovery. - `discard` — auto-stash and drop the stash after the pull, so the update always lands on a clean tree. Use this only on machines where you never intend to keep local edits to the Hermes source. It stash-drops (not `git reset --hard` + `git clean -fd`), so ignored paths like `node_modules`, `venv`, and build outputs are never touched. In the desktop app this is **Settings → Advanced → In-App Update Local Changes**. ### Preview-only: `hermes update --check` Want to know if an update is available before pulling? Run `hermes update --check` — for git installs it fetches and compares commits against `origin/main`; for pip installs it queries PyPI for the latest release. No files are modified, no gateway is restarted. Useful in scripts and cron jobs that gate on "is there an update". ### Full pre-update backup: `--backup` For high-value profiles (production gateways, shared team installs) you can opt into a full pre-pull backup of `HERMES_HOME` (config, auth, sessions, skills, pairing): ```bash hermes update --backup ``` Or make it the default for every run: ```yaml # ~/.hermes/config.yaml updates: pre_update_backup: true ``` `--backup` was the always-on behavior in earlier builds, but it was adding minutes to every update on large homes, so it's now opt-in. The lightweight pairing-data snapshot above still runs unconditionally. ### Windows: another `hermes.exe` is running On Windows, `hermes update` will refuse to run if it detects another `hermes.exe` process holding the venv's entry-point executable open — most commonly the Hermes Desktop app's spawned backend, an open `hermes` REPL in another terminal, or a running gateway: ``` $ hermes update ✗ Another hermes.exe is running: PID 12345 hermes.exe Updating now would fail to overwrite ...\venv\Scripts\hermes.exe because Windows blocks REPLACE on a running executable. Close Hermes Desktop, exit any open `hermes` REPLs, and stop the gateway (`hermes gateway stop`) before retrying. Override with `hermes update --force` if you've already confirmed those processes will not write to the venv. ``` Close the listed processes and re-run. If you're sure the concurrent process won't interfere (rare — usually only useful when an antivirus shim is mis-attributed), pass `--force` to skip the check. In that case the updater will still retry the `.exe` rename with exponential backoff and, on stubborn locks, schedule the replacement for next reboot via `MoveFileEx(MOVEFILE_DELAY_UNTIL_REBOOT)` so the update can complete. Expected output looks like: ``` $ hermes update Updating Hermes Agent... 📥 Pulling latest code... Already up to date. (or: Updating abc1234..def5678) 📦 Updating dependencies... ✅ Dependencies updated 🔍 Checking for new config options... ✅ Config is up to date (or: Found 2 new options — running migration...) 🔄 Restarting gateways... ✅ Gateway restarted ✅ Hermes Agent updated successfully! ``` ### Recommended Post-Update Validation `hermes update` handles the main update path, but a quick validation confirms everything landed cleanly: 1. `git status --short` — if the tree is unexpectedly dirty, inspect before continuing 2. `hermes doctor` — checks config, dependencies, and service health 3. `hermes --version` — confirm the version bumped as expected 4. If you use the gateway: `hermes gateway status` 5. If `doctor` reports npm audit issues: run `npm audit fix` in the flagged directory > **WARNING — Dirty working tree after update** > > If `git status --short` shows unexpected changes after `hermes update`, stop and inspect them before continuing. This usually means local modifications were reapplied on top of the updated code, or a dependency step refreshed lockfiles. ### If your terminal disconnects mid-update `hermes update` protects itself against accidental terminal loss: - The update ignores `SIGHUP`, so closing your SSH session or terminal window no longer kills it mid-install. `pip` and `git` child processes inherit this protection, so the Python environment cannot be left half-installed by a dropped connection. - All output is mirrored to `~/.hermes/logs/update.log` while the update runs. If your terminal disappears, reconnect and inspect the log to see whether the update finished and whether the gateway restart succeeded: ```bash tail -f ~/.hermes/logs/update.log ``` - `Ctrl-C` (SIGINT) and system shutdown (SIGTERM) are still honored — those are deliberate cancellations, not accidents. You no longer need to wrap `hermes update` in `screen` or `tmux` to survive a terminal drop. ### Checking your current version ```bash hermes version ``` Compare against the latest release at the [GitHub releases page](https://github.com/NousResearch/hermes-agent/releases). ### Updating from Messaging Platforms You can also update directly from Telegram, Discord, Slack, WhatsApp, or Teams by sending: ``` /update ``` This pulls the latest code, updates dependencies, and restarts running gateways. The bot will briefly go offline during the restart (typically 5–15 seconds) and then resume. ### Manual Update If you installed manually (not via the quick installer): ```bash cd /path/to/hermes-agent export VIRTUAL_ENV="$(pwd)/venv" # Pull latest code git pull origin main # Reinstall (picks up new dependencies) uv pip install -e ".[all]" # Check for new config options hermes config check hermes config migrate # Interactively add any missing options ``` ### Rollback instructions If an update introduces a problem, you can roll back to a previous version: ```bash cd /path/to/hermes-agent # List recent versions git log --oneline -10 # Roll back to a specific commit git checkout uv pip install -e ".[all]" # Restart the gateway if running hermes gateway restart ``` To roll back to a specific release tag (substitute your previous tag — e.g. a recent release like `v2026.5.16`, or any earlier tag from `git tag --sort=-version:refname`): ```bash git checkout vX.Y.Z uv pip install -e ".[all]" ``` > **WARNING** > > Rolling back may cause config incompatibilities if new options were added. Run `hermes config check` after rolling back and remove any unrecognized options from `config.yaml` if you encounter errors. ### Note for Nix users If you installed via Nix flake, updates are managed through the Nix package manager: ```bash # Update the flake input nix flake update hermes-agent # Or rebuild with the latest nix profile upgrade hermes-agent ``` Nix installations are immutable — rollback is handled by Nix's generation system: ```bash nix profile rollback ``` See [Nix Setup](/docs/getting-started/nix-setup) for more details. --- ## Uninstalling ### Git installs ```bash hermes uninstall ``` The uninstaller gives you the option to keep your configuration files (`~/.hermes/`) for a future reinstall. ### pip installs ```bash pip uninstall hermes-agent rm -rf ~/.hermes # Optional — keep if you plan to reinstall ``` ### Manual Uninstall ```bash rm -f ~/.local/bin/hermes rm -rf /path/to/hermes-agent rm -rf ~/.hermes # Optional — keep if you plan to reinstall ``` > **INFO** > > If you installed the gateway as a system service, stop and disable it first: > ```bash > hermes gateway stop > # Linux: systemctl --user disable hermes-gateway > # macOS: launchctl remove ai.hermes.gateway > ``` --- --- ## Android / Termux Section: Getting Started · URL: https://hermesbible.com/docs/getting-started/termux # Hermes on Android with Termux This is the tested path for running Hermes Agent directly on an Android phone through [Termux](https://termux.dev/). It gives you a working local CLI on the phone, plus the core extras that are currently known to install cleanly on Android. ## What is supported in the tested path? The tested Termux bundle installs: - the Hermes CLI - cron support - PTY/background terminal support - Telegram gateway support (manual / best-effort background runs) - MCP support - Honcho memory support - ACP support Concretely, it maps to: ```bash python -m pip install -e '.[termux]' -c constraints-termux.txt ``` ## What is not part of the tested path yet? A few features still need desktop/server-style dependencies that are not published for Android, or have not been validated on phones yet: - `.[all]` is not supported on Android today - the `voice` extra is blocked by `faster-whisper -> ctranslate2`, and `ctranslate2` does not publish Android wheels - automatic browser / Playwright bootstrap is skipped in the Termux installer - Docker-based terminal isolation is not available inside Termux - Android may still suspend Termux background jobs, so gateway persistence is best-effort rather than a normal managed service That does not stop Hermes from working well as a phone-native CLI agent — it just means the recommended mobile install is intentionally narrower than the desktop/server install. --- ## Option 1: One-line installer Hermes now ships a Termux-aware installer path: ```bash curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash ``` On Termux, the installer automatically: - uses `pkg` for system packages - creates the venv with `python -m venv` - attempts the broad `.[termux-all]` extra first and falls back to the smaller `.[termux]` extra (then a base install) — the curl installer matches this order automatically - links `hermes` into `$PREFIX/bin` so it stays on your Termux PATH - skips the untested browser / WhatsApp bootstrap If you want the explicit commands or need to debug a failed install, use the manual path below. --- ## Option 2: Manual install (fully explicit) ### 1. Update Termux and install system packages ```bash pkg update pkg install -y git python clang rust make pkg-config libffi openssl nodejs ripgrep ffmpeg ``` Why these packages? - `python` — runtime + venv support - `git` — clone/update the repo - `clang`, `rust`, `make`, `pkg-config`, `libffi`, `openssl` — needed to build a few Python dependencies on Android - `nodejs` — optional Node runtime for experiments beyond the tested core path - `ripgrep` — fast file search - `ffmpeg` — media / TTS conversions ### 2. Clone Hermes ```bash git clone https://github.com/NousResearch/hermes-agent.git cd hermes-agent ``` ### 3. Create a virtual environment ```bash python -m venv venv source venv/bin/activate export ANDROID_API_LEVEL="$(getprop ro.build.version.sdk)" python -m pip install --upgrade pip setuptools wheel ``` `ANDROID_API_LEVEL` is important for Rust / maturin-based packages such as `jiter`. ### 4. Install the tested Termux bundle ```bash python -m pip install -e '.[termux]' -c constraints-termux.txt ``` If you only want the minimal core agent, this also works: ```bash python -m pip install -e '.' -c constraints-termux.txt ``` ### 5. Put `hermes` on your Termux PATH ```bash ln -sf "$PWD/venv/bin/hermes" "$PREFIX/bin/hermes" ``` `$PREFIX/bin` is already on PATH in Termux, so this makes the `hermes` command persist across new shells without re-activating the venv every time. ### 6. Verify the install ```bash hermes version hermes doctor ``` ### 7. Start Hermes ```bash hermes ``` --- ## Recommended follow-up setup ### Configure a model ```bash hermes model ``` Or set keys directly in `~/.hermes/.env`. ### Re-run the full interactive setup wizard later ```bash hermes setup ``` ### Install optional Node dependencies manually The tested Termux path skips Node/browser bootstrap on purpose. If you want to experiment with browser tooling later: ```bash pkg install nodejs-lts npm install ``` The browser tool automatically includes Termux directories (`/data/data/com.termux/files/usr/bin`) in its PATH search, so `agent-browser` and `npx` are discovered without any extra PATH configuration. Treat browser / WhatsApp tooling on Android as experimental until documented otherwise. --- ## Troubleshooting ### `No solution found` when installing `.[all]` Use the tested Termux bundle instead: ```bash python -m pip install -e '.[termux]' -c constraints-termux.txt ``` The blocker is currently the `voice` extra: - `voice` pulls `faster-whisper` - `faster-whisper` depends on `ctranslate2` - `ctranslate2` does not publish Android wheels ### `uv pip install` fails on Android Use the Termux path with the stdlib venv + `pip` instead: ```bash python -m venv venv source venv/bin/activate export ANDROID_API_LEVEL="$(getprop ro.build.version.sdk)" python -m pip install --upgrade pip setuptools wheel python -m pip install -e '.[termux]' -c constraints-termux.txt ``` ### `jiter` / `maturin` complains about `ANDROID_API_LEVEL` Set the API level explicitly before installing: ```bash export ANDROID_API_LEVEL="$(getprop ro.build.version.sdk)" python -m pip install -e '.[termux]' -c constraints-termux.txt ``` ### `hermes doctor` says ripgrep or Node is missing Install them with Termux packages: ```bash pkg install ripgrep nodejs ``` ### Build failures while installing Python packages Make sure the build toolchain is installed: ```bash pkg install clang rust make pkg-config libffi openssl ``` Then retry: ```bash python -m pip install -e '.[termux]' -c constraints-termux.txt ``` --- ## Known limitations on phones - Docker backend is unavailable - local voice transcription via `faster-whisper` is unavailable in the tested path - browser automation setup is intentionally skipped by the installer - some optional extras may work, but only `.[termux]` and `.[termux-all]` are currently documented as the tested Android bundles If you hit a new Android-specific issue, please open a GitHub issue with: - your Android version - `termux-info` - `python --version` - `hermes doctor` - the exact install command and full error output --- --- ## Nix & NixOS Setup Section: Getting Started · URL: https://hermesbible.com/docs/getting-started/nix-setup Hermes Agent ships a Nix flake with three levels of integration: | Level | Who it's for | What you get | |-------|-------------|--------------| | **`nix run` / `nix profile install`** | Any Nix user (macOS, Linux) | Pre-built binary with all deps — then use the standard CLI workflow | | **NixOS module (native)** | NixOS server deployments | Declarative config, hardened systemd service, managed secrets | | **NixOS module (container)** | Agents that need self-modification | Everything above, plus a persistent Ubuntu container where the agent can `apt`/`pip`/`npm install` | > **INFO — What's different from the standard install** > > The `curl | bash` installer manages Python, Node, and dependencies itself. The Nix flake replaces all of that — every Python dependency is a Nix derivation built by [uv2nix](https://github.com/pyproject-nix/uv2nix), and runtime tools (Node.js, git, ripgrep, ffmpeg) are wrapped into the binary's PATH. There is no runtime pip, no venv activation, no `npm install`. > > **For non-NixOS users**, this only changes the install step. Everything after (`hermes setup`, `hermes gateway install`, config editing) works identically to the standard install. > > **For NixOS module users**, the entire lifecycle is different: configuration lives in `configuration.nix`, secrets go through sops-nix/agenix, the service is a systemd unit, and CLI config commands are blocked. You manage hermes the same way you manage any other NixOS service. ## Prerequisites - **Nix with flakes enabled** — [Determinate Nix](https://install.determinate.systems) recommended (enables flakes by default) - **API keys** for the services you want to use (at minimum: an OpenRouter or Anthropic key) --- ## Quick Start (Any Nix User) No clone needed. Nix fetches, builds, and runs everything: ```bash # Run directly (builds on first use, cached after) nix run github:NousResearch/hermes-agent -- setup nix run github:NousResearch/hermes-agent -- chat # Or install persistently nix profile install github:NousResearch/hermes-agent hermes setup hermes chat ``` After `nix profile install`, `hermes`, `hermes-agent`, and `hermes-acp` are on your PATH. From here, the workflow is identical to the [standard installation](/docs/getting-started/installation) — `hermes setup` walks you through provider selection, `hermes gateway install` sets up a launchd (macOS) or systemd user service, and config lives in `~/.hermes/`. > **WARNING — Messaging platforms (Discord, Telegram, Slack)** > > The default package doesn't include messaging platform libraries — they were moved to on-demand installation, which can't work in Nix's read-only environment. If you plan to connect the agent to Discord, Telegram, or Slack, install the `messaging` variant: > > ```bash > nix profile install github:NousResearch/hermes-agent#messaging > ``` > > For all optional extras (voice, all providers, all platforms): > > ```bash > nix profile install github:NousResearch/hermes-agent#full > ``` > > The `full` variant adds ~700 MB to the closure. If you only need messaging platforms, `#messaging` adds just ~33 MB.
Building from a local clone ```bash git clone https://github.com/NousResearch/hermes-agent.git cd hermes-agent nix build ./result/bin/hermes setup ```
--- ## NixOS Module The flake exports `nixosModules.default` — a full NixOS service module that declaratively manages user creation, directories, config generation, secrets, documents, and service lifecycle. > **NOTE** > > This module requires NixOS. For non-NixOS systems (macOS, other Linux distros), use `nix profile install` and the standard CLI workflow above. ### Add the Flake Input ```nix # /etc/nixos/flake.nix (or your system flake) { inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; hermes-agent.url = "github:NousResearch/hermes-agent"; }; outputs = { nixpkgs, hermes-agent, ... }: { nixosConfigurations.your-host = nixpkgs.lib.nixosSystem { system = "x86_64-linux"; modules = [ hermes-agent.nixosModules.default ./configuration.nix ]; }; }; } ``` ### Minimal Configuration ```nix # configuration.nix { config, ... }: { services.hermes-agent = { enable = true; settings.model.default = "anthropic/claude-sonnet-4"; environmentFiles = [ config.sops.secrets."hermes-env".path ]; addToSystemPackages = true; }; } ``` That's it. `nixos-rebuild switch` creates the `hermes` user, generates `config.yaml`, wires up secrets, and starts the gateway — a long-running service that connects the agent to messaging platforms (Telegram, Discord, etc.) and listens for incoming messages. > **WARNING — Secrets are required** > > The `environmentFiles` line above assumes you have [sops-nix](https://github.com/Mic92/sops-nix) or [agenix](https://github.com/ryantm/agenix) configured. The file should contain at least one LLM provider key (e.g., `OPENROUTER_API_KEY=sk-or-...`). See [Secrets Management](#secrets-management) for full setup. If you don't have a secrets manager yet, you can use a plain file as a starting point — just ensure it's not world-readable: > > ```bash > echo "OPENROUTER_API_KEY=sk-or-your-key" | sudo install -m 0600 -o hermes /dev/stdin /var/lib/hermes/env > ``` > > ```nix > services.hermes-agent.environmentFiles = [ "/var/lib/hermes/env" ]; > ``` > **TIP — addToSystemPackages** > > Setting `addToSystemPackages = true` does two things: puts the `hermes` CLI on your system PATH **and** sets `HERMES_HOME` system-wide so the interactive CLI shares state (sessions, skills, cron) with the gateway service. Without it, running `hermes` in your shell creates a separate `~/.hermes/` directory. ### Container-aware CLI > **INFO** > > When `container.enable = true` and `addToSystemPackages = true`, **every** `hermes` command on the host automatically routes into the managed container. This means your interactive CLI session runs inside the same environment as the gateway service — with access to all container-installed packages and tools. > > - The routing is transparent: `hermes chat`, `hermes sessions list`, `hermes version`, etc. all exec into the container under the hood > - All CLI flags are forwarded as-is > - If the container isn't running, the CLI retries briefly (5s with a spinner for interactive use, 10s silently for scripts) then fails with a clear error — no silent fallback > - For developers working on the hermes codebase, set `HERMES_DEV=1` to bypass container routing and run the local checkout directly > > Set `container.hostUsers` to create a `~/.hermes` symlink to the service state directory, so the host CLI and the container share sessions, config, and memories: > > ```nix > services.hermes-agent = { > container.enable = true; > container.hostUsers = [ "your-username" ]; > addToSystemPackages = true; > }; > ``` > > Users listed in `hostUsers` are automatically added to the `hermes` group for file permission access. > > **Podman users:** The NixOS service runs the container as root. Docker users get access via the `docker` group socket, but Podman's rootful containers require sudo. Grant passwordless sudo for your container runtime: > > ```nix > security.sudo.extraRules = [{ > users = [ "your-username" ]; > commands = [{ > command = "/run/current-system/sw/bin/podman"; > options = [ "NOPASSWD" ]; > }]; > }]; > ``` > > The CLI auto-detects when sudo is needed and uses it transparently. Without this, you'll need to run `sudo hermes chat` manually. ### Verify It Works After `nixos-rebuild switch`, check that the service is running: ```bash # Check service status systemctl status hermes-agent # Watch logs (Ctrl+C to stop) journalctl -u hermes-agent -f # If addToSystemPackages is true, test the CLI hermes version hermes config # shows the generated config ``` ### Choosing a Deployment Mode The module supports two modes, controlled by `container.enable`: | | **Native** (default) | **Container** | |---|---|---| | How it runs | Hardened systemd service on the host | Persistent Ubuntu container with `/nix/store` bind-mounted | | Security | `NoNewPrivileges`, `ProtectSystem=strict`, `PrivateTmp` | Container isolation, runs as unprivileged user inside | | Agent can self-install packages | No — only tools on the Nix-provided PATH | Yes — `apt`, `pip`, `npm` installs persist across restarts | | Config surface | Same | Same | | When to choose | Standard deployments, maximum security, reproducibility | Agent needs runtime package installation, mutable environment, experimental tools | To enable container mode, add one line: ```nix { services.hermes-agent = { enable = true; container.enable = true; # ... rest of config is identical }; } ``` > **INFO** > > Container mode auto-enables `virtualisation.docker.enable` via `mkDefault`. If you use Podman instead, set `container.backend = "podman"` and `virtualisation.docker.enable = false`. --- ## 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: ```nix # 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](https://openrouter.ai) (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 ```nix { 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`: ```nix 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.` | See [MCP Servers](#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"` | --- ## Secrets Management > **DANGER — Never put API keys in `settings` or `environment`** > > Values in Nix expressions end up in `/nix/store`, which is world-readable. Always use `environmentFiles` with a secrets manager. Both `environment` (non-secret vars) and `environmentFiles` (secret files) are merged into `$HERMES_HOME/.env` at activation time (`nixos-rebuild switch`). Hermes reads this file on every startup, so changes take effect with a `systemctl restart hermes-agent` — no container recreation needed. ### sops-nix ```nix { sops = { defaultSopsFile = ./secrets/hermes.yaml; age.keyFile = "/home/user/.config/sops/age/keys.txt"; secrets."hermes-env" = { format = "yaml"; }; }; services.hermes-agent.environmentFiles = [ config.sops.secrets."hermes-env".path ]; } ``` The secrets file contains key-value pairs: ```yaml # secrets/hermes.yaml (encrypted with sops) hermes-env: | OPENROUTER_API_KEY=sk-or-... TELEGRAM_BOT_TOKEN=123456:ABC... ANTHROPIC_API_KEY=sk-ant-... ``` ### agenix ```nix { age.secrets.hermes-env.file = ./secrets/hermes-env.age; services.hermes-agent.environmentFiles = [ config.age.secrets.hermes-env.path ]; } ``` ### OAuth / Auth Seeding For platforms requiring OAuth (e.g., Discord), use `authFile` to seed credentials on first deploy: ```nix { services.hermes-agent = { authFile = config.sops.secrets."hermes/auth.json".path; # authFileForceOverwrite = true; # overwrite on every activation }; } ``` The file is only copied if `auth.json` doesn't already exist (unless `authFileForceOverwrite = true`). Runtime OAuth token refreshes are written to the state directory and preserved across rebuilds. --- ## Documents The `documents` option installs files into the agent's working directory (the `workingDirectory`, which the agent reads as its workspace). Hermes looks for specific filenames by convention: - **`USER.md`** — context about the user the agent is interacting with. - Any other files you place here are visible to the agent as workspace files. The agent identity file is separate: Hermes loads its primary `SOUL.md` from `$HERMES_HOME/SOUL.md`, which in the NixOS module is `${services.hermes-agent.stateDir}/.hermes/SOUL.md`. Putting `SOUL.md` in `documents` only creates a workspace file and will not replace the main persona file. ```nix { services.hermes-agent.documents = { "USER.md" = ./documents/USER.md; # path reference, copied from Nix store }; } ``` Values can be inline strings or path references. Files are installed on every `nixos-rebuild switch`. --- ## MCP Servers The `mcpServers` option declaratively configures [MCP (Model Context Protocol)](https://modelcontextprotocol.io) servers. Each server uses either **stdio** (local command) or **HTTP** (remote URL) transport. ### Stdio Transport (Local Servers) ```nix { services.hermes-agent.mcpServers = { filesystem = { command = "npx"; args = [ "-y" "@modelcontextprotocol/server-filesystem" "/data/workspace" ]; }; github = { command = "npx"; args = [ "-y" "@modelcontextprotocol/server-github" ]; env.GITHUB_PERSONAL_ACCESS_TOKEN = "\${GITHUB_TOKEN}"; # resolved from .env }; }; } ``` > **TIP** > > Environment variables in `env` values are resolved from `$HERMES_HOME/.env` at runtime. Use `environmentFiles` to inject secrets — never put tokens directly in Nix config. ### HTTP Transport (Remote Servers) ```nix { services.hermes-agent.mcpServers.remote-api = { url = "https://mcp.example.com/v1/mcp"; headers.Authorization = "Bearer \${MCP_REMOTE_API_KEY}"; timeout = 180; }; } ``` ### HTTP Transport with OAuth Set `auth = "oauth"` for servers using OAuth 2.1. Hermes implements the full PKCE flow — metadata discovery, dynamic client registration, token exchange, and automatic refresh. ```nix { services.hermes-agent.mcpServers.my-oauth-server = { url = "https://mcp.example.com/mcp"; auth = "oauth"; }; } ``` Tokens are stored in `$HERMES_HOME/mcp-tokens/.json` and persist across restarts and rebuilds.
Initial OAuth authorization on headless servers The first OAuth authorization requires a browser-based consent flow. In a headless deployment, Hermes prints the authorization URL to stdout/logs instead of opening a browser. **Option A: Interactive bootstrap** — run the flow once via `docker exec` (container) or `sudo -u hermes` (native): ```bash # Container mode docker exec -it hermes-agent \ hermes mcp add my-oauth-server --url https://mcp.example.com/mcp --auth oauth # Native mode sudo -u hermes HERMES_HOME=/var/lib/hermes/.hermes \ hermes mcp add my-oauth-server --url https://mcp.example.com/mcp --auth oauth ``` The container uses `--network=host`, so the OAuth callback listener on `127.0.0.1` is reachable from the host browser. **Option B: Pre-seed tokens** — complete the flow on a workstation, then copy tokens: ```bash hermes mcp add my-oauth-server --url https://mcp.example.com/mcp --auth oauth scp ~/.hermes/mcp-tokens/my-oauth-server{,.client}.json \ server:/var/lib/hermes/.hermes/mcp-tokens/ # Ensure: chown hermes:hermes, chmod 0600 ```
### Sampling (Server-Initiated LLM Requests) Some MCP servers can request LLM completions from the agent: ```nix { services.hermes-agent.mcpServers.analysis = { command = "npx"; args = [ "-y" "analysis-server" ]; sampling = { enabled = true; model = "google/gemini-3-flash"; max_tokens_cap = 4096; timeout = 30; max_rpm = 10; }; }; } ``` --- ## Managed Mode When hermes runs via the NixOS module, the following CLI commands are **blocked** with a descriptive error pointing you to `configuration.nix`: | Blocked command | Why | |---|---| | `hermes setup` | Config is declarative — edit `settings` in your Nix config | | `hermes config edit` | Config is generated from `settings` | | `hermes config set ` | Config is generated from `settings` | | `hermes gateway install` | The systemd service is managed by NixOS | | `hermes gateway uninstall` | The systemd service is managed by NixOS | This prevents drift between what Nix declares and what's on disk. Detection uses two signals: 1. **`HERMES_MANAGED=true`** environment variable — set by the systemd service, visible to the gateway process 2. **`.managed` marker file** in `HERMES_HOME` — set by the activation script, visible to interactive shells (e.g., `docker exec -it hermes-agent hermes config set ...` is also blocked) To change configuration, edit your Nix config and run `sudo nixos-rebuild switch`. --- ## Container Architecture > **INFO** > > This section is only relevant if you're using `container.enable = true`. Skip it for native mode deployments. When container mode is enabled, hermes runs inside a persistent Ubuntu container with the Nix-built binary bind-mounted read-only from the host: ``` Host Container ──── ───────── /nix/store/...-hermes-agent-0.1.0 ──► /nix/store/... (ro) ~/.hermes -> /var/lib/hermes/.hermes (symlink bridge, per hostUsers) /var/lib/hermes/ ──► /data/ (rw) ├── current-package -> /nix/store/... (symlink, updated each rebuild) ├── .gc-root -> /nix/store/... (prevents nix-collect-garbage) ├── .container-identity (sha256 hash, triggers recreation) ├── .hermes/ (HERMES_HOME) │ ├── .env (merged from environment + environmentFiles) │ ├── config.yaml (Nix-generated, deep-merged by activation) │ ├── .managed (marker file) │ ├── .container-mode (routing metadata: backend, exec_user, etc.) │ ├── state.db, sessions/, memories/ (runtime state) │ └── mcp-tokens/ (OAuth tokens for MCP servers) ├── home/ ──► /home/hermes (rw) └── workspace/ (agent working directory) ├── SOUL.md (from documents option) └── (agent-created files) Container writable layer (apt/pip/npm): /usr, /usr/local, /tmp ``` The Nix-built binary works inside the Ubuntu container because `/nix/store` is bind-mounted — it brings its own interpreter and all dependencies, so there's no reliance on the container's system libraries. The container entrypoint resolves through a `current-package` symlink: `/data/current-package/bin/hermes gateway run --replace`. On `nixos-rebuild switch`, only the symlink is updated — the container keeps running. ### What Persists Across What | Event | Container recreated? | `/data` (state) | `/home/hermes` | Writable layer (`apt`/`pip`/`npm`) | |---|---|---|---|---| | `systemctl restart hermes-agent` | No | Persists | Persists | Persists | | `nixos-rebuild switch` (code change) | No (symlink updated) | Persists | Persists | Persists | | Host reboot | No | Persists | Persists | Persists | | `nix-collect-garbage` | No (GC root) | Persists | Persists | Persists | | Image change (`container.image`) | **Yes** | Persists | Persists | **Lost** | | Volume/options change | **Yes** | Persists | Persists | **Lost** | | `environment`/`environmentFiles` change | No | Persists | Persists | Persists | The container is only recreated when its **identity hash** changes. The hash covers: schema version, image, `extraVolumes`, `extraOptions`, and the entrypoint script. Changes to environment variables, settings, documents, or the hermes package itself do **not** trigger recreation. > **WARNING — Writable layer loss** > > When the identity hash changes (image upgrade, new volumes, new container options), the container is destroyed and recreated from a fresh pull of `container.image`. Any `apt install`, `pip install`, or `npm install` packages in the writable layer are lost. State in `/data` and `/home/hermes` is preserved (these are bind mounts). > > If the agent relies on specific packages, consider baking them into a custom image (`container.image = "my-registry/hermes-base:latest"`) or scripting their installation in the agent's SOUL.md. ### GC Root Protection The `preStart` script creates a GC root at `${stateDir}/.gc-root` pointing to the current hermes package. This prevents `nix-collect-garbage` from removing the running binary. If the GC root somehow breaks, restarting the service recreates it. --- ## Plugins The NixOS module supports declarative plugin installation — no imperative `hermes plugins install` needed. ### Directory Plugins (`extraPlugins`) For plugins that are just a source tree with `plugin.yaml` + `__init__.py` (e.g., [hermes-lcm](https://github.com/stephenschoettler/hermes-lcm)): ```nix services.hermes-agent.extraPlugins = [ (pkgs.fetchFromGitHub { owner = "stephenschoettler"; repo = "hermes-lcm"; rev = "v0.7.0"; hash = "sha256-..."; }) ]; ``` Plugins are symlinked into `$HERMES_HOME/plugins/` at activation time. Hermes discovers them via its normal directory scan. Removing a plugin from the list and running `nixos-rebuild switch` removes the symlink. ### Entry-Point Plugins (`extraPythonPackages`) For pip-packaged plugins that register via `[project.entry-points."hermes_agent.plugins"]` (e.g., [rtk-hermes](https://github.com/ogallotti/rtk-hermes)): ```nix services.hermes-agent.extraPythonPackages = [ (pkgs.python312Packages.buildPythonPackage { pname = "rtk-hermes"; version = "1.0.0"; src = pkgs.fetchFromGitHub { owner = "ogallotti"; repo = "rtk-hermes"; rev = "v1.0.0"; hash = "sha256-..."; }; format = "pyproject"; build-system = [ pkgs.python312Packages.setuptools ]; }) ]; ``` The package's `site-packages` is added to PYTHONPATH in the hermes wrapper. `importlib.metadata` discovers the entry point at session start. ### Optional Dependency Groups (`extraDependencyGroups`) For optional extras declared in hermes-agent's `pyproject.toml`, use `extraDependencyGroups` to include them in the sealed venv at build time. This is required for any extra not in the default `[all]` set — on Nix, runtime installation into the read-only store is not possible. ```nix # Enable Discord, Telegram, Slack services.hermes-agent.extraDependencyGroups = [ "messaging" ]; ``` ```nix # Enable a memory provider services.hermes-agent = { extraDependencyGroups = [ "hindsight" ]; settings.memory.provider = "hindsight"; }; ``` This is resolved by uv alongside core dependencies — no PYTHONPATH patching, no collision risk. Available groups: | Group | What it enables | |-------|-----------------| | `messaging` | Discord, Telegram, Slack | | `matrix` | Matrix/Element (mautrix with encryption; Linux only) | | `dingtalk` | DingTalk | | `feishu` | Feishu/Lark | | `voice` | Local speech-to-text (faster-whisper) | | `edge-tts` | Edge TTS provider | | `tts-premium` | ElevenLabs TTS | | `anthropic` | Native Anthropic SDK (not needed via OpenRouter) | | `bedrock` | AWS Bedrock (boto3) | | `azure-identity` | Azure Entra ID auth | | `honcho` | Honcho memory provider | | `hindsight` | Hindsight memory provider | | `modal` | Modal terminal backend | | `daytona` | Daytona terminal backend | | `exa` | Exa web search | | `firecrawl` | Firecrawl web search | | `fal` | FAL image generation | Or use the pre-built `#messaging` or `#full` flake packages instead of per-extra configuration (see [Quick Start](#quick-start-any-nix-user)). **When to use which:** | Need | Option | |------|--------| | Enable a pyproject.toml optional extra | `extraDependencyGroups` | | Add an external Python plugin not in pyproject.toml | `extraPythonPackages` | | Add a system binary (pandoc, jq, etc.) | `extraPackages` | | Add a directory-based plugin source tree | `extraPlugins` | ### Combining Both A directory plugin with third-party Python dependencies needs both options: ```nix services.hermes-agent = { extraPlugins = [ my-plugin-src ]; # plugin source extraPythonPackages = [ pkgs.python312Packages.redis ]; # its Python dep extraPackages = [ pkgs.redis ]; # system binary it needs }; ``` ### Using the Overlay External flakes can override the package directly: ```nix { inputs.hermes-agent.url = "github:NousResearch/hermes-agent"; outputs = { hermes-agent, nixpkgs, ... }: { nixpkgs.overlays = [ hermes-agent.overlays.default ]; # Then: # pkgs.hermes-agent.override { extraPythonPackages = [...]; } # pkgs.hermes-agent.override { extraDependencyGroups = [ "hindsight" ]; } }; } ``` ### Plugin Configuration Plugins still need to be enabled in `config.yaml`. Add them via the declarative settings: ```nix services.hermes-agent.settings.plugins.enabled = [ "hermes-lcm" "rtk-rewrite" ]; ``` > **NOTE** > > A build-time collision check prevents plugin packages from shadowing core hermes dependencies. If a plugin provides a package already in the sealed venv, `nixos-rebuild` fails with a clear error. --- ## Development ### Dev Shell The flake provides a development shell with Python 3.12, uv, Node.js, and all runtime tools: ```bash cd hermes-agent nix develop # Shell provides: # - Python 3.12 + uv (deps installed into .venv on first entry) # - Node.js 22, ripgrep, git, openssh, ffmpeg on PATH # - Stamp-file optimization: re-entry is near-instant if deps haven't changed hermes setup hermes chat ``` ### direnv (Recommended) The included `.envrc` activates the dev shell automatically: ```bash cd hermes-agent direnv allow # one-time # Subsequent entries are near-instant (stamp file skips dep install) ``` ### Flake Checks The flake includes build-time verification that runs in CI and locally: ```bash # Run all checks nix flake check # Individual checks nix build .#checks.x86_64-linux.package-contents # binaries exist + version nix build .#checks.x86_64-linux.entry-points-sync # pyproject.toml ↔ Nix package sync nix build .#checks.x86_64-linux.cli-commands # gateway/config subcommands nix build .#checks.x86_64-linux.managed-guard # HERMES_MANAGED blocks mutation nix build .#checks.x86_64-linux.bundled-skills # skills present in package nix build .#checks.x86_64-linux.config-roundtrip # merge script preserves user keys ```
What each check verifies | Check | What it tests | |---|---| | `package-contents` | `hermes` and `hermes-agent` binaries exist and `hermes version` runs | | `entry-points-sync` | Every `[project.scripts]` entry in `pyproject.toml` has a wrapped binary in the Nix package | | `cli-commands` | `hermes --help` exposes `gateway` and `config` subcommands | | `managed-guard` | `HERMES_MANAGED=true hermes config set ...` prints the NixOS error | | `bundled-skills` | Skills directory exists, contains SKILL.md files, `HERMES_BUNDLED_SKILLS` is set in wrapper | | `config-roundtrip` | 7 merge scenarios: fresh install, Nix override, user key preservation, mixed merge, MCP additive merge, nested deep merge, idempotency |
--- ## Options Reference ### Core | Option | Type | Default | Description | |---|---|---|---| | `enable` | `bool` | `false` | Enable the hermes-agent service | | `package` | `package` | `hermes-agent` | The hermes-agent package to use | | `user` | `str` | `"hermes"` | System user | | `group` | `str` | `"hermes"` | System group | | `createUser` | `bool` | `true` | Auto-create user/group | | `stateDir` | `str` | `"/var/lib/hermes"` | State directory (`HERMES_HOME` parent) | | `workingDirectory` | `str` | `"${stateDir}/workspace"` | Agent working directory | | `addToSystemPackages` | `bool` | `false` | Add `hermes` CLI to system PATH and set `HERMES_HOME` system-wide | ### Configuration | Option | Type | Default | Description | |---|---|---|---| | `settings` | `attrs` (deep-merged) | `{}` | Declarative config rendered as `config.yaml`. Supports arbitrary nesting; multiple definitions are merged via `lib.recursiveUpdate` | | `configFile` | `null` or `path` | `null` | Path to an existing `config.yaml`. Overrides `settings` entirely if set | ### Secrets & Environment | Option | Type | Default | Description | |---|---|---|---| | `environmentFiles` | `listOf str` | `[]` | Paths to env files with secrets. Merged into `$HERMES_HOME/.env` at activation time | | `environment` | `attrsOf str` | `{}` | Non-secret env vars. **Visible in Nix store** — do not put secrets here | | `authFile` | `null` or `path` | `null` | OAuth credentials seed. Only copied on first deploy | | `authFileForceOverwrite` | `bool` | `false` | Always overwrite `auth.json` from `authFile` on activation | ### Documents | Option | Type | Default | Description | |---|---|---|---| | `documents` | `attrsOf (either str path)` | `{}` | Workspace files. Keys are filenames, values are inline strings or paths. Installed into `workingDirectory` on activation | ### MCP Servers | Option | Type | Default | Description | |---|---|---|---| | `mcpServers` | `attrsOf submodule` | `{}` | MCP server definitions, merged into `settings.mcp_servers` | | `mcpServers..command` | `null` or `str` | `null` | Server command (stdio transport) | | `mcpServers..args` | `listOf str` | `[]` | Command arguments | | `mcpServers..env` | `attrsOf str` | `{}` | Environment variables for the server process | | `mcpServers..url` | `null` or `str` | `null` | Server endpoint URL (HTTP/StreamableHTTP transport) | | `mcpServers..headers` | `attrsOf str` | `{}` | HTTP headers, e.g. `Authorization` | | `mcpServers..auth` | `null` or `"oauth"` | `null` | Authentication method. `"oauth"` enables OAuth 2.1 PKCE | | `mcpServers..enabled` | `bool` | `true` | Enable or disable this server | | `mcpServers..timeout` | `null` or `int` | `null` | Tool call timeout in seconds (default: 120) | | `mcpServers..connect_timeout` | `null` or `int` | `null` | Connection timeout in seconds (default: 60) | | `mcpServers..tools` | `null` or `submodule` | `null` | Tool filtering (`include`/`exclude` lists) | | `mcpServers..sampling` | `null` or `submodule` | `null` | Sampling config for server-initiated LLM requests | ### Service Behavior | Option | Type | Default | Description | |---|---|---|---| | `extraArgs` | `listOf str` | `[]` | Extra args for `hermes gateway` | | `extraPackages` | `listOf package` | `[]` | Extra packages available to the agent. Added to the hermes user's per-user profile so terminal commands, skills, and cron jobs all see them | | `extraPlugins` | `listOf package` | `[]` | Directory plugin packages to symlink into `$HERMES_HOME/plugins/`. Each must contain `plugin.yaml` | | `extraPythonPackages` | `listOf package` | `[]` | Python packages added to PYTHONPATH for entry-point plugin discovery. Build with `python312Packages` | | `extraDependencyGroups` | `listOf str` | `[]` | pyproject.toml optional extras to include in the sealed venv (e.g. `["hindsight"]`). Resolved by uv — no collisions | | `restart` | `str` | `"always"` | systemd `Restart=` policy | | `restartSec` | `int` | `5` | systemd `RestartSec=` value | ### Container | Option | Type | Default | Description | |---|---|---|---| | `container.enable` | `bool` | `false` | Enable OCI container mode | | `container.backend` | `enum ["docker" "podman"]` | `"docker"` | Container runtime | | `container.image` | `str` | `"ubuntu:24.04"` | Base image (pulled at runtime) | | `container.extraVolumes` | `listOf str` | `[]` | Extra volume mounts (`host:container:mode`) | | `container.extraOptions` | `listOf str` | `[]` | Extra args passed to `docker create` | | `container.hostUsers` | `listOf str` | `[]` | Interactive users who get a `~/.hermes` symlink to the service stateDir and are auto-added to the `hermes` group | --- ## Directory Layout ### Native Mode ``` /var/lib/hermes/ # stateDir (owned by hermes:hermes, 0750) ├── .hermes/ # HERMES_HOME │ ├── config.yaml # Nix-generated (deep-merged each rebuild) │ ├── .managed # Marker: CLI config mutation blocked │ ├── .env # Merged from environment + environmentFiles │ ├── auth.json # OAuth credentials (seeded, then self-managed) │ ├── gateway.pid │ ├── state.db │ ├── mcp-tokens/ # OAuth tokens for MCP servers │ ├── sessions/ │ ├── memories/ │ ├── skills/ │ ├── cron/ │ └── logs/ ├── home/ # Agent HOME └── workspace/ # Agent working directory ├── SOUL.md # From documents option └── (agent-created files) ``` ### Container Mode Same layout, mounted into the container: | Container path | Host path | Mode | Notes | |---|---|---|---| | `/nix/store` | `/nix/store` | `ro` | Hermes binary + all Nix deps | | `/data` | `/var/lib/hermes` | `rw` | All state, config, workspace | | `/home/hermes` | `${stateDir}/home` | `rw` | Persistent agent home — `pip install --user`, tool caches | | `/usr`, `/usr/local`, `/tmp` | (writable layer) | `rw` | `apt`/`pip`/`npm` installs — persists across restarts, lost on recreation | --- ## Updating ```bash # Update the flake input (run from the directory containing flake.nix) cd /etc/nixos && nix flake update hermes-agent # Rebuild sudo nixos-rebuild switch ``` In container mode, the `current-package` symlink is updated and the agent picks up the new binary on restart. No container recreation, no loss of installed packages. --- ## Troubleshooting > **TIP — Podman users** > > All `docker` commands below work the same with `podman`. Substitute accordingly if you set `container.backend = "podman"`. ### Service Logs ```bash # Both modes use the same systemd unit journalctl -u hermes-agent -f # Container mode: also available directly docker logs -f hermes-agent ``` ### Container Inspection ```bash systemctl status hermes-agent docker ps -a --filter name=hermes-agent docker inspect hermes-agent --format='{{.State.Status}}' docker exec -it hermes-agent bash docker exec hermes-agent readlink /data/current-package docker exec hermes-agent cat /data/.container-identity ``` ### Force Container Recreation If you need to reset the writable layer (fresh Ubuntu): ```bash sudo systemctl stop hermes-agent docker rm -f hermes-agent sudo rm /var/lib/hermes/.container-identity sudo systemctl start hermes-agent ``` ### Verify Secrets Are Loaded If the agent starts but can't authenticate with the LLM provider, check that the `.env` file was merged correctly: ```bash # Native mode sudo -u hermes cat /var/lib/hermes/.hermes/.env # Container mode docker exec hermes-agent cat /data/.hermes/.env ``` ### GC Root Verification ```bash nix-store --query --roots $(docker exec hermes-agent readlink /data/current-package) ``` ### Common Issues | Symptom | Cause | Fix | |---|---|---| | `Cannot save configuration: managed by NixOS` | CLI guards active | Edit `configuration.nix` and `nixos-rebuild switch` | | `No adapter available for discord` (or telegram/slack) | Messaging deps missing from the sealed Nix venv | Install `#messaging` variant: `nix profile install ...#messaging`. For NixOS module: `extraDependencyGroups = [ "messaging" ]`. Check `journalctl -u hermes-agent` for `FeatureUnavailable` or `requirements not met` for the underlying error. | | Container recreated unexpectedly | `extraVolumes`, `extraOptions`, or `image` changed | Expected — writable layer resets. Reinstall packages or use a custom image | | `hermes version` shows old version | Container not restarted | `systemctl restart hermes-agent` | | Permission denied on `/var/lib/hermes` | State dir is `0750 hermes:hermes` | Use `docker exec` or `sudo -u hermes` | | `nix-collect-garbage` removed hermes | GC root missing | Restart the service (preStart recreates the GC root) | | `no container with name or ID "hermes-agent"` (Podman) | Podman rootful container not visible to regular user | Add passwordless sudo for podman (see [Container Mode](#container-mode) section) | | `unable to find user hermes` | Container still starting (entrypoint hasn't created user yet) | Wait a few seconds and retry — the CLI retries automatically | | Tool added via `extraPackages` not found in terminal | Requires `nixos-rebuild switch` to update the per-user profile | Rebuild and restart: `nixos-rebuild switch && systemctl restart hermes-agent` | --- --- ## Features Overview Section: Core Features · URL: https://hermesbible.com/docs/user-guide/features/overview Hermes Agent includes a rich set of capabilities that extend far beyond basic chat. From persistent memory and file-aware context to browser automation and voice conversations, these features work together to make Hermes a powerful autonomous assistant. > **TIP — Don't know where to start?** > > `hermes setup --portal` covers a model provider plus all four Tool Gateway tools (web search, image generation, TTS, browser) in one command. See [Nous Portal](/integrations/nous-portal). ## Core - **[Tools & Toolsets](tools.md)** — Tools are functions that extend the agent's capabilities. They're organized into logical toolsets that can be enabled or disabled per platform, covering web search, terminal execution, file editing, memory, delegation, and more. - **[Skills System](skills.md)** — On-demand knowledge documents the agent can load when needed. Skills follow a progressive disclosure pattern to minimize token usage and are compatible with the [agentskills.io](https://agentskills.io/specification) open standard. - **[Persistent Memory](memory.md)** — Bounded, curated memory that persists across sessions. Hermes remembers your preferences, projects, environment, and things it has learned via `MEMORY.md` and `USER.md`. - **[Context Files](context-files.md)** — Hermes automatically discovers and loads project context files (`.hermes.md`, `AGENTS.md`, `CLAUDE.md`, `SOUL.md`, `.cursorrules`) that shape how it behaves in your project. - **[Context References](context-references.md)** — Type `@` followed by a reference to inject files, folders, git diffs, and URLs directly into your messages. Hermes expands the reference inline and appends the content automatically. - **[Checkpoints](/docs/user-guide/checkpoints-and-rollback)** — Hermes automatically snapshots your working directory before making file changes, giving you a safety net to roll back with `/rollback` if something goes wrong. ## Automation - **[Scheduled Tasks (Cron)](cron.md)** — Schedule tasks to run automatically with natural language or cron expressions. Jobs can attach skills, deliver results to any platform, and support pause/resume/edit operations. - **[Subagent Delegation](delegation.md)** — The `delegate_task` tool spawns child agent instances with isolated context, restricted toolsets, and their own terminal sessions. Run 3 concurrent subagents by default (configurable) for parallel workstreams. - **[Code Execution](code-execution.md)** — The `execute_code` tool lets the agent write Python scripts that call Hermes tools programmatically, collapsing multi-step workflows into a single LLM turn via sandboxed RPC execution. - **[Event Hooks](hooks.md)** — Run custom code at key lifecycle points. Gateway hooks handle logging, alerts, and webhooks; plugin hooks handle tool interception, metrics, and guardrails. - **[Batch Processing](batch-processing.md)** — Run the Hermes agent across hundreds or thousands of prompts in parallel, generating structured ShareGPT-format trajectory data for training data generation or evaluation. ## Media & Web - **[Voice Mode](voice-mode.md)** — Full voice interaction across CLI and messaging platforms. Talk to the agent using your microphone, hear spoken replies, and have live voice conversations in Discord voice channels. - **[Browser Automation](browser.md)** — Full browser automation with multiple backends: Browserbase cloud, Browser Use cloud, local Chrome/Brave/Chromium/Edge via CDP, or local Chromium. Navigate websites, fill forms, and extract information. - **[Vision & Image Paste](vision.md)** — Multimodal vision support. Paste images from your clipboard into the CLI and ask the agent to analyze, describe, or work with them using any vision-capable model. - **[Image Generation](image-generation.md)** — Generate images from text prompts using FAL.ai. Nine models supported (FLUX 2 Klein/Pro, GPT-Image 1.5/2, Nano Banana Pro, Ideogram V3, Recraft V4 Pro, Qwen, Z-Image Turbo); pick one via `hermes tools`. - **[Voice & TTS](tts.md)** — Text-to-speech output and voice message transcription across all messaging platforms, with ten native provider options: Edge TTS (free), ElevenLabs, OpenAI TTS, MiniMax, Mistral Voxtral, Google Gemini, xAI, NeuTTS, KittenTTS, and Piper — plus custom command providers for any local TTS CLI. ## Integrations - **[MCP Integration](mcp.md)** — Connect to any MCP server via stdio or HTTP transport. Access external tools from GitHub, databases, file systems, and internal APIs without writing native Hermes tools. Includes per-server tool filtering and sampling support. - **[Provider Routing](provider-routing.md)** — Fine-grained control over which AI providers handle your requests. Optimize for cost, speed, or quality with sorting, whitelists, blacklists, and priority ordering. - **[Fallback Providers](fallback-providers.md)** — Automatic failover to backup LLM providers when your primary model encounters errors, including independent fallback for auxiliary tasks like vision and compression. - **[Credential Pools](credential-pools.md)** — Distribute API calls across multiple keys for the same provider. Automatic rotation on rate limits or failures. - **[Prompt caching](../configuration#prompt-caching)** — Built-in cross-session 1-hour prefix cache for Claude on native Anthropic, OpenRouter, and Nous Portal. Always-on; no configuration required. - **[Memory Providers](memory-providers.md)** — Plug in external memory backends (Honcho, OpenViking, Mem0, Hindsight, Holographic, RetainDB, ByteRover, Supermemory) for cross-session user modeling and personalization beyond the built-in memory system. - **[API Server](api-server.md)** — Expose Hermes as an OpenAI-compatible HTTP endpoint. Connect any frontend that speaks the OpenAI format — Open WebUI, LobeChat, LibreChat, and more. - **[IDE Integration (ACP)](acp.md)** — Use Hermes inside ACP-compatible editors such as VS Code, Zed, and JetBrains. Chat, tool activity, file diffs, and terminal commands render inside your editor. - **[Batch Processing](batch-processing.md)** — Run the agent over many prompts or tasks in parallel from the CLI, with structured outputs and trajectory capture suitable for evals or downstream training pipelines. ## Customization - **[Personality & SOUL.md](personality.md)** — Fully customizable agent personality. `SOUL.md` is the primary identity file — the first thing in the system prompt — and you can swap in built-in or custom `/personality` presets per session. - **[Skins & Themes](skins.md)** — Customize the CLI's visual presentation: banner colors, spinner faces and verbs, response-box labels, branding text, and the tool activity prefix. - **[Plugins](plugins.md)** — Add custom tools, hooks, and integrations without modifying core code. Three plugin types: general plugins (tools/hooks), memory providers (cross-session knowledge), and context engines (alternative context management). Managed via the unified `hermes plugins` interactive UI. --- --- ## Tools & Toolsets Section: Core Features · URL: https://hermesbible.com/docs/user-guide/features/tools 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, RL training, messaging delivery, 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](/docs/user-guide/features/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 & delivery** | `cronjob`, `send_message` | Scheduled tasks with create/list/update/pause/resume/run/remove actions, plus outbound messaging delivery. | | **Integrations** | `ha_*`, MCP server tools | Home Assistant, MCP, and other integrations. | For the authoritative code-derived registry, see [Built-in Tools Reference](/reference/tools-reference) and [Toolsets Reference](/reference/toolsets-reference). > **TIP — Nous Tool Gateway** > > Paid [Nous Portal](https://portal.nousresearch.com) subscribers can use web search, image generation, TTS, and browser automation through the **[Tool Gateway](tool-gateway.md)** — no separate API keys needed. Run `hermes model` to enable it, or configure individual tools with `hermes tools`. ## Using Toolsets ```bash # 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`, `moa`, `skills`, `tts`, `todo`, `memory`, `session_search`, `cronjob`, `code_execution`, `delegation`, `clarify`, `homeassistant`, `messaging`, `spotify`, `discord`, `discord_admin`, `debugging`, and `safe`. See [Toolsets Reference](/reference/toolsets-reference) for the full set, including platform presets such as `hermes-cli`, `hermes-telegram`, and dynamic MCP toolsets like `mcp-`. ## 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 ```yaml # In ~/.hermes/config.yaml terminal: backend: local # or: docker, ssh, singularity, modal, daytona cwd: "." # Working directory timeout: 180 # Command timeout in seconds ``` ### Docker Backend ```yaml 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](/docs/user-guide/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: ```yaml terminal: backend: ssh ``` ```bash # Set credentials in ~/.hermes/.env TERMINAL_SSH_HOST=my-server.example.com TERMINAL_SSH_USER=myuser TERMINAL_SSH_KEY=~/.ssh/id_rsa ``` ### Singularity/Apptainer ```bash # 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) ```bash uv pip install modal modal setup hermes config set terminal.backend modal ``` ### Container Resources Configure CPU, memory, disk, and persistence for all container backends: ```yaml 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: ```python 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", session_id="proc_abc123") # Check status process(action="wait", session_id="proc_abc123") # Block until done process(action="log", session_id="proc_abc123") # Full output process(action="kill", session_id="proc_abc123") # Terminate process(action="write", session_id="proc_abc123", data="y") # Send input ``` PTY mode (`pty=true`) enables interactive CLI tools like Codex and Claude Code. ## Sudo Support If a command needs sudo, you'll be prompted for your password (cached for the session). Or set `SUDO_PASSWORD` in `~/.hermes/.env`. > **WARNING** > > On messaging platforms, if sudo fails, the output includes a tip to add `SUDO_PASSWORD` to `~/.hermes/.env`. --- --- ## Skills System Section: Core Features · URL: https://hermesbible.com/docs/user-guide/features/skills 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): ```bash hermes profile create research --no-skills ``` **On an already-installed profile** (default or named), toggle it at runtime: ```bash 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: ```bash # 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 ``` 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: ```bash hermes chat --toolsets skills -q "What skills do you have?" hermes chat --toolsets skills -q "Show me the axolotl skill" ``` ## 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 ```markdown --- name: my-skill description: Brief description of what this skill does version: 1.0.0 platforms: [macos, linux] # Optional — restrict to specific OS platforms metadata: hermes: tags: [python, automation] category: devops fallback_for_toolsets: [web] # Optional — conditional activation (see below) requires_toolsets: [terminal] # Optional — conditional activation (see below) config: # Optional — config.yaml settings - key: my.setting description: "What this controls" default: "value" prompt: "Prompt for setup" --- # Skill Title ## When to Use Trigger conditions for this skill. ## Procedure 1. Step one 2. Step two ## Pitfalls - Known failure modes and fixes ## Verification How to confirm it worked. ``` ### Platform-Specific Skills Skills can restrict themselves to specific operating systems using the `platforms` field: | Value | Matches | |-------|---------| | `macos` | macOS (Darwin) | | `linux` | Linux | | `windows` | Windows | ```yaml platforms: [macos] # macOS only (e.g., iMessage, Apple Reminders, FindMy) platforms: [macos, linux] # macOS and Linux ``` When set, the skill is automatically hidden from the system prompt, `skills_list()`, and slash commands on incompatible platforms. If omitted, the skill loads on all platforms. ## Skill output and media delivery When a skill response (or any agent response) includes a bare absolute path to a media file — for example `/home/user/screenshots/diagram.png` — the gateway auto-detects it, strips it from the visible text, and delivers the file natively to the user's chat (Telegram photo, Discord attachment, etc.) instead of leaving the raw path in the message. For audio specifically, the `[[audio_as_voice]]` directive promotes audio files to native voice-message bubbles on platforms that support them (Telegram, WhatsApp). ### Forcing document-style delivery: `[[as_document]]` Sometimes you want the **opposite** of inline preview: you want the file delivered as a downloadable attachment, not a re-compressed image bubble. The classic example is a high-resolution screenshot or chart — Telegram's `sendPhoto` recompresses it to ~200 KB at 1280 px, destroying readability. A 1-2 MB PNG sent via `sendDocument` keeps the original bytes intact. If a response (or any text inside it — typically the last line) contains the literal directive `[[as_document]]`, every media path extracted from that response is delivered as a document/file attachment rather than an image bubble: ``` Here is your rendered chart: /home/user/.hermes/cache/chart-q4-2025.png [[as_document]] ``` The directive is stripped before delivery, so users never see it. Granularity is intentionally all-or-nothing per response: emit `[[as_document]]` once and every image path in the same response is delivered as a document. This mirrors the scope of `[[audio_as_voice]]`. Use it from a skill when: - You produce screenshots or charts the user needs as files (for editing in another tool, archiving, sharing intact). - The default lossy preview would obscure detail (small text, pixel-accurate diagrams, color-sensitive renders). Platforms without a separate document path (e.g. SMS) fall back to whatever attachment mechanism they have. ### Conditional Activation (Fallback Skills) Skills can automatically show or hide themselves based on which tools are available in the current session. This is most useful for **fallback skills** — free or local alternatives that should only appear when a premium tool is unavailable. ```yaml metadata: hermes: fallback_for_toolsets: [web] # Show ONLY when these toolsets are unavailable requires_toolsets: [terminal] # Show ONLY when these toolsets are available fallback_for_tools: [web_search] # Show ONLY when these specific tools are unavailable requires_tools: [terminal] # Show ONLY when these specific tools are available ``` | Field | Behavior | |-------|----------| | `fallback_for_toolsets` | Skill is **hidden** when the listed toolsets are available. Shown when they're missing. | | `fallback_for_tools` | Same, but checks individual tools instead of toolsets. | | `requires_toolsets` | Skill is **hidden** when the listed toolsets are unavailable. Shown when they're present. | | `requires_tools` | Same, but checks individual tools. | **Example:** The built-in `duckduckgo-search` skill uses `fallback_for_toolsets: [web]`. When you have `FIRECRAWL_API_KEY` set, the web toolset is available and the agent uses `web_search` — the DuckDuckGo skill stays hidden. If the API key is missing, the web toolset is unavailable and the DuckDuckGo skill automatically appears as a fallback. Skills without any conditional fields behave exactly as before — they're always shown. ## Secure Setup on Load Skills can declare required environment variables without disappearing from discovery: ```yaml required_environment_variables: - name: TENOR_API_KEY prompt: Tenor API key help: Get a key from https://developers.google.com/tenor required_for: full functionality ``` When a missing value is encountered, Hermes asks for it securely only when the skill is actually loaded in the local CLI. You can skip setup and keep using the skill. Messaging surfaces never ask for secrets in chat — they tell you to use `hermes setup` or `~/.hermes/.env` locally instead. Once set, declared env vars are **automatically passed through** to `execute_code` and `terminal` sandboxes — the skill's scripts can use `$TENOR_API_KEY` directly. For non-skill env vars, use the `terminal.env_passthrough` config option. See [Environment Variable Passthrough](/user-guide/security#environment-variable-passthrough) for details. ### Skill Config Settings Skills can also declare non-secret config settings (paths, preferences) stored in `config.yaml`: ```yaml metadata: hermes: config: - key: myplugin.path description: Path to the plugin data directory default: "~/myplugin-data" prompt: Plugin data directory path ``` Settings are stored under `skills.config` in your config.yaml. `hermes config migrate` prompts for unconfigured settings, and `hermes config show` displays them. When a skill loads, its resolved config values are injected into the context so the agent knows the configured values automatically. See [Skill Settings](/user-guide/configuration#skill-settings) and [Creating Skills — Config Settings](/developer-guide/creating-skills#config-settings-configyaml) for details. ## Skill Directory Structure ```text ~/.hermes/skills/ # Single source of truth ├── mlops/ # Category directory │ ├── axolotl/ │ │ ├── SKILL.md # Main instructions (required) │ │ ├── references/ # Additional docs │ │ ├── templates/ # Output formats │ │ ├── scripts/ # Helper scripts callable from the skill │ │ └── assets/ # Supplementary files │ └── vllm/ │ └── SKILL.md ├── devops/ │ └── deploy-k8s/ # Agent-created skill │ ├── SKILL.md │ └── references/ ├── .hub/ # Skills Hub state │ ├── lock.json │ ├── quarantine/ │ └── audit.log └── .bundled_manifest # Tracks seeded bundled skills ``` ## External Skill Directories If you maintain skills outside of Hermes — for example, a shared `~/.agents/skills/` directory used by multiple AI tools — you can tell Hermes to scan those directories too. Add `external_dirs` under the `skills` section in `~/.hermes/config.yaml`: ```yaml skills: external_dirs: - ~/.agents/skills - /home/shared/team-skills - ${SKILLS_REPO}/skills ``` Paths support `~` expansion and `${VAR}` environment variable substitution. ### How it works - **Create locally, update in place**: New agent-created skills are written to `~/.hermes/skills/`. Existing skills are modified where they are found, including skills under `external_dirs`, when the agent uses `skill_manage` actions such as `patch`, `edit`, `write_file`, `remove_file`, or `delete`. - **External dirs are not a write-protection boundary**: If an external skill directory is writable by the Hermes process, agent-managed skill updates can change files in that directory. Use filesystem permissions or a separate profile/toolset setup if shared external skills must stay read-only. - **Local precedence**: If the same skill name exists in both the local dir and an external dir, the local version wins. - **Full integration**: External skills appear in the system prompt index, `skills_list`, `skill_view`, and as `/skill-name` slash commands — no different from local skills. - **Non-existent paths are silently skipped**: If a configured directory doesn't exist, Hermes ignores it without errors. Useful for optional shared directories that may not be present on every machine. ### Example ```text ~/.hermes/skills/ # Local (primary, read-write) ├── devops/deploy-k8s/ │ └── SKILL.md └── mlops/axolotl/ └── SKILL.md ~/.agents/skills/ # External (shared, mutable if writable) ├── my-custom-workflow/ │ └── SKILL.md └── team-conventions/ └── SKILL.md ``` All four skills appear in your skill index. If you create a new skill called `my-custom-workflow` locally, it shadows the external version. ## Skill Bundles Skill bundles are tiny YAML files that group several skills under a single slash command. When you run `/`, every skill listed in the bundle loads at once — useful when a particular task always benefits from the same set of skills together. ### Quick example ```bash # Create a bundle for backend feature work hermes bundles create backend-dev \ --skill github-code-review \ --skill test-driven-development \ --skill github-pr-workflow \ -d "Backend feature work — review, test, PR workflow" ``` Then in the CLI or any gateway platform: ``` /backend-dev refactor the auth middleware ``` The agent receives all three skills loaded into one user message, with any text after the slash command attached as a user instruction. ### YAML schema Bundles live in **`~/.hermes/skill-bundles/.yaml`** and look like this: ```yaml name: backend-dev description: Backend feature work — review, test, PR workflow. skills: - github-code-review - test-driven-development - github-pr-workflow instruction: | Always start by writing failing tests, then implement. Open the PR through the standard workflow with co-author tags. ``` Fields: - `name` (optional — defaults to the filename stem) — the bundle's display name. Normalized to a hyphen slug for the slash command (`Backend Dev` → `/backend-dev`). - `description` (optional) — short text shown in `/bundles` and `hermes bundles list`. - `skills` (required, non-empty list) — skill names or paths relative to your skills directory. Use the same identifier you'd pass to `/`. - `instruction` (optional) — extra guidance prepended to the loaded skill content. Useful for codifying "how we always use these together." ### Managing bundles ```bash # List all installed bundles hermes bundles list # Inspect one bundle hermes bundles show backend-dev # Create a bundle interactively (omit --skill flags to enter them one per line) hermes bundles create research # Overwrite an existing bundle hermes bundles create backend-dev --skill ... --force # Delete a bundle hermes bundles delete backend-dev # Re-scan ~/.hermes/skill-bundles/ and report changes hermes bundles reload ``` From inside a chat session, `/bundles` lists every installed bundle and its skills. ### Behavior - **Bundles take precedence over individual skills** when slugs collide. If you name a bundle `research` and you also have a skill called `research`, `/research` invokes the bundle. This is intentional — you opted into the bundle by naming it. - **Missing skills are skipped, not fatal.** If a bundle lists `skill-foo` and you haven't installed it, the bundle still loads the skills that do resolve, and the agent gets a note listing what was skipped. - **Bundles work in every surface** — interactive CLI, TUI, dashboard chat, and every gateway platform (Telegram, Discord, Slack, …) — because dispatch is centralized in the same place as individual skill commands. - **Bundles do not invalidate the prompt cache.** They generate a fresh user message at invocation time, the same way `/` does — no system prompt mutation. ### When bundles beat installing each skill manually Use a bundle when: - You always pair the same skills for a recurring task (`/backend-dev`, `/release-prep`, `/incident-response`). - You want a one-character-shorter mental model than typing several `/skill` invocations in a row. - You want to ship a team-wide "task profile" by checking the bundle YAML into a shared dotfiles repo and symlinking it into `~/.hermes/skill-bundles/`. A bundle is just a YAML alias — it doesn't install skills for you. The skills themselves must already be present (in `~/.hermes/skills/` or an external skill directory). Otherwise the bundle invocation just skips the missing ones. ## Agent-Managed Skills (skill_manage tool) The agent can create, update, and delete its own skills via the `skill_manage` tool. This is the agent's **procedural memory** — when it figures out a non-trivial workflow, it saves the approach as a skill for future reuse. ### When the Agent Creates Skills - After completing a complex task (5+ tool calls) successfully - When it hit errors or dead ends and found the working path - When the user corrected its approach - When it discovered a non-trivial workflow ### Actions | Action | Use for | Key params | |--------|---------|------------| | `create` | New skill from scratch | `name`, `content` (full SKILL.md), optional `category` | | `patch` | Targeted fixes (preferred) | `name`, `old_string`, `new_string` | | `edit` | Major structural rewrites | `name`, `content` (full SKILL.md replacement) | | `delete` | Remove a skill entirely | `name` | | `write_file` | Add/update supporting files | `name`, `file_path`, `file_content` | | `remove_file` | Remove a supporting file | `name`, `file_path` | > **TIP** > > The `patch` action is preferred for updates — it's more token-efficient than `edit` because only the changed text appears in the tool call. ### Gating agent skill writes (`skills.write_approval`) By default the agent writes skills freely — including from the [background self-improvement review](/user-guide/features/memory#controlling-memory-writes-write_approval) that runs after a turn. If you'd rather approve every skill write first (small models that misjudge what they learned, secure environments, or just wanting eyes on the self-improvement loop), turn on the write-approval gate: ```yaml skills: write_approval: false # false = write freely (default) | true = require approval ``` When `write_approval: true`, every `skill_manage` write (create / edit / patch / delete / write_file / remove_file) is **staged** instead of committed — a SKILL.md is too large to review inline, so staging applies regardless of whether the write came from a foreground turn or the background review. Staged writes survive restarts under `~/.hermes/pending/skills/` and are reviewed with the same familiar approve/deny flow as dangerous commands: ``` /skills pending # list staged skill writes + a one-line gist each /skills diff # full unified diff (best viewed in CLI or dashboard) /skills approve # apply it (or 'all') /skills reject # drop it (or 'all') /skills approval on # turn the gate on (or 'off') and persist it ``` The review surface works in the interactive CLI and on messaging platforms (diff output is truncated for chat bubbles — read the full diff on the CLI or in the pending JSON file). Memory writes have the same gate under `memory.write_approval` — see [Controlling memory writes](/user-guide/features/memory#controlling-memory-writes-write_approval). > The separate `skills.guard_agent_created` setting is a content scanner > (dangerous-pattern heuristics), not an approval gate — the two are > independent. See [Guard on agent-created skill writes](/user-guide/configuration#guard-on-agent-created-skill-writes). ## Skills Hub Browse, search, install, and manage skills from online registries, `skills.sh`, direct well-known skill endpoints, and official optional skills. ### Common commands ```bash hermes skills browse # Browse all hub skills (official first) hermes skills browse --source official # Browse only official optional skills hermes skills search kubernetes # Search all sources hermes skills search react --source skills-sh # Search the skills.sh directory hermes skills search https://mintlify.com/docs --source well-known hermes skills inspect openai/skills/k8s # Preview before installing hermes skills install openai/skills/k8s # Install with security scan hermes skills install official/security/1password hermes skills install skills-sh/vercel-labs/json-render/json-render-react --force hermes skills install well-known:https://mintlify.com/docs/.well-known/skills/mintlify hermes skills install https://sharethis.chat/SKILL.md # Direct URL (single-file SKILL.md) hermes skills install https://example.com/SKILL.md --name my-skill # Override name when frontmatter has none hermes skills list --source hub # List hub-installed skills hermes skills check # Check installed hub skills for upstream updates hermes skills update # Reinstall hub skills with upstream changes when needed hermes skills audit # Re-scan all hub skills for security hermes skills uninstall k8s # Remove a hub skill hermes skills reset google-workspace # Un-stick a bundled skill from "user-modified" (see below) hermes skills reset google-workspace --restore # Also restore the bundled version, deleting your local edits hermes skills publish skills/my-skill --to github --repo owner/repo hermes skills snapshot export setup.json # Export skill config hermes skills tap add myorg/skills-repo # Add a custom GitHub source ``` ### Supported hub sources | Source | Example | Notes | |--------|---------|-------| | `official` | `official/security/1password` | Optional skills shipped with Hermes. | | `skills-sh` | `skills-sh/vercel-labs/agent-skills/vercel-react-best-practices` | Searchable via `hermes skills search --source skills-sh`. Hermes resolves alias-style skills when the skills.sh slug differs from the repo folder. | | `well-known` | `well-known:https://mintlify.com/docs/.well-known/skills/mintlify` | Skills served directly from `/.well-known/skills/index.json` on a website. Search using the site or docs URL. | | `url` | `https://sharethis.chat/SKILL.md` | Direct HTTP(S) URL to a single-file `SKILL.md`. Name resolution: frontmatter → URL slug → interactive prompt → `--name` flag. | | `github` | `openai/skills/k8s` | Direct GitHub repo/path installs and custom taps. | | `clawhub`, `lobehub`, `browse-sh` | Source-specific identifiers | Community or marketplace integrations. | ### Integrated hubs and registries Hermes currently integrates with these skills ecosystems and discovery sources: #### 1. Official optional skills (`official`) These are maintained in the Hermes repository itself and install with built-in trust. - Catalog: [Official Optional Skills Catalog](../../reference/optional-skills-catalog) - Source in repo: `optional-skills/` - Example: ```bash hermes skills browse --source official hermes skills install official/security/1password ``` #### 2. skills.sh (`skills-sh`) This is Vercel's public skills directory. Hermes can search it directly, inspect skill detail pages, resolve alias-style slugs, and install from the underlying source repo. - Directory: [skills.sh](https://skills.sh/) - CLI/tooling repo: [vercel-labs/skills](https://github.com/vercel-labs/skills) - Official Vercel skills repo: [vercel-labs/agent-skills](https://github.com/vercel-labs/agent-skills) - Example: ```bash hermes skills search react --source skills-sh hermes skills inspect skills-sh/vercel-labs/json-render/json-render-react hermes skills install skills-sh/vercel-labs/json-render/json-render-react --force ``` #### 3. Well-known skill endpoints (`well-known`) This is URL-based discovery from sites that publish `/.well-known/skills/index.json`. It is not a single centralized hub — it is a web discovery convention. - Example live endpoint: [Mintlify docs skills index](https://mintlify.com/docs/.well-known/skills/index.json) - Reference server implementation: [vercel-labs/skills-handler](https://github.com/vercel-labs/skills-handler) - Example: ```bash hermes skills search https://mintlify.com/docs --source well-known hermes skills inspect well-known:https://mintlify.com/docs/.well-known/skills/mintlify hermes skills install well-known:https://mintlify.com/docs/.well-known/skills/mintlify ``` #### 4. Direct GitHub skills (`github`) Hermes can install directly from GitHub repositories and GitHub-based taps. This is useful when you already know the repo/path or want to add your own custom source repo. Default taps (browsable without any setup): - [openai/skills](https://github.com/openai/skills) - [anthropics/skills](https://github.com/anthropics/skills) - [huggingface/skills](https://github.com/huggingface/skills) - [NVIDIA/skills](https://github.com/NVIDIA/skills) — NVIDIA-verified skills (signed `skill.oms.sig` + governance `skill-card.md`) - [garrytan/gstack](https://github.com/garrytan/gstack) - Example: ```bash hermes skills install openai/skills/k8s hermes skills tap add myorg/skills-repo ``` **Category groupings (`skills.sh.json`).** A GitHub tap may ship a `skills.sh.json` file at its repo root following the [skills.sh schema](https://skills.sh/schemas/skills.sh.schema.json). Its `groupings` (each with a `title` and a list of skill names) are read at index time and become the category labels shown in the [Skills Hub](https://hermes-agent.nousresearch.com/docs) page — instead of a tag-derived guess. This is generic: any tap that ships the file gets real categorization, no Hermes-side changes required. ```json { "$schema": "https://skills.sh/schemas/skills.sh.schema.json", "groupings": [ { "title": "Inference AI", "skills": ["dynamo-recipe-runner", "dynamo-router-sla"] }, { "title": "Decision Optimization", "skills": ["cuopt-developer", "cuopt-install"] } ] } ``` #### 5. ClawHub (`clawhub`) A third-party skills marketplace integrated as a community source. - Site: [clawhub.ai](https://clawhub.ai/) - Hermes source id: `clawhub` #### 6. Claude marketplace-style repos (`claude-marketplace`) Hermes supports marketplace repos that publish Claude-compatible plugin/marketplace manifests. Known integrated sources include: - [anthropics/skills](https://github.com/anthropics/skills) - [aiskillstore/marketplace](https://github.com/aiskillstore/marketplace) Hermes source id: `claude-marketplace` #### 7. LobeHub (`lobehub`) Hermes can search and convert agent entries from LobeHub's public catalog into installable Hermes skills. - Site: [LobeHub](https://lobehub.com/) - Public agents index: [chat-agents.lobehub.com](https://chat-agents.lobehub.com/) - Backing repo: [lobehub/lobe-chat-agents](https://github.com/lobehub/lobe-chat-agents) - Hermes source id: `lobehub` #### 8. browse.sh (`browse-sh`) Hermes integrates with [browse.sh](https://browse.sh), Browserbase's catalog of 200+ site-specific browser-automation SKILL.md files (Airbnb, Amazon, arXiv, 12306.cn, Etsy, Xero, and many more). Each skill describes how to drive one website end-to-end and is suitable for use with Hermes' browser tools and any browser-automation skills you already have installed. - Site: [browse.sh](https://browse.sh/) - Catalog API: `https://browse.sh/api/skills` - Hermes source id: `browse-sh` - Trust level: `community` ```bash hermes skills search airbnb --source browse-sh hermes skills inspect browse-sh/airbnb.com/search-listings-ddgioa hermes skills install browse-sh/airbnb.com/search-listings-ddgioa ``` Identifiers use the form `browse-sh//` and match the slug exposed by the browse.sh catalog. Content is resolved through the per-skill detail endpoint (`/api/skills/` → `skillMdUrl`), not through the catalog's GitHub `sourceUrl`. #### 9. Direct URL (`url`) Install a single-file `SKILL.md` directly from any HTTP(S) URL — useful when an author hosts a skill on their own site (no hub listing, no GitHub path to type). Hermes fetches the URL, parses the YAML frontmatter, security-scans it, and installs. - Hermes source id: `url` - Identifier: the URL itself (no prefix needed) - Scope: **single-file `SKILL.md`** only. Multi-file skills with `references/` or `scripts/` need a manifest and should be published via one of the other sources above. ```bash hermes skills install https://sharethis.chat/SKILL.md hermes skills install https://example.com/my-skill/SKILL.md --category productivity ``` Name resolution, in order: 1. `name:` field in the SKILL.md YAML frontmatter (recommended — every well-formed skill has one). 2. Parent directory name from the URL path (e.g. `.../my-skill/SKILL.md` → `my-skill`, or `.../my-skill.md` → `my-skill`), when it's a valid identifier (`^[a-z][a-z0-9_-]*$`). 3. Interactive prompt on a terminal with a TTY. 4. On non-interactive surfaces (the `/skills install` slash command inside the TUI, gateway platforms, scripts), a clean error pointing at the `--name` override. ```bash # Frontmatter has no name and the URL slug is unhelpful — supply one: hermes skills install https://example.com/SKILL.md --name sharethis-chat # Or inside a chat session: /skills install https://example.com/SKILL.md --name sharethis-chat ``` Trust level is always `community` — the same security scan runs as for every other source. The URL is stored as the install identifier, so `hermes skills update` re-fetches from the same URL automatically when you want to refresh. ### Security scanning and `--force` All hub-installed skills go through a **security scanner** that checks for data exfiltration, prompt injection, destructive commands, supply-chain signals, and other threats. `hermes skills inspect ...` now also surfaces upstream metadata when available: - repo URL - skills.sh detail page URL - install command - weekly installs - upstream security audit statuses - well-known index/endpoint URLs Use `--force` when you have reviewed a third-party skill and want to override a non-dangerous policy block: ```bash hermes skills install skills-sh/anthropics/skills/pdf --force ``` Important behavior: - `--force` can override policy blocks for caution/warn-style findings. - `--force` does **not** override a `dangerous` scan verdict. - Official optional skills (`official/...`) are treated as built-in trust and do not show the third-party warning panel. ### Trust levels | Level | Source | Policy | |-------|--------|--------| | `builtin` | Ships with Hermes | Always trusted | | `official` | `optional-skills/` in the repo | Built-in trust, no third-party warning | | `trusted` | Trusted registries/repos such as `openai/skills`, `anthropics/skills`, `huggingface/skills`, `NVIDIA/skills` | More permissive policy than community sources | | `community` | Everything else (`skills.sh`, well-known endpoints, custom GitHub repos, most marketplaces) | Non-dangerous findings can be overridden with `--force`; `dangerous` verdicts stay blocked | ### Update lifecycle The hub now tracks enough provenance to re-check upstream copies of installed skills: ```bash hermes skills check # Report which installed hub skills changed upstream hermes skills update # Reinstall only the skills with updates available hermes skills update react # Update one specific installed hub skill ``` This uses the stored source identifier plus the current upstream bundle content hash to detect drift. > **TIP — GitHub rate limits** > > Skills hub operations use the GitHub API, which has a rate limit of 60 requests/hour for unauthenticated users. If you see rate-limit errors during install or search, set `GITHUB_TOKEN` in your `.env` file to increase the limit to 5,000 requests/hour. The error message includes an actionable hint when this happens. ### Publishing a custom skill tap If you want to share a curated set of skills — for your team, your org, or publicly — you can publish them as a **tap**: a GitHub repository other Hermes users add with `hermes skills tap add `. No server, no registry sign-up, no release pipeline. Just a directory of `SKILL.md` files. #### Repo layout A tap is any GitHub repo (public or private — private needs `GITHUB_TOKEN`) laid out like this: ``` owner/repo ├── skills/ # default path; configurable per-tap │ ├── my-workflow/ │ │ ├── SKILL.md # required │ │ ├── references/ # optional supporting files │ │ ├── templates/ │ │ └── scripts/ │ ├── another-skill/ │ │ └── SKILL.md │ └── third-skill/ │ └── SKILL.md └── README.md # optional but helpful ``` Rules: - Each skill lives in its own directory under the tap's root path (default `skills/`). - The directory name becomes the skill's install slug. - Each skill directory must contain a `SKILL.md` with standard [SKILL.md frontmatter](#skillmd-format) (`name`, `description`, plus optional `metadata.hermes.tags`, `version`, `author`, `platforms`, `metadata.hermes.config`). - Subdirectories like `references/`, `templates/`, `scripts/`, `assets/` are downloaded alongside `SKILL.md` at install time. - Skills whose directory name starts with `.` or `_` are ignored. Hermes discovers skills by listing every subdirectory of the tap path and probing each for `SKILL.md`. #### Minimal tap example ``` my-org/hermes-skills └── skills/ └── deploy-runbook/ └── SKILL.md ``` `skills/deploy-runbook/SKILL.md`: ```markdown --- name: deploy-runbook description: Our deployment runbook — services, rollback, Slack channels version: 1.0.0 author: My Org Platform Team metadata: hermes: tags: [deployment, runbook, internal] --- # Deploy Runbook Step 1: ... ``` After pushing that to GitHub, any Hermes user can subscribe and install: ```bash hermes skills tap add my-org/hermes-skills hermes skills search deploy hermes skills install my-org/hermes-skills/deploy-runbook ``` #### Non-default paths If your skills don't live under `skills/` (common when you're adding a `skills/` subtree to an existing project), edit the tap entry in `~/.hermes/.hub/taps.json`: ```json { "taps": [ {"repo": "my-org/platform-docs", "path": "internal/skills/"} ] } ``` The `hermes skills tap add` CLI defaults new taps to `path: "skills/"`; edit the file directly if you need a different path. `hermes skills tap list` shows the effective path per tap. #### Installing individual skills directly (without adding a tap) Users can also install a single skill from any public GitHub repo without adding the whole repo as a tap: ```bash hermes skills install owner/repo/skills/my-workflow ``` Useful when you want to share one skill without asking the user to subscribe to your whole registry. #### Trust levels for taps New taps are assigned `community` trust by default. Skills installed from them run through the standard security scan and show the third-party warning panel on first install. If your org or a widely-trusted source should get higher trust, add its repo to `TRUSTED_REPOS` in `tools/skills_hub.py` (requires a Hermes core PR). #### Tap management ```bash hermes skills tap list # show all configured taps hermes skills tap add myorg/skills-repo # add (default path: skills/) hermes skills tap remove myorg/skills-repo # remove ``` Inside a running session: ``` /skills tap list /skills tap add myorg/skills-repo /skills tap remove myorg/skills-repo ``` Taps are stored in `~/.hermes/.hub/taps.json` (created on demand). ## Bundled skill updates (`hermes skills reset`) Hermes ships with a set of bundled skills in `skills/` inside the repo. On install and on every `hermes update`, a sync pass copies those into `~/.hermes/skills/` and records a manifest at `~/.hermes/skills/.bundled_manifest` mapping each skill name to the content hash at the time it was synced (the **origin hash**). On each sync, Hermes recomputes the hash of your local copy and compares it to the origin hash: - **Unchanged** → safe to pull upstream changes, copy the new bundled version in, record the new origin hash. - **Changed** → treated as **user-modified** and skipped forever, so your edits never get stomped. The protection is good, but it has one sharp edge. If you edit a bundled skill and then later want to abandon your changes and go back to the bundled version by just copy-pasting from `~/.hermes/hermes-agent/skills/`, the manifest still holds the *old* origin hash from whenever the last successful sync ran. Your fresh copy-paste contents (current bundled hash) won't match that stale origin hash, so sync keeps flagging it as user-modified. `hermes skills reset` is the escape hatch: ```bash # Safe: clears the manifest entry for this skill. Your current copy is preserved, # but the next sync re-baselines against it so future updates work normally. hermes skills reset google-workspace # Full restore: also deletes your local copy and re-copies the current bundled # version. Use this when you want the pristine upstream skill back. hermes skills reset google-workspace --restore # Non-interactive (e.g. in scripts or TUI mode) — skip the --restore confirmation. hermes skills reset google-workspace --restore --yes ``` The same command works in chat as a slash command: ```text /skills reset google-workspace /skills reset google-workspace --restore ``` > **NOTE — Profiles** > > Each profile has its own `.bundled_manifest` under its own `HERMES_HOME`, so `hermes -p coder skills reset ` only affects that profile. ### Slash commands (inside chat) All the same commands work with `/skills`: ```text /skills browse /skills search react --source skills-sh /skills search https://mintlify.com/docs --source well-known /skills inspect skills-sh/vercel-labs/json-render/json-render-react /skills install openai/skills/skill-creator --force /skills check /skills update /skills reset google-workspace /skills list ``` Official optional skills still use identifiers like `official/security/1password` and `official/migration/openclaw-migration`. --- --- ## Curator Section: Core Features · URL: https://hermesbible.com/docs/user-guide/features/curator The curator is a background maintenance pass for **agent-created skills**. It tracks how often each skill is viewed, used, and patched, moves long-unused skills through `active → stale → archived` states, and periodically spawns a short auxiliary-model review that proposes consolidations or patches drift. It exists so that skills created via the [self-improvement loop](/user-guide/features/skills#agent-managed-skills-skill_manage-tool) don't pile up forever. Every time the agent solves a novel problem and saves a skill, that skill lands in `~/.hermes/skills/`. Without maintenance, you end up with dozens of narrow near-duplicates that pollute the catalog and waste tokens. By default (`prune_builtins: true`) the curator can archive **unused bundled built-in skills** (shipped with the repo) after `archive_after_days` of non-use, alongside the agent-created skills it primarily manages. Hub-installed skills (from [agentskills.io](https://agentskills.io)) are always off-limits. Set `curator.prune_builtins: false` to restore the old agent-created-only behavior, where bundled skills are never touched. The curator also **never auto-deletes** — the worst outcome is archival into `~/.hermes/skills/.archive/`, which is recoverable. Tracks [issue #7816](https://github.com/NousResearch/hermes-agent/issues/7816). ## How it runs The curator is triggered by an inactivity check, not a cron daemon. On CLI session start, and on a recurring tick inside the gateway's cron-ticker thread, Hermes checks whether: 1. Enough time has passed since the last curator run (`interval_hours`, default **7 days**), and 2. The agent has been idle long enough (`min_idle_hours`, default **2 hours**). If both are true, it spawns a background fork of `AIAgent` — the same pattern used by the memory/skill self-improvement nudges. The fork runs in its own prompt cache and never touches the active conversation. > **INFO — First-run behavior** > > On a brand-new install (or the first time a pre-curator install ticks after `hermes update`), the curator **does not run immediately**. The first observation seeds `last_run_at` to "now" and defers the first real pass by one full `interval_hours`. This gives you a full interval to review your skill library, pin anything important, or opt out entirely before the curator ever touches it. > > If you want to see what the curator *would* do before it runs for real, run `hermes curator run --dry-run` — it produces the same review report without mutating the library. A run has two phases: 1. **Automatic transitions** (deterministic, no LLM). Skills unused for `stale_after_days` (30) become `stale`; skills unused for `archive_after_days` (90) are moved to `~/.hermes/skills/.archive/`. 2. **LLM review** (single aux-model pass, `max_iterations=8`). The forked agent surveys the agent-created skills, can read any of them with `skill_view`, and decides per-skill whether to keep, patch (via `skill_manage`), consolidate overlapping ones, or archive via the terminal tool. Consolidation treats a skill as a full package: if a skill has `references/`, `templates/`, `scripts/`, `assets/`, or relative links to those paths, the curator must either keep it standalone, re-home the needed support files and rewrite paths, or archive the entire package unchanged — not flatten only `SKILL.md` into another skill's `references/` file. Pinned skills are off-limits to both the curator's auto-transitions and the agent's own `skill_manage` tool. See [Pinning a skill](#pinning-a-skill) below. ## Configuration All settings live in `config.yaml` under `curator:` (not `.env` — this isn't a secret). Defaults: ```yaml curator: enabled: true interval_hours: 168 # 7 days min_idle_hours: 2 stale_after_days: 30 archive_after_days: 90 prune_builtins: true # archive unused bundled built-in skills too (hub skills always exempt) ``` To disable entirely, set `curator.enabled: false`. ### Running the review on a cheaper aux model The curator's LLM review pass is a regular auxiliary task slot — `auxiliary.curator` — alongside Vision, Compression, Session Search, etc. "Auto" means "use my main chat model"; override the slot to pin a specific provider + model for the review pass instead. **Easiest — `hermes model`:** ```bash hermes model # → "Auxiliary models — side-task routing" # → pick "Curator" → pick provider → pick model ``` The same picker is available in the web dashboard under the **Models** tab. **Direct config.yaml (equivalent):** ```yaml auxiliary: curator: provider: openrouter model: google/gemini-3-flash-preview timeout: 600 # generous — reviews can take several minutes ``` Leaving `provider: auto` (the default) routes the review pass through whatever your main chat model is, matching the behavior of every other auxiliary task. > **NOTE — Legacy config** > > Earlier releases used a one-off `curator.auxiliary.{provider,model}` block. That path still works but emits a deprecation log line — please migrate to `auxiliary.curator` above so the curator shares the same plumbing (`hermes model`, dashboard Models tab, `base_url`, `api_key`, `timeout`, `extra_body`) as every other aux task. ## CLI ```bash hermes curator status # last run, counts, pinned list, LRU top 5 hermes curator run # trigger a review now (blocks until the LLM pass finishes) hermes curator run --background # fire-and-forget: start the LLM pass in a background thread hermes curator run --dry-run # preview only — report without any mutations hermes curator backup # take a manual snapshot of ~/.hermes/skills/ hermes curator rollback # restore from the newest snapshot hermes curator rollback --list # list available snapshots hermes curator rollback --id # restore a specific snapshot hermes curator rollback -y # skip the confirmation prompt hermes curator pause # stop runs until resumed hermes curator resume hermes curator pin # never auto-transition this skill hermes curator unpin hermes curator restore # move an archived skill back to active hermes curator list-archived # list skills currently in ~/.hermes/skills/.archive/ hermes curator archive # manually archive a single skill now hermes curator prune [--days N] # bulk-archive agent-created skills idle >= N days (default 90) ``` ## Backups and rollback Before every real curator pass, Hermes takes a tar.gz snapshot of `~/.hermes/skills/` at `~/.hermes/skills/.curator_backups//skills.tar.gz`. If a pass archives or consolidates something you didn't want touched, you can undo the whole run with one command: ```bash hermes curator rollback # restore newest snapshot (with confirmation) hermes curator rollback -y # skip the prompt hermes curator rollback --list # see all snapshots with reason + size ``` The rollback itself is reversible: before replacing the skills tree, Hermes takes another snapshot tagged `pre-rollback to `, so a mistaken rollback can be undone by rolling forward to that one with `--id`. You can also take manual snapshots at any time with `hermes curator backup --reason "before-refactor"`. The `--reason` string lands in the snapshot's `manifest.json` and is shown in `--list`. Snapshots are pruned to `curator.backup.keep` (default 5) to keep disk usage bounded: ```yaml curator: backup: enabled: true keep: 5 ``` Set `curator.backup.enabled: false` to disable automatic snapshotting. The manual `hermes curator backup` command still works when backups are disabled only if you set `enabled: true` first — the flag gates both paths symmetrically so there's no way to accidentally skip the pre-run snapshot on mutating runs. `hermes curator status` also lists the five least-recently-used skills — a quick way to see what's likely to become stale next. The same subcommands are available as the `/curator` slash command inside a running session (CLI or gateway platforms). ## What "agent-created" means The curator only manages skills explicitly marked as **agent-created** in `~/.hermes/skills/.usage.json`. A skill qualifies when ALL of the following are true: 1. Its name is **not** in `~/.hermes/skills/.bundled_manifest` (bundled skills shipped with the repo). 2. Its name is **not** in `~/.hermes/skills/.hub/lock.json` (hub-installed skills). 3. Its `.usage.json` entry has `"created_by": "agent"` or `"agent_created": true`. Currently, only the **background self-improvement review fork** sets this marker — when it creates a new umbrella skill during its periodic review pass (~every 10 agent turns). The background fork runs with a write origin of `"background_review"` (via `tools/skill_provenance.py`), which is the only path that triggers the `mark_agent_created()` call in `skill_manage`. Skills the foreground agent creates via `skill_manage(action="create")` during a conversation are **not** marked as agent-created — they are considered user-directed and the curator intentionally leaves them alone. > **WARNING — Your hand-written skills are NOT curated** > > If you manually created a `SKILL.md` or pointed Hermes at an external skill > directory, that skill will have a `.usage.json` entry with `created_by: null` > (or the field absent). The curator will not touch it. The same applies to > skills the foreground agent created at your request. > > **To see which skills the curator actually manages**, run `hermes curator status`. > If the agent-created count is 0, no skills are currently in the curator's > jurisdiction — the LLM review pass is skipped and the report will show > `Model: (not resolved) via (not resolved)` with `Duration: 0s`. Skills that ARE agent-created follow the full lifecycle: - `active` → (30d unused) `stale` → (90d unused) `archived` - Pinned skills bypass all auto-transitions - Archives are recoverable via `hermes curator restore ` If you want to protect a specific skill from ever being touched — for example a hand-authored skill you rely on — use `hermes curator pin `. See the next section. ## Pinning a skill Pinning protects a skill from deletion — both the curator's automated archive passes and the agent's `skill_manage(action="delete")` tool call. Once a skill is pinned: - The **curator** skips it during auto-transitions (`active → stale → archived`), and its LLM review pass is instructed to leave it alone. - The **agent's `skill_manage` tool** refuses `delete` on it, pointing the user at `hermes curator unpin `. Patches and edits still go through, so the agent can improve a pinned skill's content as pitfalls come up without a pin/unpin/re-pin dance. Pin and unpin with: ```bash hermes curator pin hermes curator unpin ``` The flag is stored as `"pinned": true` on the skill's entry in `~/.hermes/skills/.usage.json`, so it survives across sessions. Only **agent-created** skills can be pinned — `hermes curator pin` refuses on bundled and hub-installed skills with an explanatory message if you try. Hub-installed skills are never subject to curator mutation. Bundled built-in skills are only touched when `curator.prune_builtins: true` (the default), and even then only archived after `archive_after_days` of non-use — never patched, consolidated, or deleted. Set `curator.prune_builtins: false` to exempt bundled skills entirely. A small set of **protected built-ins** is hardcoded as never-archivable and never-consolidatable, regardless of `curator.prune_builtins`, pin state, or LLM judgment. These back load-bearing UX — for example, `plan` powers the `/plan` slash-command flow — so silently archiving one would turn its slash command into an "Unknown command" error with no signal to you. Protected built-ins are filtered out of the curator's candidate list entirely, so the consolidation pass never sees them. If you want a stronger guarantee than "no deletion" — for instance, freezing a skill's content entirely while the agent still reads it — edit `~/.hermes/skills//SKILL.md` directly with your editor. The pin guards tool-driven deletion, not your own filesystem access. ## Usage telemetry The curator maintains a sidecar at `~/.hermes/skills/.usage.json` with one entry per skill: ```json { "my-skill": { "use_count": 12, "view_count": 34, "last_used_at": "2026-04-24T18:12:03Z", "last_viewed_at": "2026-04-23T09:44:17Z", "patch_count": 3, "last_patched_at": "2026-04-20T22:01:55Z", "created_at": "2026-03-01T14:20:00Z", "state": "active", "pinned": false, "archived_at": null } } ``` Counters increment when: - `view_count`: the agent calls `skill_view` on the skill. - `use_count`: the skill is loaded into a conversation's prompt. - `patch_count`: `skill_manage patch/edit/write_file/remove_file` runs on the skill. Bundled and hub-installed skills are explicitly excluded from telemetry writes. ## Per-run reports Every curator run writes a timestamped directory under `~/.hermes/logs/curator/`: ``` ~/.hermes/logs/curator/ └── 20260429-111512/ ├── run.json # machine-readable: full fidelity, stats, LLM output └── REPORT.md # human-readable summary ``` `REPORT.md` is a quick way to see what a given run did — which skills transitioned, what the LLM reviewer said, which skills it patched. Good for auditing without having to grep `agent.log`. > **NOTE — No candidates? Report shows `(not resolved)`** > > When the curator has **no agent-created skills** to review, the LLM review pass > is skipped entirely. The report header will show > `Model: (not resolved) via (not resolved)` with `Duration: 0s` — this does **not** > indicate a configuration error or model resolution failure. It simply means there > were no candidates, so no model was ever invoked. The auto-transition phase still > runs and reports its counts normally. ### Rename map in the summary If a run consolidated multiple skills under an umbrella (or merged near-duplicates), the user-visible summary printed at the end of the run includes an explicit rename map showing every `old-name → new-name` pair the curator applied. This is in addition to per-skill transition lines, so when a wave of renames lands you can spot them at a glance without diffing the JSON report. The hint also surfaces under `hermes curator pin` so you can pin the umbrella name immediately if you want to lock the new label in. ## Restoring an archived skill If the curator archived something you still want: ```bash hermes curator restore ``` This moves the skill back from `~/.hermes/skills/.archive/` to the active tree and resets its state to `active`. The restore refuses if a bundled or hub-installed skill has since been installed under the same name (would shadow upstream). ## Disabling per environment The curator is on by default. To turn it off: - **For one profile only:** edit `~/.hermes/config.yaml` (or the active profile's config) and set `curator.enabled: false`. - **For just one run:** `hermes curator pause` — the pause persists across sessions; use `resume` to re-enable. The curator also refuses to run if `min_idle_hours` hasn't elapsed, so on an active dev machine it naturally only runs during quiet stretches. ## See also - [Skills System](/user-guide/features/skills) — how skills work in general and the self-improvement loop that creates them - [Memory](/user-guide/features/memory) — a parallel background review that maintains long-term memory - [Bundled Skills Catalog](/reference/skills-catalog) - [Issue #7816](https://github.com/NousResearch/hermes-agent/issues/7816) — original proposal and design discussion --- --- ## Persistent Memory Section: Core Features · URL: https://hermesbible.com/docs/user-guide/features/memory Hermes Agent has bounded, curated memory that persists across sessions. This lets it remember your preferences, your projects, your environment, and things it has learned. ## How It Works Two files make up the agent's memory: | File | Purpose | Char Limit | |------|---------|------------| | **MEMORY.md** | Agent's personal notes — environment facts, conventions, things learned | 2,200 chars (~800 tokens) | | **USER.md** | User profile — your preferences, communication style, expectations | 1,375 chars (~500 tokens) | Both are stored in `~/.hermes/memories/` and are injected into the system prompt as a frozen snapshot at session start. The agent manages its own memory via the `memory` tool — it can add, replace, or remove entries. > **INFO** > > Character limits keep memory focused. Memory does **not** auto-compact: when a > write would exceed the limit, the `memory` tool returns an error instead of > silently dropping entries. The agent then makes room itself — consolidating or > removing entries in the same turn before retrying (see [What Happens When Memory > is Full](#what-happens-when-memory-is-full)). Note that `replace` is also bound > by the limit: swapping an entry for a longer one can still overflow, so the new > content must be shortened (or another entry removed) to fit. ## How Memory Appears in the System Prompt At the start of every session, memory entries are loaded from disk and rendered into the system prompt as a frozen block: ``` ══════════════════════════════════════════════ MEMORY (your personal notes) [67% — 1,474/2,200 chars] ══════════════════════════════════════════════ User's project is a Rust web service at ~/code/myapi using Axum + SQLx § This machine runs Ubuntu 22.04, has Docker and Podman installed § User prefers concise responses, dislikes verbose explanations ``` The format includes: - A header showing which store (MEMORY or USER PROFILE) - Usage percentage and character counts so the agent knows capacity - Individual entries separated by `§` (section sign) delimiters - Entries can be multiline **Frozen snapshot pattern:** The system prompt injection is captured once at session start and never changes mid-session. This is intentional — it preserves the LLM's prefix cache for performance. When the agent adds/removes memory entries during a session, the changes are persisted to disk immediately but won't appear in the system prompt until the next session starts. Tool responses always show the live state. ## Memory Tool Actions The agent uses the `memory` tool with these actions: - **add** — Add a new memory entry - **replace** — Replace an existing entry with updated content (uses substring matching via `old_text`) - **remove** — Remove an entry that's no longer relevant (uses substring matching via `old_text`) There is no `read` action — memory content is automatically injected into the system prompt at session start. The agent sees its memories as part of its conversation context. ### Substring Matching The `replace` and `remove` actions use short unique substring matching — you don't need the full entry text. The `old_text` parameter just needs to be a unique substring that identifies exactly one entry: ```python # If memory contains "User prefers dark mode in all editors" memory(action="replace", target="memory", old_text="dark mode", content="User prefers light mode in VS Code, dark mode in terminal") ``` If the substring matches multiple entries, an error is returned asking for a more specific match. ## Two Targets Explained ### `memory` — Agent's Personal Notes For information the agent needs to remember about the environment, workflows, and lessons learned: - Environment facts (OS, tools, project structure) - Project conventions and configuration - Tool quirks and workarounds discovered - Completed task diary entries - Skills and techniques that worked ### `user` — User Profile For information about the user's identity, preferences, and communication style: - Name, role, timezone - Communication preferences (concise vs detailed, format preferences) - Pet peeves and things to avoid - Workflow habits - Technical skill level ## What to Save vs Skip ### Save These (Proactively) The agent saves automatically — you don't need to ask. It saves when it learns: - **User preferences:** "I prefer TypeScript over JavaScript" → save to `user` - **Environment facts:** "This server runs Debian 12 with PostgreSQL 16" → save to `memory` - **Corrections:** "Don't use `sudo` for Docker commands, user is in docker group" → save to `memory` - **Conventions:** "Project uses tabs, 120-char line width, Google-style docstrings" → save to `memory` - **Completed work:** "Migrated database from MySQL to PostgreSQL on 2026-01-15" → save to `memory` - **Explicit requests:** "Remember that my API key rotation happens monthly" → save to `memory` ### Skip These - **Trivial/obvious info:** "User asked about Python" — too vague to be useful - **Easily re-discovered facts:** "Python 3.12 supports f-string nesting" — can web search this - **Raw data dumps:** Large code blocks, log files, data tables — too big for memory - **Session-specific ephemera:** Temporary file paths, one-off debugging context - **Information already in context files:** SOUL.md and AGENTS.md content ## Capacity Management Memory has strict character limits to keep system prompts bounded: | Store | Limit | Typical entries | |-------|-------|----------------| | memory | 2,200 chars | 8-15 entries | | user | 1,375 chars | 5-10 entries | ### What Happens When Memory is Full When you try to add an entry that would exceed the limit, the tool returns an error: ```json { "success": false, "error": "Memory at 2,100/2,200 chars. Adding this entry (250 chars) would exceed the limit. Consolidate now: use 'replace' to merge overlapping entries into shorter ones or 'remove' stale or less important entries (see current_entries below), then retry this add — all in this turn.", "current_entries": ["..."], "usage": "2,100/2,200" } ``` The agent should then: 1. Read the current entries (shown in the error response) 2. Identify entries that can be removed or consolidated 3. Use `replace` to merge related entries into shorter versions 4. Then `add` the new entry **Best practice:** When memory is above 80% capacity (visible in the system prompt header), consolidate entries before adding new ones. For example, merge three separate "project uses X" entries into one comprehensive project description entry. ### Practical Examples of Good Memory Entries **Compact, information-dense entries work best:** ``` # Good: Packs multiple related facts User runs macOS 14 Sonoma, uses Homebrew, has Docker Desktop and Podman. Shell: zsh with oh-my-zsh. Editor: VS Code with Vim keybindings. # Good: Specific, actionable convention Project ~/code/api uses Go 1.22, sqlc for DB queries, chi router. Run tests with 'make test'. CI via GitHub Actions. # Good: Lesson learned with context The staging server (10.0.1.50) needs SSH port 2222, not 22. Key is at ~/.ssh/staging_ed25519. # Bad: Too vague User has a project. # Bad: Too verbose On January 5th, 2026, the user asked me to look at their project which is located at ~/code/api. I discovered it uses Go version 1.22 and... ``` ## Duplicate Prevention The memory system automatically rejects exact duplicate entries. If you try to add content that already exists, it returns success with a "no duplicate added" message. ## Security Scanning Memory entries are scanned for injection and exfiltration patterns before being accepted, since they're injected into the system prompt. Content matching threat patterns (prompt injection, credential exfiltration, SSH backdoors) or containing invisible Unicode characters is blocked. ## Session Search Beyond MEMORY.md and USER.md, the agent can search its past conversations using the `session_search` tool: - All CLI and messaging sessions are stored in SQLite (`~/.hermes/state.db`) with FTS5 full-text search - Search queries return actual messages from the DB — no LLM summarization, no truncation - The agent can find things it discussed weeks ago, even if they're not in its active memory - The agent can also scroll forward/backward inside any session it finds ```bash hermes sessions list # Browse past sessions ``` See [Session Search Tool](/user-guide/sessions#session-search-tool) for the three calling shapes (discovery / scroll / browse) and the response format. ### session_search vs memory | Feature | Persistent Memory | Session Search | |---------|------------------|----------------| | **Capacity** | ~1,300 tokens total | Unlimited (all sessions) | | **Speed** | Instant (in system prompt) | ~20ms FTS5 query, ~1ms scroll | | **Cost** | Token cost in every prompt | Free — no LLM calls | | **Use case** | Key facts always available | Finding specific past conversations | | **Management** | Manually curated by agent | Automatic — all sessions stored | | **Token cost** | Fixed per session (~1,300 tokens) | On-demand (searched when needed) | **Memory** is for critical facts that should always be in context. **Session search** is for "did we discuss X last week?" queries where the agent needs to recall specifics from past conversations. ## Configuration ```yaml # In ~/.hermes/config.yaml memory: memory_enabled: true user_profile_enabled: true memory_char_limit: 2200 # ~800 tokens user_char_limit: 1375 # ~500 tokens write_approval: false # false = write freely (default) | true = require approval ``` ## Controlling memory writes (`write_approval`) By default the agent saves memory freely — including from the background self-improvement review that runs after a turn. If you'd rather approve saves first, set `memory.write_approval: true`. It's a simple on/off gate applied to **both** foreground turns and the background review: | `write_approval` | Behaviour | |------------------|-----------| | `false` (default) | Write freely — the gate is off (the pre-gate behaviour). | | `true` | Require approval before anything is saved. In the interactive CLI, foreground writes prompt you inline (entries are small enough to read in full). Everywhere else — messaging platforms, scripts, and the background self-improvement review — writes are **staged** for review with `/memory pending`. | > To turn memory off entirely (not just gate it), set `memory_enabled: false`. Review staged writes from the CLI or any messaging platform: ``` /memory pending # list staged memory writes (auto ones tagged [auto]) /memory approve # apply one (or 'all') /memory reject # drop one (or 'all') /memory approval on # turn the gate on (or 'off') and persist it ``` This is the answer to "the agent saved a wrong assumption about me": set `write_approval: true`, and every save — especially the unprompted background ones — waits for your yes/no before it ever enters your profile. ## Background review notifications (`display.memory_notifications`) After a turn, the background self-improvement review may quietly save a memory or update a skill. By default it surfaces a short `💾 Memory updated` line in chat so you know it happened. Control how chatty that is: ```yaml display: memory_notifications: on # off | on (default) | verbose ``` | Value | Behaviour | |-------|-----------| | `off` | No chat notification. The review still runs and still writes — you just don't see a line for it. | | `on` (default) | Generic line, e.g. `💾 Memory updated`, `💾 Skill 'foo' patched`. | | `verbose` | Includes a compact preview of what changed, e.g. `💾 Memory ➕ User prefers terse replies` or a `"old" → "new"` skill diff snippet. | > This only governs the **gateway** chat notification. The review itself, and > writes to your memory/skill stores, are unaffected by this setting. Set it > per-platform via `display.platforms..memory_notifications`. ## Controlling skill writes (`skills.write_approval`) Skills use the same on/off gate, but the review UX differs because a `SKILL.md` is far too large to read in a chat bubble: ```yaml skills: write_approval: false # false = write freely (default) | true = require approval ``` When `write_approval: true`, skill writes (create / edit / patch / write_file / delete) always **stage** regardless of origin. You review the one-line gist inline, but the full diff stays out-of-band: ``` /skills pending # list staged skill writes + a one-line gist each /skills diff # full unified diff (best viewed in CLI or dashboard) /skills approve # apply it (or 'all') /skills reject # drop it (or 'all') /skills approval on # turn the gate on (or 'off') and persist it ``` On a messaging platform, approve a skill from its gist + metadata, or open `/skills diff` on the CLI / dashboard / the staged file under `~/.hermes/pending/skills/.json` when you want to read the whole change. Full details in [Gating agent skill writes](/user-guide/features/skills#gating-agent-skill-writes-skillswrite_approval). ## External Memory Providers For deeper, persistent memory that goes beyond MEMORY.md and USER.md, Hermes ships with 8 external memory provider plugins — including Honcho, OpenViking, Mem0, Hindsight, Holographic, RetainDB, ByteRover, and Supermemory. External providers run **alongside** built-in memory (never replacing it) and add capabilities like knowledge graphs, semantic search, automatic fact extraction, and cross-session user modeling. ```bash hermes memory setup # pick a provider and configure it hermes memory status # check what's active ``` See the [Memory Providers](/docs/user-guide/features/memory-providers) guide for full details on each provider, setup instructions, and comparison. --- --- ## Memory Providers Section: Core Features · URL: https://hermesbible.com/docs/user-guide/features/memory-providers Hermes Agent ships with 8 external memory provider plugins that give the agent persistent, cross-session knowledge beyond the built-in MEMORY.md and USER.md. Only **one** external provider can be active at a time — the built-in memory is always active alongside it. ## Quick Start ```bash hermes memory setup # interactive picker + configuration hermes memory status # check what's active hermes memory off # disable external provider ``` You can also select the active memory provider via `hermes plugins` → Provider Plugins → Memory Provider. Or set manually in `~/.hermes/config.yaml`: ```yaml memory: provider: openviking # or honcho, mem0, hindsight, holographic, retaindb, byterover, supermemory ``` ## How It Works When a memory provider is active, Hermes automatically: 1. **Injects provider context** into the system prompt (what the provider knows) 2. **Prefetches relevant memories** before each turn (background, non-blocking) 3. **Syncs conversation turns** to the provider after each response 4. **Extracts memories on session end** (for providers that support it) 5. **Mirrors built-in memory writes** to the external provider 6. **Adds provider-specific tools** so the agent can search, store, and manage memories The built-in memory (MEMORY.md / USER.md) continues to work exactly as before. The external provider is additive. ## Available Providers ### Honcho AI-native cross-session user modeling with dialectic reasoning, session-scoped context injection, semantic search, and persistent conclusions. Base context now includes the session summary alongside user representation and peer cards, giving the agent awareness of what has already been discussed. | | | |---|---| | **Best for** | Multi-agent systems with cross-session context, user-agent alignment | | **Requires** | `pip install honcho-ai` + [API key](https://app.honcho.dev) or self-hosted instance | | **Data storage** | Honcho Cloud or self-hosted | | **Cost** | Honcho pricing (cloud) / free (self-hosted) | **Tools (5):** `honcho_profile` (read/update peer card), `honcho_search` (semantic search), `honcho_context` (session context — summary, representation, card, messages), `honcho_reasoning` (LLM-synthesized), `honcho_conclude` (create/delete conclusions) **Architecture:** Two-layer context injection — a base layer (session summary + representation + peer card, refreshed on `contextCadence`) plus a dialectic supplement (LLM reasoning, refreshed on `dialecticCadence`). The dialectic automatically selects cold-start prompts (general user facts) vs. warm prompts (session-scoped context) based on whether base context exists. **Three orthogonal config knobs** control cost and depth independently: - `contextCadence` — how often the base layer refreshes (API call frequency) - `dialecticCadence` — how often the dialectic LLM fires (LLM call frequency) - `dialecticDepth` — how many `.chat()` passes per dialectic invocation (1–3, depth of reasoning) **Setup Wizard:** ```bash hermes memory setup # select "honcho" — runs the Honcho-specific post-setup ``` The legacy `hermes honcho setup` command still works (it now redirects to `hermes memory setup`), but is only registered after Honcho is selected as the active memory provider. **Config:** `$HERMES_HOME/honcho.json` (profile-local) or `~/.honcho/config.json` (global). Resolution order: `$HERMES_HOME/honcho.json` > `~/.hermes/honcho.json` > `~/.honcho/config.json`. See the [config reference](https://github.com/NousResearch/hermes-agent/blob/main/plugins/memory/honcho/README.md) and the [Honcho integration guide](https://docs.honcho.dev/v3/guides/integrations/hermes).
Full config reference | Key | Default | Description | |-----|---------|-------------| | `apiKey` | -- | API key from [app.honcho.dev](https://app.honcho.dev) | | `baseUrl` | -- | Base URL for self-hosted Honcho | | `peerName` | -- | User peer identity | | `aiPeer` | host key | AI peer identity (one per profile) | | `workspace` | host key | Shared workspace ID | | `contextTokens` | `null` (uncapped) | Token budget for auto-injected context per turn. Truncates at word boundaries | | `contextCadence` | `1` | Minimum turns between `context()` API calls (base layer refresh) | | `dialecticCadence` | `2` | Minimum turns between `peer.chat()` LLM calls. Recommended 1–5. Only applies to `hybrid`/`context` modes | | `dialecticDepth` | `1` | Number of `.chat()` passes per dialectic invocation. Clamped 1–3. Pass 0: cold/warm prompt, pass 1: self-audit, pass 2: reconciliation | | `dialecticDepthLevels` | `null` | Optional array of reasoning levels per pass, e.g. `["minimal", "low", "medium"]`. Overrides proportional defaults | | `dialecticReasoningLevel` | `'low'` | Base reasoning level: `minimal`, `low`, `medium`, `high`, `max` | | `dialecticDynamic` | `true` | When `true`, model can override reasoning level per-call via tool param | | `dialecticMaxChars` | `600` | Max chars of dialectic result injected into system prompt | | `recallMode` | `'hybrid'` | `hybrid` (auto-inject + tools), `context` (inject only), `tools` (tools only) | | `writeFrequency` | `'async'` | When to flush messages: `async` (background thread), `turn` (sync), `session` (batch on end), or integer N | | `saveMessages` | `true` | Whether to persist messages to Honcho API | | `observationMode` | `'directional'` | `directional` (all on) or `unified` (shared pool). Override with `observation` object | | `messageMaxChars` | `25000` | Max chars per message (chunked if exceeded) | | `dialecticMaxInputChars` | `10000` | Max chars for dialectic query input to `peer.chat()` | | `sessionStrategy` | `'per-directory'` | `per-directory`, `per-repo`, `per-session`, `global` | | `pinUserPeer` | `false` | Gateway only. When `true`, every non-agent gateway user collapses to `peerName`; the pin overrides all aliases | | `userPeerAliases` | `{}` | Gateway only. Maps runtime IDs to peers (`{"7654321": "alice"}`). Many-to-one | | `runtimePeerPrefix` | `""` | Gateway only. Namespaces unknown runtime IDs (`telegram_7654321`) when no alias matches |
Minimal honcho.json (cloud) ```json { "apiKey": "your-key-from-app.honcho.dev", "hosts": { "hermes": { "enabled": true, "aiPeer": "hermes", "peerName": "your-name", "workspace": "hermes" } } } ```
Minimal honcho.json (self-hosted) ```json { "baseUrl": "http://localhost:8000", "hosts": { "hermes": { "enabled": true, "aiPeer": "hermes", "peerName": "your-name", "workspace": "hermes" } } } ```
> **TIP — Migrating from `hermes honcho`** > > If you previously used `hermes honcho setup`, your config and all server-side data are intact. Just re-enable through the setup wizard again or manually set `memory.provider: honcho` to reactivate via the new system. **Multi-peer setup:** Honcho models conversations as peers exchanging messages — one user peer plus one AI peer per Hermes profile, all sharing a workspace. The workspace is the shared environment: the user peer is global across profiles, each AI peer is its own identity. Every AI peer builds an independent representation / card from its own observations, so a `coder` profile stays code-oriented while a `writer` profile stays editorial against the same user. The mapping: | Concept | What it is | |---------|-----------| | **Workspace** | Shared environment. All Hermes profiles under one workspace see the same user identity. | | **User peer** (`peerName`) | The human. Shared across profiles in the workspace. | | **AI peer** (`aiPeer`) | One per Hermes profile. Host key `hermes` → default; `hermes.` for others. | | **Observation** | Per-peer toggles controlling what Honcho models from whose messages. `directional` (default, all four on) or `unified` (single-observer pool). | ### New profile, fresh Honcho peer ```bash hermes profile create coder --clone ``` `--clone` creates a `hermes.coder` host block in `honcho.json` with `aiPeer: "coder"`, shared `workspace`, inherited `peerName`, `recallMode`, `writeFrequency`, `observation`, etc. The AI peer is eagerly created in Honcho so it exists before the first message. ### Existing profiles, backfill Honcho peers ```bash hermes honcho sync ``` Scans every Hermes profile, creates host blocks for any profile without one, inherits settings from the default `hermes` block, and creates the new AI peers eagerly. Idempotent — skips profiles that already have a host block. ### Per-profile observation Each host block can override the observation config independently. Example: a code-focused profile where the AI peer observes the user but doesn't self-model: ```json "hermes.coder": { "aiPeer": "coder", "observation": { "user": { "observeMe": true, "observeOthers": true }, "ai": { "observeMe": false, "observeOthers": true } } } ``` **Observation toggles (one set per peer):** | Toggle | Effect | |--------|--------| | `observeMe` | Honcho builds a representation of this peer from its own messages | | `observeOthers` | This peer observes the other peer's messages (feeds cross-peer reasoning) | Presets via `observationMode`: - **`"directional"`** (default) — all four flags on. Full mutual observation; enables cross-peer dialectic. - **`"unified"`** — user `observeMe: true`, AI `observeOthers: true`, rest false. Single-observer pool; AI models the user but not itself, user peer only self-models. Server-side toggles set via the [Honcho dashboard](https://app.honcho.dev) win over local defaults — synced back at session init. See the [Honcho page](/docs/user-guide/features/honcho#observation-directional-vs-unified) for the full observation reference. ### Gateway identity mapping The peer model above covers CLI, TUI, and desktop sessions, where every conversation resolves to `peerName`. The [gateway](/docs/developer-guide/gateway-internals) adds a second axis: users arrive with platform-native runtime IDs (Telegram UID, Discord snowflake, Slack user), and three keys decide which peer each ID resolves to. | Key | Effect | |-----|--------| | `pinUserPeer: true` | Every non-agent gateway user collapses to `peerName`. The pin is checked first, so it overrides all aliases — pick it only when no user-side identity needs its own peer | | `userPeerAliases` | Maps specific runtime IDs to peers (`{"7654321": "alice"}`). The home for routing distinct identities — including agents that each carry their own peer | | `runtimePeerPrefix` | Namespaces any unmapped runtime ID (`telegram_7654321`) so platforms with same-shaped IDs don't collide | Off-gateway these keys do nothing. `hermes memory setup` only prompts for them when it detects a connected gateway platform. See the [Honcho page](/docs/user-guide/features/honcho#gateway-identity-mapping) for the resolver ladder and the setup flow.
Full honcho.json example (multi-profile) ```json { "apiKey": "your-key", "workspace": "hermes", "peerName": "eri", "hosts": { "hermes": { "enabled": true, "aiPeer": "hermes", "workspace": "hermes", "peerName": "eri", "recallMode": "hybrid", "writeFrequency": "async", "sessionStrategy": "per-directory", "observation": { "user": { "observeMe": true, "observeOthers": true }, "ai": { "observeMe": true, "observeOthers": true } }, "dialecticReasoningLevel": "low", "dialecticDynamic": true, "dialecticCadence": 2, "dialecticDepth": 1, "dialecticMaxChars": 600, "contextCadence": 1, "messageMaxChars": 25000, "saveMessages": true }, "hermes.coder": { "enabled": true, "aiPeer": "coder", "workspace": "hermes", "peerName": "eri", "recallMode": "tools", "observation": { "user": { "observeMe": true, "observeOthers": false }, "ai": { "observeMe": true, "observeOthers": true } } }, "hermes.writer": { "enabled": true, "aiPeer": "writer", "workspace": "hermes", "peerName": "eri" } }, "sessions": { "/home/user/myproject": "myproject-main" } } ```
See the [config reference](https://github.com/NousResearch/hermes-agent/blob/main/plugins/memory/honcho/README.md) and [Honcho integration guide](https://docs.honcho.dev/v3/guides/integrations/hermes). --- ### OpenViking Context database by Volcengine (ByteDance) with filesystem-style knowledge hierarchy, tiered retrieval, and automatic memory extraction into 6 categories. | | | |---|---| | **Best for** | Self-hosted knowledge management with structured browsing | | **Requires** | `pip install openviking` + running server | | **Data storage** | Self-hosted (local or cloud) | | **Cost** | Free (open-source, AGPL-3.0) | **Tools:** `viking_search` (semantic search), `viking_read` (tiered: abstract/overview/full), `viking_browse` (filesystem navigation), `viking_remember` (store facts), `viking_add_resource` (ingest URLs/docs) **Setup:** ```bash # Start the OpenViking server first pip install openviking openviking-server # Then configure Hermes hermes memory setup # select "openviking" # Or manually: hermes config set memory.provider openviking echo "OPENVIKING_ENDPOINT=http://localhost:1933" >> ~/.hermes/.env ``` **Key features:** - Tiered context loading: L0 (~100 tokens) → L1 (~2k) → L2 (full) - Automatic memory extraction on session commit (profile, preferences, entities, events, cases, patterns) - `viking://` URI scheme for hierarchical knowledge browsing --- ### Mem0 Server-side LLM fact extraction with semantic search, reranking, and automatic deduplication. | | | |---|---| | **Best for** | Hands-off memory management — Mem0 handles extraction automatically | | **Requires** | `pip install mem0ai` + API key | | **Data storage** | Mem0 Cloud | | **Cost** | Mem0 pricing | **Tools:** `mem0_profile` (all stored memories), `mem0_search` (semantic search + reranking), `mem0_conclude` (store verbatim facts) **Setup:** ```bash hermes memory setup # select "mem0" # Or manually: hermes config set memory.provider mem0 echo "MEM0_API_KEY=your-key" >> ~/.hermes/.env ``` **Config:** `$HERMES_HOME/mem0.json` | Key | Default | Description | |-----|---------|-------------| | `user_id` | `hermes-user` | User identifier | | `agent_id` | `hermes` | Agent identifier | --- ### Hindsight Long-term memory with knowledge graph, entity resolution, and multi-strategy retrieval. The `hindsight_reflect` tool provides cross-memory synthesis that no other provider offers. Automatically retains full conversation turns (including tool calls) with session-level document tracking. | | | |---|---| | **Best for** | Knowledge graph-based recall with entity relationships | | **Requires** | Cloud: API key from [ui.hindsight.vectorize.io](https://ui.hindsight.vectorize.io). Local: LLM API key (OpenAI, Groq, OpenRouter, etc.) | | **Data storage** | Hindsight Cloud or local embedded PostgreSQL | | **Cost** | Hindsight pricing (cloud) or free (local) | **Tools:** `hindsight_retain` (store with entity extraction), `hindsight_recall` (multi-strategy search), `hindsight_reflect` (cross-memory synthesis) **Setup:** ```bash hermes memory setup # select "hindsight" # Or manually: hermes config set memory.provider hindsight echo "HINDSIGHT_API_KEY=your-key" >> ~/.hermes/.env ``` The setup wizard installs dependencies automatically and only installs what's needed for the selected mode (`hindsight-client` for cloud, `hindsight-all` for local). Requires `hindsight-client >= 0.4.22` (auto-upgraded on session start if outdated). **Local mode UI:** `hindsight-embed -p hermes ui start` **Config:** `$HERMES_HOME/hindsight/config.json` | Key | Default | Description | |-----|---------|-------------| | `mode` | `cloud` | `cloud` or `local` | | `bank_id` | `hermes` | Memory bank identifier | | `recall_budget` | `mid` | Recall thoroughness: `low` / `mid` / `high` | | `memory_mode` | `hybrid` | `hybrid` (context + tools), `context` (auto-inject only), `tools` (tools only) | | `auto_retain` | `true` | Automatically retain conversation turns | | `auto_recall` | `true` | Automatically recall memories before each turn | | `retain_async` | `true` | Process retain asynchronously on the server | | `retain_context` | `conversation between Hermes Agent and the User` | Context label for retained memories | | `retain_tags` | — | Default tags applied to retained memories; merged with per-call tool tags | | `retain_source` | — | Optional `metadata.source` attached to retained memories | | `retain_user_prefix` | `User` | Label used before user turns in auto-retained transcripts | | `retain_assistant_prefix` | `Assistant` | Label used before assistant turns in auto-retained transcripts | | `recall_tags` | — | Tags to filter on recall | See [plugin README](https://github.com/NousResearch/hermes-agent/blob/main/plugins/memory/hindsight/README.md) for the full configuration reference. --- ### Holographic Local SQLite fact store with FTS5 full-text search, trust scoring, and HRR (Holographic Reduced Representations) for compositional algebraic queries. | | | |---|---| | **Best for** | Local-only memory with advanced retrieval, no external dependencies | | **Requires** | Nothing (SQLite is always available). NumPy optional for HRR algebra. | | **Data storage** | Local SQLite | | **Cost** | Free | **Tools:** `fact_store` (9 actions: add, search, probe, related, reason, contradict, update, remove, list), `fact_feedback` (helpful/unhelpful rating that trains trust scores) **Setup:** ```bash hermes memory setup # select "holographic" # Or manually: hermes config set memory.provider holographic ``` **Config:** `config.yaml` under `plugins.hermes-memory-store` | Key | Default | Description | |-----|---------|-------------| | `db_path` | `$HERMES_HOME/memory_store.db` | SQLite database path | | `auto_extract` | `false` | Auto-extract facts at session end | | `default_trust` | `0.5` | Default trust score (0.0–1.0) | **Unique capabilities:** - `probe` — entity-specific algebraic recall (all facts about a person/thing) - `reason` — compositional AND queries across multiple entities - `contradict` — automated detection of conflicting facts - Trust scoring with asymmetric feedback (+0.05 helpful / -0.10 unhelpful) --- ### RetainDB Cloud memory API with hybrid search (Vector + BM25 + Reranking), 7 memory types, and delta compression. | | | |---|---| | **Best for** | Teams already using RetainDB's infrastructure | | **Requires** | RetainDB account + API key | | **Data storage** | RetainDB Cloud | | **Cost** | $20/month | **Tools:** `retaindb_profile` (user profile), `retaindb_search` (semantic search), `retaindb_context` (task-relevant context), `retaindb_remember` (store with type + importance), `retaindb_forget` (delete memories) **Setup:** ```bash hermes memory setup # select "retaindb" # Or manually: hermes config set memory.provider retaindb echo "RETAINDB_API_KEY=your-key" >> ~/.hermes/.env ``` --- ### ByteRover Persistent memory via the `brv` CLI — hierarchical knowledge tree with tiered retrieval (fuzzy text → LLM-driven search). Local-first with optional cloud sync. | | | |---|---| | **Best for** | Developers who want portable, local-first memory with a CLI | | **Requires** | ByteRover CLI (`npm install -g byterover-cli` or [install script](https://byterover.dev)) | | **Data storage** | Local (default) or ByteRover Cloud (optional sync) | | **Cost** | Free (local) or ByteRover pricing (cloud) | **Tools:** `brv_query` (search knowledge tree), `brv_curate` (store facts/decisions/patterns), `brv_status` (CLI version + tree stats) **Setup:** ```bash # Install the CLI first curl -fsSL https://byterover.dev/install.sh | sh # Then configure Hermes hermes memory setup # select "byterover" # Or manually: hermes config set memory.provider byterover ``` **Key features:** - Automatic pre-compression extraction (saves insights before context compression discards them) - Knowledge tree stored at `$HERMES_HOME/byterover/` (profile-scoped) - SOC2 Type II certified cloud sync (optional) --- ### Supermemory Semantic long-term memory with profile recall, semantic search, explicit memory tools, and session-end conversation ingest via the Supermemory graph API. | | | |---|---| | **Best for** | Semantic recall with user profiling and session-level graph building | | **Requires** | `pip install supermemory` + [API key](https://supermemory.ai) | | **Data storage** | Supermemory Cloud | | **Cost** | Supermemory pricing | **Tools:** `supermemory_store` (save explicit memories), `supermemory_search` (semantic similarity search), `supermemory_forget` (forget by ID or best-match query), `supermemory_profile` (persistent profile + recent context) **Setup:** ```bash hermes memory setup # select "supermemory" # Or manually: hermes config set memory.provider supermemory echo 'SUPERMEMORY_API_KEY=***' >> ~/.hermes/.env ``` **Config:** `$HERMES_HOME/supermemory.json` | Key | Default | Description | |-----|---------|-------------| | `container_tag` | `hermes` | Container tag used for search and writes. Supports `{identity}` template for profile-scoped tags. | | `auto_recall` | `true` | Inject relevant memory context before turns | | `auto_capture` | `true` | Store cleaned user-assistant turns after each response | | `max_recall_results` | `10` | Max recalled items to format into context | | `profile_frequency` | `50` | Include profile facts on first turn and every N turns | | `capture_mode` | `all` | Skip tiny or trivial turns by default | | `search_mode` | `hybrid` | Search mode: `hybrid`, `memories`, or `documents` | | `api_timeout` | `5.0` | Timeout for SDK and ingest requests | **Environment variables:** `SUPERMEMORY_API_KEY` (required), `SUPERMEMORY_CONTAINER_TAG` (overrides config). **Key features:** - Automatic context fencing — strips recalled memories from captured turns to prevent recursive memory pollution - Full-session ingest — the entire conversation is sent once at session boundaries - Session-end conversation ingest (to `/v4/conversations`) for richer profile + graph building in Supermemory - Profile facts injected on first turn and at configurable intervals - **Profile-scoped containers** — use `{identity}` in `container_tag` (e.g. `hermes-{identity}` → `hermes-coder`) to isolate memories per Hermes profile - **Multi-container mode** — enable `enable_custom_container_tags` with a `custom_containers` list to let the agent read/write across named containers. Automatic operations stay on the primary container.
Multi-container example ```json { "container_tag": "hermes", "enable_custom_container_tags": true, "custom_containers": ["project-alpha", "shared-knowledge"], "custom_container_instructions": "Use project-alpha for coding context." } ```
**Support:** [Discord](https://supermemory.link/discord) · [support@supermemory.com](mailto:support@supermemory.com) ### Memori Structured long-term memory using Memori Cloud, with background completed-turn capture, tool-aware turn context, and explicit recall tools for facts, summaries, quota, signup, and feedback. | | | |---|---| | **Best for** | Agent-controlled recall with structured project and session attribution | | **Requires** | `pip install hermes-memori` + `hermes-memori install` + [Memori API key](https://app.memorilabs.ai/signup) | | **Data storage** | Memori Cloud | | **Cost** | Memori pricing | **Tools:** `memori_recall` (search long-term memory), `memori_recall_summary` (summarized context), `memori_quota` (usage/quota), `memori_signup` (request signup email), `memori_feedback` (send integration feedback) **Setup:** ```bash pip install hermes-memori hermes-memori install hermes config set memory.provider memori hermes memory setup ``` --- ## Provider Comparison | Provider | Storage | Cost | Tools | Dependencies | Unique Feature | |----------|---------|------|-------|-------------|----------------| | **Honcho** | Cloud | Paid | 5 | `honcho-ai` | Dialectic user modeling + session-scoped context | | **OpenViking** | Self-hosted | Free | 5 | `openviking` + server | Filesystem hierarchy + tiered loading | | **Mem0** | Cloud | Paid | 3 | `mem0ai` | Server-side LLM extraction | | **Hindsight** | Cloud/Local | Free/Paid | 3 | `hindsight-client` | Knowledge graph + reflect synthesis | | **Holographic** | Local | Free | 2 | None | HRR algebra + trust scoring | | **RetainDB** | Cloud | $20/mo | 5 | `requests` | Delta compression | | **ByteRover** | Local/Cloud | Free/Paid | 3 | `brv` CLI | Pre-compression extraction | | **Supermemory** | Cloud | Paid | 4 | `supermemory` | Context fencing + session graph ingest + multi-container | | **Memori** | Cloud | Free/Paid | 5 | `hermes-memori` | Tool-aware memory + structured recall | ## Profile Isolation Each provider's data is isolated per [profile](/user-guide/profiles): - **Local storage providers** (Holographic, ByteRover) use `$HERMES_HOME/` paths which differ per profile - **Config file providers** (Honcho, Mem0, Hindsight, Supermemory) store config in `$HERMES_HOME/` so each profile has its own credentials - **Cloud providers** (RetainDB) auto-derive profile-scoped project names - **Env var providers** (OpenViking) are configured via each profile's `.env` file ## Building a Memory Provider See the [Developer Guide: Memory Provider Plugins](/developer-guide/memory-provider-plugin) for how to create your own. --- --- ## Context Files Section: Core Features · URL: https://hermesbible.com/docs/user-guide/features/context-files Hermes Agent automatically discovers and loads context files that shape how it behaves. Some are project-local and discovered from your working directory. `SOUL.md` is now global to the Hermes instance and is loaded from `HERMES_HOME` only. ## Supported Context Files | File | Purpose | Discovery | |------|---------|-----------| | **.hermes.md** / **HERMES.md** | Project instructions (highest priority) | Walks to git root | | **AGENTS.md** | Project instructions, conventions, architecture | CWD at startup + subdirectories progressively | | **CLAUDE.md** | Claude Code context files (also detected) | CWD at startup + subdirectories progressively | | **SOUL.md** | Global personality and tone customization for this Hermes instance | `HERMES_HOME/SOUL.md` only | | **.cursorrules** | Cursor IDE coding conventions | CWD only | | **.cursor/rules/*.mdc** | Cursor IDE rule modules | CWD only | > **INFO — Priority system** > > Only **one** project context type is loaded per session (first match wins): `.hermes.md` → `AGENTS.md` → `CLAUDE.md` → `.cursorrules`. **SOUL.md** is always loaded independently as the agent identity (slot #1). ## AGENTS.md `AGENTS.md` is the primary project context file. It tells the agent how your project is structured, what conventions to follow, and any special instructions. ### Progressive Subdirectory Discovery At session start, Hermes loads the `AGENTS.md` from your working directory into the system prompt. As the agent navigates into subdirectories during the session (via `read_file`, `terminal`, `search_files`, etc.), it **progressively discovers** context files in those directories and injects them into the conversation at the moment they become relevant. ``` my-project/ ├── AGENTS.md ← Loaded at startup (system prompt) ├── frontend/ │ └── AGENTS.md ← Discovered when agent reads frontend/ files ├── backend/ │ └── AGENTS.md ← Discovered when agent reads backend/ files └── shared/ └── AGENTS.md ← Discovered when agent reads shared/ files ``` This approach has two advantages over loading everything at startup: - **No system prompt bloat** — subdirectory hints only appear when needed - **Prompt cache preservation** — the system prompt stays stable across turns Each subdirectory is checked at most once per session. The discovery also walks up parent directories, so reading `backend/src/main.py` will discover `backend/AGENTS.md` even if `backend/src/` has no context file of its own. > **INFO** > > Subdirectory context files go through the same [security scan](#security-prompt-injection-protection) as startup context files. Malicious files are blocked. ### Example AGENTS.md ```markdown # Project Context This is a Next.js 14 web application with a Python FastAPI backend. ## Architecture - Frontend: Next.js 14 with App Router in `/frontend` - Backend: FastAPI in `/backend`, uses SQLAlchemy ORM - Database: PostgreSQL 16 - Deployment: Docker Compose on a Hetzner VPS ## Conventions - Use TypeScript strict mode for all frontend code - Python code follows PEP 8, use type hints everywhere - All API endpoints return JSON with `{data, error, meta}` shape - Tests go in `__tests__/` directories (frontend) or `tests/` (backend) ## Important Notes - Never modify migration files directly — use Alembic commands - The `.env.local` file has real API keys, don't commit it - Frontend port is 3000, backend is 8000, DB is 5432 ``` ## SOUL.md `SOUL.md` controls the agent's personality, tone, and communication style. See the [Personality](/user-guide/features/personality) page for full details. **Location:** - `~/.hermes/SOUL.md` - or `$HERMES_HOME/SOUL.md` if you run Hermes with a custom home directory Important details: - Hermes seeds a default `SOUL.md` automatically if one does not exist yet - Hermes loads `SOUL.md` only from `HERMES_HOME` - Hermes does not probe the working directory for `SOUL.md` - If the file is empty, nothing from `SOUL.md` is added to the prompt - If the file has content, the content is injected verbatim after scanning and truncation ## .cursorrules Hermes is compatible with Cursor IDE's `.cursorrules` file and `.cursor/rules/*.mdc` rule modules. If these files exist in your project root and no higher-priority context file (`.hermes.md`, `AGENTS.md`, or `CLAUDE.md`) is found, they're loaded as the project context. This means your existing Cursor conventions automatically apply when using Hermes. ## How Context Files Are Loaded ### At startup (system prompt) Context files are loaded by `build_context_files_prompt()` in `agent/prompt_builder.py`: 1. **Scan working directory** — checks for `.hermes.md` → `AGENTS.md` → `CLAUDE.md` → `.cursorrules` (first match wins) 2. **Content is read** — each file is read as UTF-8 text 3. **Security scan** — content is checked for prompt injection patterns 4. **Truncation** — files exceeding `context_file_max_chars` characters (default 20,000) are head/tail truncated (70% head, 20% tail, with a marker in the middle) 5. **Assembly** — all sections are combined under a `# Project Context` header 6. **Injection** — the assembled content is added to the system prompt ### During the session (progressive discovery) `SubdirectoryHintTracker` in `agent/subdirectory_hints.py` watches tool call arguments for file paths: 1. **Path extraction** — after each tool call, file paths are extracted from arguments (`path`, `workdir`, shell commands) 2. **Ancestor walk** — the directory and up to 5 parent directories are checked (stopping at already-visited directories) 3. **Hint loading** — if an `AGENTS.md`, `CLAUDE.md`, or `.cursorrules` is found, it's loaded (first match per directory) 4. **Security scan** — same prompt injection scan as startup files 5. **Truncation** — capped at 8,000 characters per file 6. **Injection** — appended to the tool result, so the model sees it in context naturally The final prompt section looks roughly like: ```text # Project Context The following project context files have been loaded and should be followed: ## AGENTS.md [Your AGENTS.md content here] ## .cursorrules [Your .cursorrules content here] [Your SOUL.md content here] ``` Notice that SOUL content is inserted directly, without extra wrapper text. ## Security: Prompt Injection Protection All context files are scanned for potential prompt injection before being included. The scanner checks for: - **Instruction override attempts**: "ignore previous instructions", "disregard your rules" - **Deception patterns**: "do not tell the user" - **System prompt overrides**: "system prompt override" - **Hidden HTML comments**: `` - **Hidden div elements**: `
` - **Credential exfiltration**: `curl ... $API_KEY` - **Secret file access**: `cat .env`, `cat credentials` - **Invisible characters**: zero-width spaces, bidirectional overrides, word joiners If any threat pattern is detected, the file is blocked: ``` [BLOCKED: AGENTS.md contained potential prompt injection (prompt_injection). Content not loaded.] ``` > **WARNING** > > This scanner protects against common injection patterns, but it's not a substitute for reviewing context files in shared repositories. Always validate AGENTS.md content in projects you didn't author. ## Size Limits | Limit | Value | |-------|-------| | Max chars per file | `context_file_max_chars` (default 20,000, ~7,000 tokens) | | Head truncation ratio | 70% | | Tail truncation ratio | 20% | | Truncation marker | 10% (shows char counts and suggests using file tools) | When a file exceeds the configured limit, the truncation message reads: ``` [...truncated AGENTS.md: kept 14000+4000 of 25000 chars. Use file tools to read the full file.] ``` ## Tips for Effective Context Files > **TIP — Best practices for AGENTS.md** > > 1. **Keep it concise** — stay under your configured `context_file_max_chars`; the agent reads it every turn > 2. **Structure with headers** — use `##` sections for architecture, conventions, important notes > 3. **Include concrete examples** — show preferred code patterns, API shapes, naming conventions > 4. **Mention what NOT to do** — "never modify migration files directly" > 5. **List key paths and ports** — the agent uses these for terminal commands > 6. **Update as the project evolves** — stale context is worse than no context ### Per-Subdirectory Context For monorepos, put subdirectory-specific instructions in nested AGENTS.md files: ```markdown # Frontend Context - Use `pnpm` not `npm` for package management - Components go in `src/components/`, pages in `src/app/` - Use Tailwind CSS, never inline styles - Run tests with `pnpm test` ``` ```markdown # Backend Context - Use `poetry` for dependency management - Run the dev server with `poetry run uvicorn main:app --reload` - All endpoints need OpenAPI docstrings - Database models are in `models/`, schemas in `schemas/` ``` --- --- ## Context References Section: Core Features · URL: https://hermesbible.com/docs/user-guide/features/context-references Type `@` followed by a reference to inject content directly into your message. Hermes expands the reference inline and appends the content under an `--- Attached Context ---` section. ## Supported References | Syntax | Description | |--------|-------------| | `@file:path/to/file.py` | Inject file contents | | `@file:path/to/file.py:10-25` | Inject specific line range (1-indexed, inclusive) | | `@folder:path/to/dir` | Inject directory tree listing with file metadata | | `@diff` | Inject `git diff` (unstaged working tree changes) | | `@staged` | Inject `git diff --staged` (staged changes) | | `@git:5` | Inject last N commits with patches (max 10) | | `@url:https://example.com` | Fetch and inject web page content | ## Usage Examples ```text Review @file:src/main.py and suggest improvements What changed? @diff Compare @file:old_config.yaml and @file:new_config.yaml What's in @folder:src/components? Summarize this article @url:https://arxiv.org/abs/2301.00001 ``` Multiple references work in a single message: ```text Check @file:main.py, and also @file:test.py. ``` Trailing punctuation (`,`, `.`, `;`, `!`, `?`) is automatically stripped from reference values. ## CLI Tab Completion In the interactive CLI, typing `@` triggers autocomplete: - `@` shows all reference types (`@diff`, `@staged`, `@file:`, `@folder:`, `@git:`, `@url:`) - `@file:` and `@folder:` trigger filesystem path completion with file size metadata - Bare `@` followed by partial text shows matching files and folders from the current directory ## Line Ranges The `@file:` reference supports line ranges for precise content injection: ```text @file:src/main.py:42 # Single line 42 @file:src/main.py:10-25 # Lines 10 through 25 (inclusive) ``` Lines are 1-indexed. Invalid ranges are silently ignored (full file is returned). ## Size Limits Context references are bounded to prevent overwhelming the model's context window: | Threshold | Value | Behavior | |-----------|-------|----------| | Soft limit | 25% of context length | Warning appended, expansion proceeds | | Hard limit | 50% of context length | Expansion refused, original message returned unchanged | | Folder entries | 200 files max | Excess entries replaced with `- ...` | | Git commits | 10 max | `@git:N` clamped to range [1, 10] | ## Security ### Sensitive Path Blocking These paths are always blocked from `@file:` references to prevent credential exposure: - SSH keys and config: `~/.ssh/id_rsa`, `~/.ssh/id_ed25519`, `~/.ssh/authorized_keys`, `~/.ssh/config` - Shell profiles: `~/.bashrc`, `~/.zshrc`, `~/.profile`, `~/.bash_profile`, `~/.zprofile` - Credential files: `~/.netrc`, `~/.pgpass`, `~/.npmrc`, `~/.pypirc` - Hermes env: `$HERMES_HOME/.env` These directories are fully blocked (any file inside): - `~/.ssh/`, `~/.aws/`, `~/.gnupg/`, `~/.kube/`, `$HERMES_HOME/skills/.hub/` ### Path Traversal Protection All paths are resolved relative to the working directory. References that resolve outside the allowed workspace root are rejected. ### Binary File Detection Binary files are detected via MIME type and null-byte scanning. Known text extensions (`.py`, `.md`, `.json`, `.yaml`, `.toml`, `.js`, `.ts`, etc.) bypass MIME-based detection. Binary files are rejected with a warning. ## Platform Availability Context references are primarily a **CLI feature**. They work in the interactive CLI where `@` triggers tab completion and references are expanded before the message is sent to the agent. In **messaging platforms** (Telegram, Discord, etc.), the `@` syntax is not expanded by the gateway — messages are passed through as-is. The agent itself can still reference files via the `read_file`, `search_files`, and `web_extract` tools. ## Interaction with Context Compression When conversation context is compressed, the expanded reference content is included in the compression summary. This means: - Large file contents injected via `@file:` contribute to context usage - If the conversation is later compressed, the file content is summarized (not preserved verbatim) - For very large files, consider using line ranges (`@file:main.py:100-200`) to inject only relevant sections ## Common Patterns ```text # Code review workflow Review @diff and check for security issues # Debug with context This test is failing. Here's the test @file:tests/test_auth.py and the implementation @file:src/auth.py:50-80 # Project exploration What does this project do? @folder:src @file:README.md # Research Compare the approaches in @url:https://arxiv.org/abs/2301.00001 and @url:https://arxiv.org/abs/2301.00002 ``` ## Error Handling Invalid references produce inline warnings rather than failures: | Condition | Behavior | |-----------|----------| | File not found | Warning: "file not found" | | Binary file | Warning: "binary files are not supported" | | Folder not found | Warning: "folder not found" | | Git command fails | Warning with git stderr | | URL returns no content | Warning: "no content extracted" | | Sensitive path | Warning: "path is a sensitive credential file" | | Path outside workspace | Warning: "path is outside the allowed workspace" | --- --- ## How SOUL.md works now Section: Core Features · URL: https://hermesbible.com/docs/user-guide/features/personality Hermes Agent's personality is fully customizable. `SOUL.md` is the **primary identity** — it's the first thing in the system prompt and defines who the agent is. - `SOUL.md` — a durable persona file that lives in `HERMES_HOME` and serves as the agent's identity (slot #1 in the system prompt) - built-in or custom `/personality` presets — session-level system-prompt overlays If you want to change who Hermes is — or replace it with an entirely different agent persona — edit `SOUL.md`. ## How SOUL.md works now Hermes now seeds a default `SOUL.md` automatically in: ```text ~/.hermes/SOUL.md ``` More precisely, it uses the current instance's `HERMES_HOME`, so if you run Hermes with a custom home directory, it will use: ```text $HERMES_HOME/SOUL.md ``` ### Important behavior - **SOUL.md is the agent's primary identity.** It occupies slot #1 in the system prompt, replacing the hardcoded default identity. - Hermes creates a starter `SOUL.md` automatically if one does not exist yet - Existing user `SOUL.md` files are never overwritten - Hermes loads `SOUL.md` only from `HERMES_HOME` - Hermes does not look in the current working directory for `SOUL.md` - If `SOUL.md` exists but is empty, or cannot be loaded, Hermes falls back to a built-in default identity - If `SOUL.md` has content, that content is injected verbatim after security scanning and truncation - SOUL.md is **not** duplicated in the context files section — it appears only once, as the identity That makes `SOUL.md` a true per-user or per-instance identity, not just an additive layer. ## Why this design This keeps personality predictable. If Hermes loaded `SOUL.md` from whatever directory you happened to launch it in, your personality could change unexpectedly between projects. By loading only from `HERMES_HOME`, the personality belongs to the Hermes instance itself. That also makes it easier to teach users: - "Edit `~/.hermes/SOUL.md` to change Hermes' default personality." ## Where to edit it For most users: ```bash ~/.hermes/SOUL.md ``` If you use a custom home: ```bash $HERMES_HOME/SOUL.md ``` ## What should go in SOUL.md? Use it for durable voice and personality guidance, such as: - tone - communication style - level of directness - default interaction style - what to avoid stylistically - how Hermes should handle uncertainty, disagreement, or ambiguity Use it less for: - one-off project instructions - file paths - repo conventions - temporary workflow details Those belong in `AGENTS.md`, not `SOUL.md`. ## Good SOUL.md content A good SOUL file is: - stable across contexts - broad enough to apply in many conversations - specific enough to materially shape the voice - focused on communication and identity, not task-specific instructions ### Example ```markdown # Personality You are a pragmatic senior engineer with strong taste. You optimize for truth, clarity, and usefulness over politeness theater. ## Style - Be direct without being cold - Prefer substance over filler - Push back when something is a bad idea - Admit uncertainty plainly - Keep explanations compact unless depth is useful ## What to avoid - Sycophancy - Hype language - Repeating the user's framing if it's wrong - Overexplaining obvious things ## Technical posture - Prefer simple systems over clever systems - Care about operational reality, not idealized architecture - Treat edge cases as part of the design, not cleanup ``` ## What Hermes injects into the prompt `SOUL.md` content goes directly into slot #1 of the system prompt — the agent identity position. No wrapper language is added around it. The content goes through: - prompt-injection scanning - truncation if it is too large If the file is empty, whitespace-only, or cannot be read, Hermes falls back to a built-in default identity ("You are Hermes Agent, an intelligent AI assistant created by Nous Research..."). This fallback also applies when `skip_context_files` is set (e.g., in subagent/delegation contexts). ## Security scanning `SOUL.md` is scanned like other context-bearing files for prompt injection patterns before inclusion. That means you should still keep it focused on persona/voice rather than trying to sneak in strange meta-instructions. ## SOUL.md vs AGENTS.md This is the most important distinction. ### SOUL.md Use for: - identity - tone - style - communication defaults - personality-level behavior ### AGENTS.md Use for: - project architecture - coding conventions - tool preferences - repo-specific workflows - commands, ports, paths, deployment notes A useful rule: - if it should follow you everywhere, it belongs in `SOUL.md` - if it belongs to a project, it belongs in `AGENTS.md` ## SOUL.md vs `/personality` `SOUL.md` is your durable default personality. `/personality` is a session-level overlay that changes or supplements the current system prompt. So: - `SOUL.md` = baseline voice - `/personality` = temporary mode switch Examples: - keep a pragmatic default SOUL, then use `/personality teacher` for a tutoring conversation - keep a concise SOUL, then use `/personality creative` for brainstorming ## Built-in personalities Hermes ships with built-in personalities you can switch to with `/personality`. | Name | Description | |------|-------------| | **helpful** | Friendly, general-purpose assistant | | **concise** | Brief, to-the-point responses | | **technical** | Detailed, accurate technical expert | | **creative** | Innovative, outside-the-box thinking | | **teacher** | Patient educator with clear examples | | **kawaii** | Cute expressions, sparkles, and enthusiasm ★ | | **catgirl** | Neko-chan with cat-like expressions, nya~ | | **pirate** | Captain Hermes, tech-savvy buccaneer | | **shakespeare** | Bardic prose with dramatic flair | | **surfer** | Totally chill bro vibes | | **noir** | Hard-boiled detective narration | | **uwu** | Maximum cute with uwu-speak | | **philosopher** | Deep contemplation on every query | | **hype** | MAXIMUM ENERGY AND ENTHUSIASM!!! | ## Switching personalities with commands ### CLI ```text /personality /personality concise /personality technical ``` ### Messaging platforms ```text /personality teacher ``` These are convenient overlays, but your global `SOUL.md` still gives Hermes its persistent default personality unless the overlay meaningfully changes it. ## Custom personalities in config You can also define named custom personalities in `~/.hermes/config.yaml` under `agent.personalities`. ```yaml agent: personalities: codereviewer: > You are a meticulous code reviewer. Identify bugs, security issues, performance concerns, and unclear design choices. Be precise and constructive. ``` Then switch to it with: ```text /personality codereviewer ``` ## Recommended workflow A strong default setup is: 1. Keep a thoughtful global `SOUL.md` in `~/.hermes/SOUL.md` 2. Put project instructions in `AGENTS.md` 3. Use `/personality` only when you want a temporary mode shift That gives you: - a stable voice - project-specific behavior where it belongs - temporary control when needed ## How personality interacts with the full prompt At a high level, the prompt stack includes: 1. **SOUL.md** (agent identity — or built-in fallback if SOUL.md is unavailable) 2. tool-aware behavior guidance 3. memory/user context 4. skills guidance 5. context files (`AGENTS.md`, `.cursorrules`) 6. timestamp 7. platform-specific formatting hints 8. optional system-prompt overlays such as `/personality` `SOUL.md` is the foundation — everything else builds on top of it. ## Related docs - [Context Files](/user-guide/features/context-files) - [Configuration](/user-guide/configuration) - [Tips & Best Practices](/guides/tips) - [SOUL.md Guide](/guides/use-soul-with-hermes) ## CLI appearance vs conversational personality Conversational personality and CLI appearance are separate: - `SOUL.md`, `agent.system_prompt`, and `/personality` affect how Hermes speaks - `display.skin` and `/skin` affect how Hermes looks in the terminal For terminal appearance, see [Skins & Themes](/docs/user-guide/features/skins). --- --- ## Plugins Section: Core Features · URL: https://hermesbible.com/docs/user-guide/features/plugins Hermes has a plugin system for adding custom tools, hooks, and integrations without modifying core code. If you want to create a custom tool for yourself, your team, or one project, this is usually the right path. The developer guide's [Adding Tools](/developer-guide/adding-tools) page is for built-in Hermes core tools that live in `tools/` and `toolsets.py`. **→ [Build a Hermes Plugin](/guides/build-a-hermes-plugin)** — step-by-step guide with a complete working example. ## Quick overview Drop a directory into `~/.hermes/plugins/` with a `plugin.yaml` and Python code: ``` ~/.hermes/plugins/my-plugin/ ├── plugin.yaml # manifest ├── __init__.py # register() — wires schemas to handlers ├── schemas.py # tool schemas (what the LLM sees) └── tools.py # tool handlers (what runs when called) ``` Start Hermes — your tools appear alongside built-in tools. The model can call them immediately. ### Minimal working example Here is a complete plugin that adds a `hello_world` tool and logs every tool call via a hook. **`~/.hermes/plugins/hello-world/plugin.yaml`** ```yaml name: hello-world version: "1.0" description: A minimal example plugin ``` **`~/.hermes/plugins/hello-world/__init__.py`** ```python """Minimal Hermes plugin — registers a tool and a hook.""" import json def register(ctx): # --- Tool: hello_world --- schema = { "name": "hello_world", "description": "Returns a friendly greeting for the given name.", "parameters": { "type": "object", "properties": { "name": { "type": "string", "description": "Name to greet", } }, "required": ["name"], }, } def handle_hello(params, **kwargs): del kwargs name = params.get("name", "World") return json.dumps({"success": True, "greeting": f"Hello, {name}!"}) ctx.register_tool( name="hello_world", toolset="hello_world", schema=schema, handler=handle_hello, description="Return a friendly greeting for the given name.", ) # --- Hook: log every tool call --- def on_tool_call(tool_name, params, result): print(f"[hello-world] tool called: {tool_name}") ctx.register_hook("post_tool_call", on_tool_call) ``` Drop both files into `~/.hermes/plugins/hello-world/`, restart Hermes, and the model can immediately call `hello_world`. The hook prints a log line after every tool invocation. Project-local plugins under `./.hermes/plugins/` are disabled by default. Enable them only for trusted repositories by setting `HERMES_ENABLE_PROJECT_PLUGINS=true` before starting Hermes. ## What plugins can do Every `ctx.*` API below is available inside a plugin's `register(ctx)` function. | Capability | How | |-----------|-----| | Add tools | `ctx.register_tool(name=..., toolset=..., schema=..., handler=...)` | | Add hooks | `ctx.register_hook("post_tool_call", callback)` | | Add slash commands | `ctx.register_command(name, handler, description)` — adds `/name` in CLI and gateway sessions | | Dispatch tools from commands | `ctx.dispatch_tool(name, args)` — invokes a registered tool with parent-agent context auto-wired | | Add CLI commands | `ctx.register_cli_command(name, help, setup_fn, handler_fn)` — adds `hermes ` | | Inject messages | `ctx.inject_message(content, role="user")` — see [Injecting Messages](#injecting-messages) | | Ship data files | `Path(__file__).parent / "data" / "file.yaml"` | | Bundle skills | `ctx.register_skill(name, path)` — namespaced as `plugin:skill`, loaded via `skill_view("plugin:skill")` | | Gate on env vars | `requires_env: [API_KEY]` in plugin.yaml — prompted during `hermes plugins install` | | Distribute via pip | `[project.entry-points."hermes_agent.plugins"]` | | Register a gateway platform (Discord, Telegram, IRC, …) | `ctx.register_platform(name, label, adapter_factory, check_fn, ...)` — see [Adding Platform Adapters](/developer-guide/adding-platform-adapters) | | Register an image-generation backend | `ctx.register_image_gen_provider(provider)` — see [Image Generation Provider Plugins](/developer-guide/image-gen-provider-plugin) | | Register a video-generation backend | `ctx.register_video_gen_provider(provider)` — see [Video Generation Provider Plugins](/developer-guide/video-gen-provider-plugin) | | Register a context-compression engine | `ctx.register_context_engine(engine)` — see [Context Engine Plugins](/developer-guide/context-engine-plugin) | | Register a memory backend | Subclass `MemoryProvider` in `plugins/memory//__init__.py` — see [Memory Provider Plugins](/developer-guide/memory-provider-plugin) (uses a separate discovery system) | | Run a host-owned LLM call | `ctx.llm.complete(...)` / `ctx.llm.complete_structured(...)` — borrow the user's active model + auth for a one-shot completion with optional JSON schema validation. See [Plugin LLM Access](/developer-guide/plugin-llm-access) | | Register an inference backend (LLM provider) | `register_provider(ProviderProfile(...))` in `plugins/model-providers//__init__.py` — see [Model Provider Plugins](/developer-guide/model-provider-plugin) (uses a separate discovery system) | ## Plugin discovery | Source | Path | Use case | |--------|------|----------| | Bundled | `/plugins/` | Ships with Hermes — see [Built-in Plugins](/user-guide/features/built-in-plugins) | | User | `~/.hermes/plugins/` | Personal plugins | | Project | `.hermes/plugins/` | Project-specific plugins (requires `HERMES_ENABLE_PROJECT_PLUGINS=true`) | | pip | `hermes_agent.plugins` entry_points | Distributed packages | | Nix | `services.hermes-agent.extraPlugins` / `extraPythonPackages` | NixOS declarative installs — see [Nix Setup](/getting-started/nix-setup#plugins) | Later sources override earlier ones on name collision, so a user plugin with the same name as a bundled plugin replaces it. ### Plugin sub-categories Within each source, Hermes also recognizes sub-category directories that route plugins to specialized discovery systems: | Sub-directory | What it holds | Discovery system | |---|---|---| | `plugins/` (root) | General plugins — tools, hooks, slash commands, CLI commands, bundled skills | `PluginManager` (kind: `standalone` or `backend`) | | `plugins/platforms//` | Gateway channel adapters (`ctx.register_platform()`) | `PluginManager` (kind: `platform`, one level deeper) | | `plugins/image_gen//` | Image-generation backends (`ctx.register_image_gen_provider()`) | `PluginManager` (kind: `backend`, one level deeper) | | `plugins/memory//` | Memory providers (subclass `MemoryProvider`) | **Own loader** in `plugins/memory/__init__.py` (kind: `exclusive` — one active at a time) | | `plugins/context_engine//` | Context-compression engines (`ctx.register_context_engine()`) | **Own loader** in `plugins/context_engine/__init__.py` (one active at a time) | | `plugins/model-providers//` | LLM provider profiles (`register_provider(ProviderProfile(...))`) | **Own loader** in `providers/__init__.py` (lazily scanned on first `get_provider_profile()` call) | User plugins at `~/.hermes/plugins/model-providers//` and `~/.hermes/plugins/memory//` override bundled plugins of the same name — last-writer-wins in `register_provider()` / `register_memory_provider()`. Drop a directory in, and it replaces the built-in without any repo edits. ## Plugins are opt-in (with a few exceptions) **General plugins and user-installed backends are disabled by default** — discovery finds them (so they show up in `hermes plugins` and `/plugins`), but nothing with hooks or tools loads until you add the plugin's name to `plugins.enabled` in `~/.hermes/config.yaml`. This stops third-party code from running without your explicit consent. ```yaml plugins: enabled: - my-tool-plugin - disk-cleanup disabled: # optional deny-list — always wins if a name appears in both - noisy-plugin ``` Three ways to flip state: ```bash hermes plugins # interactive toggle (space to check/uncheck) hermes plugins enable # add to allow-list hermes plugins disable # remove from allow-list + add to disabled ``` After `hermes plugins install owner/repo`, you're asked `Enable 'name' now? [y/N]` — defaults to no. Skip the prompt for scripted installs with `--enable` or `--no-enable`. ### What the allow-list does NOT gate Several categories of plugin bypass `plugins.enabled` — they're part of Hermes' built-in surface and would break basic functionality if gated off by default: | Plugin kind | How it's activated instead | |---|---| | **Bundled platform plugins** (IRC, Teams, etc. under `plugins/platforms/`) | Auto-loaded so every shipped gateway channel is available. The actual channel turns on via `gateway.platforms..enabled` in `config.yaml`. | | **Bundled backends** (image-gen providers under `plugins/image_gen/`, etc.) | Auto-loaded so the default backend "just works". Selection happens via `.provider` in `config.yaml` (e.g. `image_gen.provider: openai`). | | **Memory providers** (`plugins/memory/`) | All discovered; exactly one is active, chosen by `memory.provider` in `config.yaml`. | | **Context engines** (`plugins/context_engine/`) | All discovered; one is active, chosen by `context.engine` in `config.yaml`. | | **Model providers** (`plugins/model-providers/`) | All bundled providers under `plugins/model-providers/` discover and register at the first `get_provider_profile()` call. The user picks one at a time via `--provider` or `config.yaml`. | | **Pip-installed `backend` plugins** | Opt-in via `plugins.enabled` (same as general plugins). | | **User-installed platforms** (under `~/.hermes/plugins/platforms/`) | Opt-in via `plugins.enabled` — third-party gateway adapters need explicit consent. | In short: **bundled "always-works" infrastructure loads automatically; third-party general plugins are opt-in.** The `plugins.enabled` allow-list is the gate specifically for arbitrary code a user drops into `~/.hermes/plugins/`. ### Migration for existing users When you upgrade to a version of Hermes that has opt-in plugins (config schema v21+), any user plugins already installed under `~/.hermes/plugins/` that weren't already in `plugins.disabled` are **automatically grandfathered** into `plugins.enabled`. Your existing setup keeps working. Bundled standalone plugins are NOT grandfathered — even existing users have to opt in explicitly. (Bundled platform/backend plugins never needed grandfathering because they were never gated.) ## Available hooks Plugins can register callbacks for these lifecycle events. See the **[Event Hooks page](/user-guide/features/hooks#plugin-hooks)** for full details, callback signatures, and examples. | Hook | Fires when | |------|-----------| | [`pre_tool_call`](/user-guide/features/hooks#pre_tool_call) | Before any tool executes | | [`post_tool_call`](/user-guide/features/hooks#post_tool_call) | After any tool returns | | [`pre_llm_call`](/user-guide/features/hooks#pre_llm_call) | Once per turn, before the LLM loop — can return `{"context": "..."}` to [inject context into the user message](/user-guide/features/hooks#pre_llm_call) | | [`post_llm_call`](/user-guide/features/hooks#post_llm_call) | Once per turn, after the LLM loop (successful turns only) | | [`on_session_start`](/user-guide/features/hooks#on_session_start) | New session created (first turn only) | | [`on_session_end`](/user-guide/features/hooks#on_session_end) | End of every `run_conversation` call + CLI exit handler | | [`on_session_finalize`](/user-guide/features/hooks#on_session_finalize) | CLI/gateway tears down an active session (`/new`, GC, CLI quit) | | [`on_session_reset`](/user-guide/features/hooks#on_session_reset) | Gateway swaps in a new session key (`/new`, `/reset`, `/clear`, idle rotation) | | [`subagent_stop`](/user-guide/features/hooks#subagent_stop) | Once per child after `delegate_task` finishes | | [`pre_gateway_dispatch`](/user-guide/features/hooks#pre_gateway_dispatch) | Gateway received a user message, before auth + dispatch. Return `{"action": "skip" \| "rewrite" \| "allow", ...}` to influence flow. | ## Plugin types Hermes has four kinds of plugins: | Type | What it does | Selection | Location | |------|-------------|-----------|----------| | **General plugins** | Add tools, hooks, slash commands, CLI commands | Multi-select (enable/disable) | `~/.hermes/plugins/` | | **Memory providers** | Replace or augment built-in memory | Single-select (one active) | `plugins/memory/` | | **Context engines** | Replace the built-in context compressor | Single-select (one active) | `plugins/context_engine/` | | **Model providers** | Declare an inference backend (OpenRouter, Anthropic, …) | Multi-register, picked by `--provider` / `config.yaml` | `plugins/model-providers/` | Memory providers and context engines are **provider plugins** — only one of each type can be active at a time. Model providers are also plugins, but many load simultaneously; the user picks one at a time via `--provider` or `config.yaml`. General plugins can be enabled in any combination. ## Pluggable interfaces — where to go for each The table above shows the four plugin categories, but within "General plugins" the `PluginContext` exposes several distinct extension points — and Hermes also accepts extensions outside the Python plugin system (config-driven backends, shell-hooked commands, external servers, etc.). Use this table to find the right doc for what you want to build: | Want to add… | How | Authoring guide | |---|---|---| | A **tool** the LLM can call | Python plugin — `ctx.register_tool()` | [Build a Hermes Plugin](/guides/build-a-hermes-plugin) · [Adding Tools](/developer-guide/adding-tools) | | A **lifecycle hook** (pre/post LLM, session start/end, tool filter) | Python plugin — `ctx.register_hook()` | [Hooks reference](/user-guide/features/hooks) · [Build a Hermes Plugin](/guides/build-a-hermes-plugin) | | A **slash command** for the CLI / gateway | Python plugin — `ctx.register_command()` | [Build a Hermes Plugin](/guides/build-a-hermes-plugin) · [Extending the CLI](/developer-guide/extending-the-cli) | | A **subcommand** for `hermes ` | Python plugin — `ctx.register_cli_command()` | [Extending the CLI](/developer-guide/extending-the-cli) | | A bundled **skill** that your plugin ships | Python plugin — `ctx.register_skill()` | [Creating Skills](/developer-guide/creating-skills) | | An **inference backend** (LLM provider: OpenAI-compat, Codex, Anthropic-Messages, Bedrock) | Provider plugin — `register_provider(ProviderProfile(...))` in `plugins/model-providers//` | **[Model Provider Plugins](/developer-guide/model-provider-plugin)** · [Adding Providers](/developer-guide/adding-providers) | | A **gateway channel** (Discord / Telegram / IRC / Teams / etc.) | Platform plugin — `ctx.register_platform()` in `plugins/platforms//` | [Adding Platform Adapters](/developer-guide/adding-platform-adapters) | | A **memory backend** (Honcho, Mem0, Supermemory, …) | Memory plugin — subclass `MemoryProvider` in `plugins/memory//` | [Memory Provider Plugins](/developer-guide/memory-provider-plugin) | | A **context-compression strategy** | Context-engine plugin — `ctx.register_context_engine()` | [Context Engine Plugins](/developer-guide/context-engine-plugin) | | An **image-generation backend** (DALL·E, SDXL, …) | Backend plugin — `ctx.register_image_gen_provider()` | [Image Generation Provider Plugins](/developer-guide/image-gen-provider-plugin) | | A **video-generation backend** (Veo, Kling, Pixverse, Grok-Imagine, Runway, …) | Backend plugin — `ctx.register_video_gen_provider()` | [Video Generation Provider Plugins](/developer-guide/video-gen-provider-plugin) | | A **TTS backend** (any CLI — Piper, VoxCPM, Kokoro, xtts, voice-cloning scripts, …) | Config-driven (recommended) — declare under `tts.providers.` with `type: command` in `config.yaml`. OR Python backend plugin — `ctx.register_tts_provider()` for Python-SDK / streaming engines that need more than a shell template. | [TTS Setup](/user-guide/features/tts#custom-command-providers) · [Python plugin guide](/user-guide/features/tts#python-plugin-providers) | | An **STT backend** (any CLI — whisper.cpp, custom whisper binary, local ASR CLI) | Config-driven (recommended) — declare under `stt.providers.` with `type: command` in `config.yaml`, or set `HERMES_LOCAL_STT_COMMAND` for the legacy single-command escape hatch. OR Python backend plugin — `ctx.register_transcription_provider()` for Python-SDK engines (OpenRouter, SenseAudio, Gemini-STT, etc.). | [STT Setup](/user-guide/features/tts#stt-custom-command-providers) · [Python plugin guide](/user-guide/features/tts#python-plugin-providers-stt) | | **External tools via MCP** (filesystem, GitHub, Linear, Notion, any MCP server) | Config-driven — declare `mcp_servers.` with `command:` / `url:` in `config.yaml`. Hermes auto-discovers the server's tools and registers them alongside built-ins. | [MCP](/user-guide/features/mcp) | | **Additional skill sources** (custom GitHub repos, private skill indexes) | CLI — `hermes skills tap add ` | [Skills Hub](/user-guide/features/skills#skills-hub) · [Publishing a custom tap](/user-guide/features/skills#publishing-a-custom-skill-tap) | | **Gateway event hooks** (fire on `gateway:startup`, `session:start`, `agent:end`, `command:*`) | Drop `HOOK.yaml` + `handler.py` into `~/.hermes/hooks//` | [Event Hooks](/user-guide/features/hooks#gateway-event-hooks) | | **Shell hooks** (run a shell command on events — notifications, audit logs, desktop alerts) | Config-driven — declare under `hooks:` in `config.yaml` | [Shell Hooks](/user-guide/features/hooks#shell-hooks) | > **NOTE** > > Not everything is a Python plugin. Some extension surfaces intentionally use **config-driven shell commands** (TTS, STT, shell hooks) so any CLI you already have becomes a plugin without writing Python. Others are **external servers** (MCP) the agent connects to and auto-registers tools from. And some are **drop-in directories** (gateway hooks) with their own manifest format. Pick the right surface for the integration style that fits your use case; the authoring guides in the table above each cover placeholders, discovery, and examples. ## NixOS declarative plugins On NixOS, plugins can be installed declaratively via the module options — no `hermes plugins install` needed. See the **[Nix Setup guide](/getting-started/nix-setup#plugins)** for full details. ```nix services.hermes-agent = { # Directory plugin (source tree with plugin.yaml) extraPlugins = [ (pkgs.fetchFromGitHub { ... }) ]; # Entry-point plugin (pip package) extraPythonPackages = [ (pkgs.python312Packages.buildPythonPackage { ... }) ]; # Enable in config settings.plugins.enabled = [ "my-plugin" ]; }; ``` Declarative plugins are symlinked with a `nix-managed-` prefix — they coexist with manually installed plugins and are cleaned up automatically when removed from the Nix config. ## Managing plugins ```bash hermes plugins # unified interactive UI hermes plugins list # table: enabled / disabled / not enabled hermes plugins install user/repo # install from Git, then prompt Enable? [y/N] hermes plugins install user/repo --enable # install AND enable (no prompt) hermes plugins install user/repo --no-enable # install but leave disabled (no prompt) hermes plugins update my-plugin # pull latest hermes plugins remove my-plugin # uninstall hermes plugins enable my-plugin # add to allow-list hermes plugins disable my-plugin # remove from allow-list + add to disabled ``` ### Interactive UI Running `hermes plugins` with no arguments opens a composite interactive screen: ``` Plugins ↑↓ navigate SPACE toggle ENTER configure/confirm ESC done General Plugins → [✓] my-tool-plugin — Custom search tool [ ] webhook-notifier — Event hooks [ ] disk-cleanup — Auto-cleanup of ephemeral files [bundled] Provider Plugins Memory Provider ▸ honcho Context Engine ▸ compressor ``` - **General Plugins section** — checkboxes, toggle with SPACE. Checked = in `plugins.enabled`, unchecked = in `plugins.disabled` (explicit off). - **Provider Plugins section** — shows current selection. Press ENTER to drill into a radio picker where you choose one active provider. - Bundled plugins appear in the same list with a `[bundled]` tag. Provider plugin selections are saved to `config.yaml`: ```yaml memory: provider: "honcho" # empty string = built-in only context: engine: "compressor" # default built-in compressor ``` ### Enabled vs. disabled vs. neither Plugins occupy one of three states: | State | Meaning | In `plugins.enabled`? | In `plugins.disabled`? | |---|---|---|---| | `enabled` | Loaded on next session | Yes | No | | `disabled` | Explicitly off — won't load even if also in `enabled` | (irrelevant) | Yes | | `not enabled` | Discovered but never opted in | No | No | The default for a newly-installed or bundled plugin is `not enabled`. `hermes plugins list` shows all three distinct states so you can tell what's been explicitly turned off vs. what's just waiting to be enabled. In a running session, `/plugins` shows which plugins are currently loaded. ## Injecting Messages Plugins can inject messages into the active conversation using `ctx.inject_message()`: ```python ctx.inject_message("New data arrived from the webhook", role="user") ``` **Signature:** `ctx.inject_message(content: str, role: str = "user") -> bool` How it works: - If the agent is **idle** (waiting for user input), the message is queued as the next input and starts a new turn. - If the agent is **mid-turn** (actively running), the message interrupts the current operation — the same as a user typing a new message and pressing Enter. - For non-`"user"` roles, the content is prefixed with `[role]` (e.g. `[system] ...`). - Returns `True` if the message was queued successfully, `False` if no CLI reference is available (e.g. in gateway mode). This enables plugins like remote control viewers, messaging bridges, or webhook receivers to feed messages into the conversation from external sources. > **NOTE** > > `inject_message` is only available in CLI mode. In gateway mode, there is no CLI reference and the method returns `False`. See the **[full guide](/guides/build-a-hermes-plugin)** for handler contracts, schema format, hook behavior, error handling, and common mistakes. --- --- ## Built-in Plugins Section: Core Features · URL: https://hermesbible.com/docs/user-guide/features/built-in-plugins Hermes ships a small set of plugins bundled with the repository. They live under `/plugins//` and load automatically alongside user-installed plugins in `~/.hermes/plugins/`. They use the same plugin surface as third-party plugins — hooks, tools, slash commands — just maintained in-tree. See the [Plugins](/user-guide/features/plugins) page for the general plugin system, and [Build a Hermes Plugin](/guides/build-a-hermes-plugin) to write your own. ## How discovery works The `PluginManager` scans four sources, in order: 1. **Bundled** — `/plugins//` (what this page documents) 2. **User** — `~/.hermes/plugins//` 3. **Project** — `./.hermes/plugins//` (requires `HERMES_ENABLE_PROJECT_PLUGINS=1`) 4. **Pip entry points** — `hermes_agent.plugins` On name collision, later sources win — a user plugin named `disk-cleanup` would replace the bundled one. `plugins/memory/` and `plugins/context_engine/` are deliberately excluded from bundled scanning. Those directories use their own discovery paths because memory providers and context engines are single-select providers configured through `hermes memory setup` / `context.engine` in config. ## Bundled plugins are opt-in Bundled plugins ship disabled. Discovery finds them (they appear in `hermes plugins list` and the interactive `hermes plugins` UI), but none load until you explicitly enable them: ```bash hermes plugins enable disk-cleanup ``` Or via `~/.hermes/config.yaml`: ```yaml plugins: enabled: - disk-cleanup ``` This is the same mechanism user-installed plugins use. Bundled plugins are never auto-enabled — not on fresh install, not for existing users upgrading to a newer Hermes. You always opt in explicitly. To turn a bundled plugin off again: ```bash hermes plugins disable disk-cleanup # or: remove it from plugins.enabled in config.yaml ``` ## Currently shipped The repo ships these bundled plugins under `plugins/`. All are opt-in — enable them via `hermes plugins enable `. | Plugin | Kind | Purpose | |---|---|---| | `disk-cleanup` | hooks + slash command | Auto-track ephemeral files and clean them on session end | | `security-guidance` | hooks | Pattern-match dangerous code on `write_file`/`patch` and append a security warning (or block) — 25 rules (Apache-2.0 fork of Anthropic's `claude-plugins-official` patterns) | | `observability/langfuse` | hooks | Trace turns / LLM calls / tools to [Langfuse](https://langfuse.com) | | `observability/nemo_relay` | hooks | Relay observability events (turns / LLM calls / tools) to an NVIDIA NeMo endpoint | | `teams_pipeline` | standalone | Microsoft Teams meeting pipeline — Graph-backed, transcript-first meeting summaries | | `spotify` | backend (7 tools) | Native Spotify playback, queue, search, playlists, albums, library | | `google_meet` | standalone | Join Meet calls, live-caption transcription, optional realtime duplex audio | | `image_gen/openai` | image backend | OpenAI `gpt-image-2` image generation backend (alternative to FAL) | | `image_gen/openai-codex` | image backend | OpenAI image generation via Codex OAuth | | `image_gen/xai` | image backend | xAI `grok-2-image` backend | | `hermes-achievements` | dashboard tab | Steam-style collectible badges generated from your real Hermes session history | | `kanban/dashboard` | dashboard tab | Kanban board UI for the multi-agent dispatcher — tasks, comments, fan-out, board switching. See [Kanban Multi-Agent](/docs/user-guide/features/kanban). | Memory providers (`plugins/memory/*`) and context engines (`plugins/context_engine/*`) are listed separately on [Memory Providers](/docs/user-guide/features/memory-providers) — they're managed through `hermes memory` and `hermes plugins` respectively. The full per-plugin detail for the two long-running hooks-based plugins follows. ### disk-cleanup Auto-tracks and removes ephemeral files created during sessions — test scripts, temp outputs, cron logs, stale chrome profiles — without requiring the agent to remember to call a tool. **How it works:** | Hook | Behaviour | |---|---| | `post_tool_call` | When `write_file` / `terminal` / `patch` creates a file matching `test_*`, `tmp_*`, or `*.test.*` inside `HERMES_HOME` or `/tmp/hermes-*`, track it silently as `test` / `temp` / `cron-output`. | | `on_session_end` | If any test files were auto-tracked during the turn, run the safe `quick` cleanup and log a one-line summary. Stays silent otherwise. | **Deletion rules:** | Category | Threshold | Confirmation | |---|---|---| | `test` | every session end | Never | | `temp` | >7 days since tracked | Never | | `cron-output` | >14 days since tracked | Never | | empty dirs under HERMES_HOME | always | Never | | `research` | >30 days, beyond 10 newest | Always (deep only) | | `chrome-profile` | >14 days since tracked | Always (deep only) | | files >500 MB | never auto | Always (deep only) | **Slash command** — `/disk-cleanup` available in both CLI and gateway sessions: ``` /disk-cleanup status # breakdown + top-10 largest /disk-cleanup dry-run # preview without deleting /disk-cleanup quick # run safe cleanup now /disk-cleanup deep # quick + list items needing confirmation /disk-cleanup track # manual tracking /disk-cleanup forget # stop tracking (does not delete) ``` **State** — everything lives at `$HERMES_HOME/disk-cleanup/`: | File | Contents | |---|---| | `tracked.json` | Tracked paths with category, size, and timestamp | | `tracked.json.bak` | Atomic-write backup of the above | | `cleanup.log` | Append-only audit trail of every track / skip / reject / delete | **Safety** — cleanup only ever touches paths under `HERMES_HOME` or `/tmp/hermes-*`. Windows mounts (`/mnt/c/...`) are rejected. Well-known top-level state dirs (`logs/`, `memories/`, `sessions/`, `cron/`, `cache/`, `skills/`, `plugins/`, `disk-cleanup/` itself) are never removed even when empty — a fresh install does not get gutted on first session end. **Enabling:** `hermes plugins enable disk-cleanup` (or check the box in `hermes plugins`). **Disabling again:** `hermes plugins disable disk-cleanup`. ### security-guidance Fast pattern-matched security warnings on file writes. When the agent's `write_file` / `patch` / `skill_manage` calls carry content matching a known-dangerous code pattern — `pickle.load`, `yaml.load` without `SafeLoader`, `eval(`, `os.system`, `subprocess(..., shell=True)`, JS `child_process.exec`, React `dangerouslySetInnerHTML`, raw `.innerHTML =` / `.outerHTML =` / `document.write`, Node `crypto.createCipher`, AES ECB mode, TLS verification disabled, XXE-prone `xml.etree` / `minidom` parsers, `