Hermes Agent — Is It the Luxury Brand of AI Agents? A First Impression#

2026-04-19

Hermes Agent — Is it the luxury brand of AI agents?

Introduction#

Lately I’ve been hearing a lot about Hermes Agent. The most compelling example came directly from a teammate. They told me they had already connected Hermes to our company Slack and built an environment where the team could handle data lookups, task requests, and Q&A with a simple @Hermes message. That was enough to make me want to understand it properly, so I spent a single day doing all three of the following:

  1. Researched what Hermes Agent is and what philosophy it was built on
  2. Analyzed, at the code level, the Hermes deployment my teammate had built into our internal Pulumi project
  3. Installed it on my own MacBook and connected it to Slack as a hands-on exercise

This essay is a record of the concepts and impressions I gathered along the way. To give the conclusion up front: Hermes is not just a coding assistant. It’s something different in kind — “a self-improving autonomous agent you park on a server and command from anywhere via messaging.” As someone who uses Cursor and Claude Code daily, I felt Hermes occupies a genuinely different niche.


What Is Hermes Agent?#

Hermes Agent is an open-source autonomous AI agent built by Nous Research. Nous Research is a lab known for open-source LLMs (Large Language Models) like Hermes, Nomos, and Psyche, and the agent framework that shares the name is Hermes Agent. It’s MIT-licensed and open-source on GitHub.

The two biggest differences from existing coding tools are:

1. Not Tied to an IDE#

Cursor and Claude Code are coding copilots that live inside an IDE. They only run while you have the IDE open. Hermes is the opposite. It’s a daemon-style agent you put on a VPS, in Docker, or on serverless infrastructure (Modal, Daytona) — and call from outside via messages. It runs on anything from a $5 VPS to a GPU cluster. A single gateway process bundles 15+ messaging platforms: Slack, Telegram, Discord, WhatsApp, Signal, Email, Matrix, Feishu, DingTalk, and more.

2. A Closed Learning Loop#

It’s not just a chatbot wrapping an LLM API. While you use it, it automatically accumulates the following:

CapabilityDescription
MemoryPersistent memory across sessions. FTS5 (SQLite Full-Text Search) based recall + LLM summarization
SkillsBuilds procedural skills from work experience and self-improves them during use
User ModelingHoncho-based user modeling that gradually deepens its understanding of who you are

In plain language: “the work you give it today gets done better tomorrow.”

3. The Full Package#

It also includes 47 built-in tools (web search, browser automation, vision, voice, image generation), MCP (Model Context Protocol) server integration, a natural-language cron scheduler, isolated subagents for parallelization, and 6 terminal backends (local, Docker, SSH, Daytona, Singularity, Modal). For models, you can freely choose OpenRouter (200+ models), Anthropic, OpenAI, Nous Portal, or any OpenAI-compatible endpoint.

Official docs: https://hermes-agent.nousresearch.com/docs/


Hermes Running In My Team — A Code-Level Look#

My teammate had deployed Hermes into our company’s internal Pulumi project. Reading the code, several interesting design decisions stood out.

Everything on One AWS Lightsail Instance#

The company runs most workloads on container-based services (EKS, Lambda, Fargate). But for Hermes, the choice was a single Lightsail instance ($40/month). Pulumi creates only 5 resources total.

ResourcePurpose
aws.lightsail.Instance (hermes-server)Ubuntu 24.04, 2 vCPU, 8GB RAM
aws.lightsail.KeyPair (hermes-key)SSH key pair
aws.lightsail.StaticIp (hermes-ip)Stable IP across reboots
aws.lightsail.InstancePublicPorts (hermes-ports)Only 22, 443 open
aws.route53.Record (hermes-dns)hermes.pulsead.io DNS record

The reason for not going serverless is clear. The Hermes Slack gateway needs a persistent WebSocket connection (Socket Mode), which means it has to be always-on. That doesn’t fit a Lambda or Fargate single-shot model. Flat fee, simple setup, one box for the whole team — those three conditions converged on Lightsail.

Separation: Infra (Pulumi) + Bootstrap (Script) + Runtime Config (Templates)#

What’s interesting is the separation of responsibilities:

  • Pulumi: Owns only the 5 AWS resources
  • scripts/setup.sh: Installs Docker, Node.js, Hermes itself + registers a systemd service
  • hermes-config/config.yaml: Model, terminal backend, MCP servers, tool permissions
  • walnuts/: Company-wide context (a directory of domain knowledge for the LLM to read)
  • SOUL.md: The agent’s persona and behavioral rules

Each layer can change independently. AWS resources change → pulumi up. Settings only change → scp + systemctl restart. Lean and tidy.

Docker Sandbox Protects the Host#

When Hermes runs commands on the server, those commands go through a Docker container. Even with 25 teammates issuing commands freely from Slack, in the worst case the Lightsail host’s filesystem stays largely untouched. Only the walnuts directory is volume-mounted into the container, and only one host environment variable (GITHUB_TOKEN) is forwarded.

Walnuts + Wiki — The Vessel for Company Knowledge#

Hermes itself is the “agent engine,” and company-specific knowledge lives in the Walnuts directory as files. The structure has three layers: _core/ (operational context, auto-refreshed by cron) + raw/ (immutable sources) + wiki/ (LLM-curated knowledge). It’s clearly inspired by Karpathy’s LLM Wiki idea. Hermes constantly reads the company’s accumulated domain knowledge while simultaneously curating and extending it.


Installing on My MacBook — Step by Step#

After dissecting the team’s setup, I wanted to build a similar structure on my MacBook. I kept the requirements simple:

  • Docker sandboxing. But with the ability to mount specific local folders when needed
  • Slack integration. Not the team bot — a separate personal one

The whole flow took 6 steps. Capturing it end-to-end here so the same environment is reproducible later.

Step 1. Prerequisites — Docker + LLM API Key#

You need a Docker daemon running. I prefer the lightweight OrbStack:

brew install --cask orbstack

You also need at least one LLM API key — either sk-ant-... from the Anthropic console or sk-or-... from OpenRouter (which gives you 200+ models in one place).

Pick the local folders you want to mount into the sandbox in advance. In my case, that’s the blog folder and its parent project root.

Step 2. Install Hermes#

The official installer is one line:

curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash

After install, open a fresh shell so PATH gets picked up. Add this to ~/.zshrc for permanence:

export PATH="$HOME/.local/bin:$PATH"

Then run the interactive initial setup:

hermes setup

It walks you through LLM provider, API key, default model, and messaging platform (choose Slack). At the end, ~/.hermes/config.yaml and ~/.hermes/.env are generated.

Step 3. Docker Sandbox + Folder Mount Configuration#

Pre-pull the container image — same one the company’s Pulumi deployment uses:

docker pull nikolaik/python-nodejs:python3.11-nodejs20

Open the terminal: section of ~/.hermes/config.yaml and switch to the Docker backend with explicit local folder mounts:

terminal:
  backend: docker
  docker_image: "nikolaik/python-nodejs:python3.11-nodejs20"
  container_cpu: 2
  container_memory: 4096
  container_persistent: true
  persistent_shell: true
  cwd: "/workspace"
  docker_volumes:
    - "/path/to/project-root:/workspace/project-root:ro"
  docker_forward_env:
    - GITHUB_TOKEN

The docker_volumes format is host_path:container_path[:ro], where :ro locks the folder as read-only. Anything you don’t mount is invisible to the container. That’s the heart of sandboxing — and the next section is dedicated to why this matters.

If you use Docker Desktop, check that Settings → Resources → File sharing includes /Users. OrbStack doesn’t need this step.

Step 4. Create a New Slack App#

Leave any existing Slack app you have for Cursor / Claude Code untouched. Create a brand new app dedicated to Hermes. Reasons: permission separation, separate rate limits, avoiding conflicts between Socket Mode and existing event subscriptions, and bot name separation.

Steps:

  1. Go to api.slack.com/appsCreate New AppFrom scratch → name it Hermes Agent (your identifier)
  2. OAuth & Permissions → Bot Token Scopes box (NOT User Token Scopes!) — add 11 scopes: chat:write, app_mentions:read, channels:history, channels:read, groups:history, im:history, im:read, im:write, users:read, files:read, files:write
  3. Settings → Socket Mode → Enable → generate an App-Level Token (name hermes-socket, scope connections:write) → copy the xapp-... token
  4. Event Subscriptions → Enable Events → Subscribe to bot events: add app_mention, message.channels, message.groups, message.im → Save
  5. App Home → Show Tabs: turn on Messages Tab + check “Allow users to send Slash commands and messages” (without this, DMs don’t work)
  6. Settings → Install App → Install to Workspace → copy the xoxb-... Bot User OAuth Token
  7. Copy your own Slack Member ID (profile → more menu → Copy member ID)

Step 5. Inject Tokens + Run the Gateway#

Add the two tokens and your Member ID to ~/.hermes/.env:

SLACK_BOT_TOKEN=<BOT_USER_OAUTH_TOKEN>
SLACK_APP_TOKEN=<APP_LEVEL_TOKEN>
SLACK_ALLOWED_USERS=<YOUR_MEMBER_ID>

With only your ID in SLACK_ALLOWED_USERS, the bot ignores anyone else. Lock the file permissions for safety:

chmod 600 ~/.hermes/.env

Now start the gateway:

hermes gateway

When the log shows Connected to Slack workspace ..., you’re connected. Keep this terminal open as long as you want the bot alive. To background it, hermes gateway install registers it as a macOS LaunchAgent that auto-starts on login and auto-restarts on crash.

Step 6. Verify#

In Slack, create a test channel and invite the bot:

/invite @Hermes Agent (your identifier)
@Hermes Agent (your identifier) hi, run pwd for me

If a thread reply comes back with a path like /workspace/ted-blog (the container path, not your host path), everything is working. In DMs, you don’t need to mention the bot — just talk.


The Pitfalls I Hit#

The setup itself is short, but a few small pitfalls are easy to trip on the first time. Collecting them here for anyone trying the same path.

Pitfall 1. The prompt_toolkit Error Right After curl ... | bash#

The install script tries to launch the hermes TUI immediately after install, which produces this error:

File ".../prompt_toolkit/input/vt100.py", line 165, in _attached_input
    loop.add_reader(fd, callback_wrapper)
OSError: [Errno 22] Invalid argument

The cause is simple. A shell launched via curl ... | bash has its stdin tied to a pipe (curl’s output), not a real TTY. The TUI requires stdin to be a real terminal to receive keyboard input, so it fails. Just open a fresh terminal and run hermes again — it works fine. The install itself was 100% successful.

Pitfall 2. The app_mentions:read Scope Doesn’t Show Up#

In the Slack app’s OAuth & Permissions page, I went looking for app_mentions:read and it wasn’t in the list. The reason is simple. That page has two boxes, and app_mentions:read is exclusive to the Bot Token Scopes box. It won’t appear if you search inside User Token Scopes.

BoxToken TypePurpose
Bot Token Scopesxoxb- (Bot User OAuth Token)The bot’s own permissions
User Token Scopesxoxp- (User OAuth Token)The bot acts on behalf of the installing user

All scopes Hermes needs go into the Bot Token side. You don’t need to touch User Token Scopes.

Pitfall 3. The Difference Between SLACK_BOT_TOKEN and SLACK_APP_TOKEN#

Hermes’s .env requires two Slack tokens. Confusing at first, but here’s the breakdown:

ItemSLACK_BOT_TOKENSLACK_APP_TOKEN
Prefixxoxb-xapp-
Issued When“Install to Workspace”“Socket Mode” enable
Permission BasisBot Token ScopesApp-Level Scopes (connections:write)
PurposeWeb API calls (send message, upload file, etc.)Open the Socket Mode WebSocket connection
AnalogyThe bot’s ID + action permissionsThe key that opens a private phone line to Slack

Cursor / Claude Code Slack MCPs typically use just one token (Bot or User). They follow a “call the API when needed” pattern. Hermes, in contrast, is a bot that receives the event stream in real time and reacts on its own, so Socket Mode is mandatory — and so both tokens are required.


The Real Value of the Docker Sandbox#

I want to revisit the meaning of mounting only two folders via docker_volumes in Step 3 of the install. It matters more than it looks.

Cursor and Claude Code essentially hand the agent your entire home directory. Your ~/.ssh, ~/.aws, every config file is theoretically reachable. The setup above, by contrast, exposes only the two folders you explicitly named to the container. The rest of the host doesn’t even exist from the container’s perspective. On top of that, you can lock one folder as read-only (:ro).

For verification I had the bot query an arbitrary host path that had not been mounted. The response was “no such directory.” Correct. Whatever you didn’t mount does not show up. This is the real value of a sandbox: the user can precisely control the agent’s blast radius.


A Luxury First Impression — and the Homework That Remains#

Right after finishing install + Slack connection, I exchanged my first hello with the bot — and an unexpected problem was waiting. I sent “hi,” waited 5 minutes, no response. A bit later I sent another message, and only then did the response to the first message land in Slack.

A search turned up several issues with similar patterns:

Issue #8221 most closely matches what I observed. Whether this is really that bug, or a Docker container cold-start hang, or the Anthropic streaming response failing to emit a completion signal — the only way to confirm is to read verbose logs. I deferred that diagnosis to a later session.

There was one secondary issue worth noting. I use a light-background terminal, and Hermes’s default skin uses yellow/white-heavy colors that were nearly unreadable. Two built-in skins solve this:

/skin daylight       # dark text + cool blue accents
/skin warm-lightmode # warm brown / gold tones

This same problem is even officially logged as an issue.


In Closing — Is It the Luxury Brand of AI Agents?#

After installing it, wiring it into Slack, and tracing through a real team deployment, my first impression became fairly clear. Hermes feels less like “a tool with a lot of features” and more like a tool built around a strong idea of how agents should be operated. It is not mainly about helping inside an IDE for a few minutes at a time. It is better understood as a longer-running system that ties messaging, sandboxing, memory, and skills into one workflow.

That is why the “luxury” comparison did not feel entirely exaggerated to me. Not because Hermes is flashy, but because its priorities are unusually clear. The Docker-first sandboxing model, the natural fit with messaging channels like Slack, and the idea that context and memory should accumulate over time all left a strong impression. Looking at the company’s Pulumi deployment reinforced that feeling. The value of Hermes seems to lie less in any single feature than in the way it turns agent operation itself into a coherent system.

It is still too early for me to make a definitive judgment. At this point I have only spent a day installing and connecting it, and there are still practical issues to investigate, such as the delayed-response behavior I saw locally. Even so, it already feels clear that Hermes is aiming at a different place from Cursor or Claude Code. If those tools are closer to “productivity right now,” Hermes feels closer to “an environment you keep cultivating over time.”

For now, my next step is to diagnose the response-delay issue on my MacBook. Once that is under control, I want to use my teammate’s walnuts structure as a reference and slowly build a domain knowledge container of my own. After spending more real time with it, I would like to come back with a follow-up piece based not just on first impressions, but on actual operating experience.


References#