Hermes Agent — Agent계의 명품인가? 직접 써보고 정리한 첫인상#
2026-04-19

들어가며#
요즘 주변에서 Hermes Agent 이야기를 자주 듣습니다. 그중에서도 같은 팀 동료에게서 직접 들은 운영 사례가 가장 인상적이었습니다. 그 동료는 Hermes를 회사 슬랙에 연결해 팀원들이 슬랙에서 @Hermes 한 줄로 데이터 조회, 작업 의뢰, QnA를 처리할 수 있는 환경을 이미 만들어두고 있었습니다. 필자도 바로 감을 잡아보고 싶어, 오늘 하루 동안 다음 세 가지를 한꺼번에 진행했습니다.
- Hermes Agent가 무엇이고 어떤 철학으로 만들어졌는지 조사
- 팀 동료가 사내 Pulumi 프로젝트에 배포해둔 Hermes 구성을 코드 레벨에서 분석
- 필자의 맥북에 직접 설치하고 슬랙까지 연결해보는 실습
이 글은 그 과정에서 정리한 개념과 인상을 기록한 것입니다. 결론을 미리 말씀드리면, Hermes는 단순한 코딩 도우미가 아니라 “서버에 띄워두고 어디서든 메시지로 부려먹을 수 있는, 학습하면서 성장하는 자율 에이전트” 라는 점에서 기존 도구들과는 결이 다릅니다. Cursor와 Claude Code를 일상적으로 쓰고 있는 필자에게도 새로운 성격의 도구로 다가왔습니다.
Hermes Agent란 무엇인가#
Hermes Agent는 Nous Research가 만든 오픈소스 자율 AI 에이전트입니다. Nous Research는 Hermes, Nomos, Psyche 같은 오픈소스 LLM(Large Language Model, 대규모 언어 모델)을 만들어 온 연구소이고, 같은 이름의 에이전트 프레임워크가 Hermes Agent입니다. MIT 라이선스로 GitHub에 공개되어 있습니다.
기존 코딩 도구들과 가장 다른 점은 두 가지입니다.
1. IDE에 묶여있지 않다#
Cursor나 Claude Code는 IDE 안에서 동작하는 코딩 코파일럿입니다. 사용자가 IDE를 열고 있어야 작동합니다. Hermes는 그 반대입니다. VPS · Docker · 서버리스(Modal, Daytona) 등 어디든 띄워두고, 외부에서 메시지로 호출하는 데몬형 에이전트입니다. $5짜리 VPS부터 GPU 클러스터까지 다 돌아갑니다. 슬랙, 텔레그램, 디스코드, 왓츠앱, 시그널, 이메일, 매트릭스, 페이수, 딩톡 등 15개 이상의 메시징 플랫폼을 단일 게이트웨이로 묶습니다.
2. 닫힌 학습 루프(Closed Learning Loop)#
단순히 LLM API 호출을 래핑한 챗봇이 아닙니다. 사용하면서 다음을 자동으로 축적합니다.
| 기능 | 설명 |
|---|---|
| Memory | 세션을 넘나드는 영속 메모리. FTS5(SQLite Full-Text Search) 기반 검색 + LLM 요약 |
| Skills | 작업 경험에서 스스로 절차적 스킬을 만들고, 사용 중에 자가 개선 |
| User Modeling | Honcho 기반의 사용자 모델링으로 “당신이 누구인지"를 점점 더 잘 알게 됨 |
쉽게 말해 “오늘 시킨 일이 내일 더 잘 되는” 구조입니다.
3. 풀 패키지#
추가로 47개의 빌트인 도구(웹 검색, 브라우저 자동화, 비전, 음성, 이미지 생성), MCP(Model Context Protocol) 서버 통합, 자연어 cron 스케줄러, 격리된 서브에이전트로 작업 병렬화, 6종의 터미널 백엔드(local, Docker, SSH, Daytona, Singularity, Modal)를 포함합니다. 모델은 OpenRouter(200+개), Anthropic, OpenAI, Nous Portal, 또는 임의의 OpenAI 호환 엔드포인트를 자유롭게 선택할 수 있습니다.
공식 문서: https://hermes-agent.nousresearch.com/docs/
팀에서 운영 중인 Hermes — 코드로 살펴보기#
팀 동료가 사내 Pulumi 프로젝트에 Hermes를 배포해두었습니다. 코드를 들여다보니 흥미로운 설계 결정들이 보입니다.
AWS Lightsail 한 대에 모두 올림#
회사는 EKS, Lambda, Fargate 등 대부분의 워크로드를 컨테이너 기반으로 운영하지만, Hermes만큼은 Lightsail 인스턴스 한 대 ($40 / 월) 에 올렸습니다. Pulumi가 만들어내는 리소스는 5개에 불과합니다.
| 리소스 | 용도 |
|---|---|
aws.lightsail.Instance (hermes-server) | Ubuntu 24.04, 2 vCPU, 8GB RAM |
aws.lightsail.KeyPair (hermes-key) | SSH 접속용 키페어 |
aws.lightsail.StaticIp (hermes-ip) | 재부팅해도 변하지 않는 고정 IP |
aws.lightsail.InstancePublicPorts (hermes-ports) | 22, 443만 오픈 |
aws.route53.Record (hermes-dns) | hermes.pulsead.io DNS 레코드 |
서버리스가 아닌 이유는 명확합니다. Hermes의 슬랙 게이트웨이는 Socket Mode 기반 WebSocket 지속 연결이 필요해서 항상 켜져 있어야 합니다. 람다나 Fargate 같은 단발성 환경과는 결이 안 맞습니다. 정액제, 단순 구성, 팀 공용 봇 한 대면 충분 — 이 세 조건이 맞아 떨어지는 곳이 Lightsail이었습니다.
인프라(Pulumi) + 부트스트랩(스크립트) + 운영 설정(템플릿)의 분업#
흥미로운 건 책임 분리입니다.
- Pulumi: AWS 리소스 5개만 책임
scripts/setup.sh: Docker, Node.js, Hermes 본체 설치 + systemd 서비스 등록hermes-config/config.yaml: 모델, 터미널 백엔드, MCP 서버, 도구 권한 등walnuts/: 회사 전사 컨텍스트 (LLM이 읽을 도메인 지식 디렉토리)SOUL.md: 에이전트의 페르소나와 행동 규칙
각 레이어가 독립적으로 변경 가능합니다. AWS 리소스가 바뀌면 pulumi up, 설정만 바뀌면 scp + systemctl restart 한 줄. 군더더기 없는 설계입니다.
Docker 샌드박스로 호스트를 보호#
서버 안에서 Hermes가 도구를 실행할 때는 Docker 컨테이너를 거칩니다. 팀원 25명이 슬랙에서 자유롭게 작업을 시켜도, 최악의 경우라도 Lightsail 호스트의 본체 파일시스템은 거의 안 다칩니다. 컨테이너에는 walnuts 디렉토리만 볼륨 마운트되어 있고, 호스트 환경변수도 GITHUB_TOKEN 한 개만 컨테이너로 전달합니다.
Walnuts + Wiki — 회사 지식의 그릇#
Hermes 본체는 “에이전트 엔진"이고, 회사 고유 지식은 Walnuts 디렉토리에 파일로 쌓입니다. _core/(운영 컨텍스트, cron으로 자동 갱신) + raw/(불변 소스) + wiki/(LLM이 자기 손으로 정리)의 3계층 구조입니다. Karpathy의 LLM Wiki 아이디어를 차용한 구성으로 보입니다. 회사가 쌓아온 도메인 지식을 Hermes가 매번 참조하면서, 동시에 자기 손으로 정리·확장해 나가는 구조입니다.
맥북에 설치하기 — 단계별 절차#
팀 구성을 분석한 뒤, 필자도 맥북에 비슷한 구성의 환경을 만들어보고 싶었습니다. 요구사항을 단순하게 잡았습니다.
- Docker로 샌드박싱. 단, 필요에 따라 맥북 로컬의 일부 폴더만 마운트
- 슬랙 연결. 팀 공용 봇이 아니라 개인용 별도 봇
전체 흐름은 6단계로 끝났습니다. 처음부터 끝까지 한 번에 정리해두면, 동일한 환경을 다시 만들 때 그대로 따라가면 됩니다.
1단계. 사전 준비 — Docker + LLM API 키#
먼저 Docker 데몬이 떠 있어야 합니다. 필자는 가벼운 OrbStack을 선호합니다.
brew install --cask orbstackLLM API 키는 최소 하나가 필요합니다. Anthropic 콘솔에서 sk-ant-...를 발급받거나, OpenRouter에서 다양한 모델을 한 번에 쓸 수 있는 sk-or-...을 발급받으면 됩니다.
마운트해서 작업시킬 로컬 폴더 경로도 미리 정해둡니다. 필자의 경우는 블로그 폴더와 그 상위 프로젝트 루트, 두 개입니다.
2단계. Hermes 설치#
공식 설치 스크립트 한 줄입니다.
curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash설치 후에는 PATH가 반영되도록 셸을 새로 띄워야 합니다. ~/.zshrc에 다음 줄을 한 번 추가해두면 영구 반영됩니다.
export PATH="$HOME/.local/bin:$PATH"이어서 대화식 초기 설정을 진행합니다.
hermes setup여기서 LLM provider, API 키, 기본 모델, 메시징 플랫폼(Slack 선택)을 차례대로 입력하면 ~/.hermes/config.yaml과 ~/.hermes/.env가 생성됩니다.
3단계. Docker 샌드박스 + 폴더 마운트 설정#
샌드박스 컨테이너 이미지를 미리 받아둡니다. 사내 Pulumi 배포판과 동일한 이미지입니다.
docker pull nikolaik/python-nodejs:python3.11-nodejs20~/.hermes/config.yaml의 terminal: 섹션을 열어 Docker 백엔드로 바꾸고, 마운트할 로컬 폴더를 명시적으로 선언합니다.
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_TOKENdocker_volumes의 형식은 호스트경로:컨테이너경로[:ro]이고, :ro를 붙이면 읽기 전용으로 잠깁니다. 마운트하지 않은 폴더는 컨테이너에서 아예 보이지 않습니다. 이게 샌드박스의 본체이자, 다음 섹션에서 따로 다룰 핵심 가치입니다.
Docker Desktop을 쓰는 경우 Settings → Resources → File sharing 목록에 /Users 경로가 포함되어 있는지 확인해야 합니다. OrbStack은 이 과정 자체가 필요 없습니다.
4단계. 새 Slack App 생성#
기존에 운영 중이던 Cursor / Claude Code용 Slack App은 그대로 두고, Hermes 전용 새 App을 따로 만드는 것을 강력히 권장합니다. 이유는 권한 분리, Rate limit 분리, Socket Mode와 기존 이벤트 구독 설정의 충돌 회피, 그리고 봇 이름 분리입니다.
순서는 다음과 같습니다.
- api.slack.com/apps → Create New App → From scratch → 이름은
Hermes Agent (개인 식별자) - OAuth & Permissions → Bot Token Scopes 박스(User Token Scopes 박스 아님)에 11개 추가:
chat:write,app_mentions:read,channels:history,channels:read,groups:history,im:history,im:read,im:write,users:read,files:read,files:write - Settings → Socket Mode → Enable → App-Level Token 발급 (이름
hermes-socket, scopeconnections:write) →xapp-...토큰 복사 - Event Subscriptions → Enable Events → Subscribe to bot events 에
app_mention,message.channels,message.groups,message.im추가 → Save - App Home → Show Tabs: Messages Tab ON + “Allow users to send Slash commands and messages” 체크 (이게 빠지면 DM이 안 됩니다)
- Settings → Install App → Install to Workspace →
xoxb-...Bot User OAuth Token 복사 - 본인의 Slack Member ID 복사 (프로필 더보기 → Copy member ID)
5단계. 토큰 주입 + 게이트웨이 실행#
~/.hermes/.env에 받은 토큰 두 개와 본인 Member ID를 넣습니다.
SLACK_BOT_TOKEN=<BOT_USER_OAUTH_TOKEN>
SLACK_APP_TOKEN=<APP_LEVEL_TOKEN>
SLACK_ALLOWED_USERS=<YOUR_MEMBER_ID>SLACK_ALLOWED_USERS에 본인 ID만 넣어두면, 다른 사람이 같은 봇에게 말 걸어도 무시됩니다. 파일 권한도 안전하게 잠가둡니다.
chmod 600 ~/.hermes/.env이제 게이트웨이를 띄웁니다.
hermes gateway로그에 Connected to Slack workspace ...가 뜨면 연결 완료입니다. 이 터미널은 봇이 살아있는 동안 닫지 말아야 합니다. 백그라운드로 돌리고 싶다면 hermes gateway install로 macOS LaunchAgent에 등록할 수 있고, 그러면 로그인할 때마다 자동으로 시작되고 크래시 시 자동 재시작됩니다.
6단계. 동작 확인#
Slack에서 테스트용 채널을 만들어 봇을 초대합니다.
/invite @Hermes Agent (개인 식별자)
@Hermes Agent (개인 식별자) 안녕, pwd 해봐스레드에 /workspace/ted-blog 같은 컨테이너 안 경로가 응답으로 오면 모든 게 정상 동작하는 상태입니다. DM에서는 멘션 없이 그냥 말을 걸어도 응답이 옵니다.
마주친 함정들#
설치 절차 자체는 위처럼 짧지만, 처음 부딪치면 헤매기 좋은 자잘한 함정이 몇 가지 있었습니다. 같은 환경을 만들려는 분들에게 도움이 될 것 같아 따로 모아둡니다.
함정 1. curl ... | bash 직후의 prompt_toolkit 에러#
설치 스크립트가 끝나자마자 자동으로 hermes TUI를 실행하는데, 이때 다음 에러가 발생했습니다.
File ".../prompt_toolkit/input/vt100.py", line 165, in _attached_input
loop.add_reader(fd, callback_wrapper)
OSError: [Errno 22] Invalid argument원인은 단순합니다. curl ... | bash 로 실행한 셸은 stdin이 파이프(curl의 출력)로 묶여 있어서 진짜 터미널이 아닙니다. TUI는 키보드 입력을 받기 위해 stdin이 TTY여야 하므로 실패합니다. 새 터미널 창을 열어서 hermes를 다시 실행하면 정상 동작합니다. 설치 자체는 100% 성공한 상태이고요.
함정 2. Slack app_mentions:read scope이 안 보임#
슬랙 앱 OAuth & Permissions 페이지에서 app_mentions:read를 찾는데 후보 목록에 안 떴습니다. 이유는 의외로 사소합니다. 그 페이지에는 박스가 두 개 있는데, app_mentions:read는 Bot Token Scopes 전용입니다. User Token Scopes 박스에서 검색하면 안 보입니다.
| 박스 | 토큰 종류 | 용도 |
|---|---|---|
| Bot Token Scopes | xoxb- (Bot User OAuth Token) | 봇 자체의 권한 |
| User Token Scopes | xoxp- (User OAuth Token) | 설치한 사용자의 권한을 봇이 대행 |
Hermes에 필요한 모든 scope은 Bot Token 쪽에만 추가합니다. User Token 쪽은 건드릴 필요가 없습니다.
함정 3. SLACK_BOT_TOKEN과 SLACK_APP_TOKEN의 차이#
Hermes의 .env에는 슬랙 토큰이 두 개 필요합니다. 처음에는 헷갈렸지만 정리하면 다음과 같습니다.
| 항목 | SLACK_BOT_TOKEN | SLACK_APP_TOKEN |
|---|---|---|
| 접두사 | xoxb- | xapp- |
| 발급 위치 | “Install to Workspace” 시 | “Socket Mode” 활성화 시 |
| 권한 기준 | Bot Token Scopes | App-Level Scopes (connections:write) |
| 용도 | Web API 호출 (메시지 전송, 파일 업로드 등) | Socket Mode WebSocket 연결 열기 |
| 비유 | 봇의 신분증 + 행동 권한 | Slack 서버로 전용 전화선을 여는 열쇠 |
Cursor나 Claude Code의 슬랙 MCP는 보통 Bot Token(또는 User Token) 하나만 씁니다. “필요할 때 API를 호출"하는 구조이기 때문입니다. 반면 Hermes는 이벤트 스트림을 실시간으로 받아서 스스로 판단·반응 하는 봇이라 Socket Mode가 필수이고, 따라서 두 토큰이 모두 필요합니다.
Docker 샌드박스의 진가#
설치 절차의 3단계에서 docker_volumes로 두 폴더만 마운트했던 의미를 한 번 더 짚고 넘어가고 싶습니다. 이게 의외로 큰 의미를 가지기 때문입니다.
Cursor나 Claude Code는 사용자의 홈 디렉토리 전체를 사실상 에이전트에게 내어주는 구조입니다. 내 ~/.ssh, ~/.aws, 각종 설정 파일이 모두 이론적으로 접근 가능합니다. 반면 위 설정은 필자가 명시한 두 폴더만 컨테이너에 노출하고, 나머지 호스트는 컨테이너 입장에서 존재하지도 않는 경로가 됩니다. 거기에 더해 한 폴더는 읽기 전용(:ro)으로 잠가둘 수도 있습니다.
확인용으로 슬랙에서 봇에게 마운트하지 않은 임의의 호스트 경로를 조회하게 해보니 “그런 디렉토리 없음” 응답이 옵니다. 정상입니다. 마운트 안 한 건 컨테이너에서 보이지 않는 게 맞습니다. 이게 샌드박스의 진짜 가치입니다. 에이전트의 행동 반경을 사용자가 정확히 통제할 수 있다는 것.
명품 같은 첫인상, 그리고 풀어야 할 숙제#
설치와 슬랙 연결을 마치고 봇과 첫 인사를 나누는 순간 — 의외의 문제가 기다리고 있었습니다. “안녕” 한 마디를 보냈는데 5분이 지나도 응답이 없는 겁니다. 잠시 후 다른 메시지를 보내자 그제서야 첫 메시지에 대한 응답이 슬랙에 전송됐습니다.
검색해보니 비슷한 패턴의 버그가 여러 건 등록되어 있습니다.
- #4469 — Multiple rapid messages only last one processed: 게이트웨이 내부에 메시지 큐가 두 군데 있는데(
GatewayRunner._pending_messages,adapter._pending_messages) 동기화가 안 됨 - #8221 — Telegram duplicate replies when interrupted session sends stale response before processing pending message: 인터럽트된 세션이 stale response를 먼저 내보냄
- #5057 — Message handling behavior when multiple messages arrive during active agent execution
이슈 #8221이 필자의 증상과 가장 비슷합니다. 다만 이게 정말 그 버그인지, 아니면 Docker 컨테이너 콜드 스타트가 hang된 것인지, 또는 Anthropic 스트리밍 응답이 종료 시그널을 못 받고 멈춘 것인지는 verbose 로그를 봐야 확정할 수 있습니다. 이 진단은 다음 세션으로 미뤘습니다.
부수적인 이슈도 하나 있었습니다. 밝은 색 터미널 배경을 쓰고 있는데 Hermes의 기본 스킨이 노랑 / 흰색 위주여서 텍스트가 잘 안 보였습니다. 이건 빌트인 스킨 두 개가 해결합니다.
/skin daylight # 어두운 텍스트 + 파란 액센트
/skin warm-lightmode # 따뜻한 갈색 / 금색 톤같은 문제가 공식 이슈로 등록되어 있을 만큼 알려진 사항이었습니다.
마치며 — Agent계의 명품인가?#
하루 동안 설치하고, 슬랙에 붙여 보고, 팀 운영 사례까지 따라가며 얻은 첫인상은 비교적 선명합니다. Hermes는 단순히 기능이 많은 도구라기보다, 에이전트를 어떻게 운영해야 하는지에 대한 관점이 분명한 도구에 가깝습니다. IDE 안에서 잠깐 쓰고 닫는 보조 도구가 아니라, 메시징 · 샌드박스 · 메모리 · 스킬을 한 흐름으로 묶어 장기적으로 굴리는 쪽에 더 어울립니다.
그래서 필자에게는 “명품"이라는 비유가 완전히 과장처럼 느껴지지는 않았습니다. 화려해서라기보다, 어디에 힘을 줬는지가 분명했기 때문입니다. Docker 샌드박스를 기본 전제로 두고, Slack 같은 메시징 채널을 자연스럽게 붙이고, 컨텍스트와 Memory를 축적해 장기적으로 더 잘 쓰이도록 설계한 점은 분명 인상적이었습니다. 사내 Pulumi 구성까지 함께 살펴보니, Hermes의 가치는 개별 기능보다도 운영 방식 전체를 하나의 시스템으로 묶는 데 있다는 생각이 들었습니다.
물론 지금 단계에서 단정적인 평가를 내리기는 이릅니다. 필자는 아직 하루 동안 설치하고 연결해본 수준이고, 응답 지연처럼 실제 운영에서 먼저 확인해야 할 문제도 남아 있습니다. 다만 짧게 써본 것만으로도, 이 도구가 Cursor나 Claude Code와는 다른 자리에 서 있으려 한다는 점은 분명히 느껴졌습니다. 그 도구들이 “지금 이 순간의 생산성"에 가깝다면, Hermes는 “계속 길러 가는 작업 환경” 쪽에 더 가까워 보였습니다.
당분간은 필자의 맥북에서 응답 지연 이슈를 먼저 진단해볼 생각입니다. 그 문제가 정리되면 팀 동료의 walnuts 구조를 참고해 필자만의 도메인 지식 그릇도 차근차근 만들어볼 계획입니다. 어느 정도 더 써본 뒤에는, 첫인상이 아니라 실제 운영 경험에 가까운 후속 글을 다시 정리해보고 싶습니다.