FIF's 코딩팩토리

Java, Spring, Vue, React 로 개발하고 AI 에이전트를 실무에 붙여보면서 써본 기술을 정리하는 블로그.

AI

[AI] Hermes Agent 사용법 - 스스로 스킬을 만들고 기억하는 오픈소스 AI 에이전트, 학습 루프 뜯어보기

반응형

Nous Research 의 오픈소스 AI 에이전트 Hermes Agent 설치법과, 대화 중에 스스로 메모리와 스킬을 만들고 정리하는 학습 루프가 어떻게 돌아가는지에 대한 정리

 

 

Hermes Agent 란?

요즘 깃허브에서 스타가 제일 많은 AI 에이전트 레포다.

2026-10-30 에 GitHub API 로 보면 NousResearch/hermes-agent 가 스타 258,565 개, 최신 릴리스는 v0.22.5 (10-23) 다. 라이선스는 MIT.

Claude Code 나 Codex 처럼 터미널에서 대화하면서 파일 읽고, 명령 돌리고, 코드 고치는 에이전트인데 몇 가지가 다르다.

  • 모델을 안 가린다. OpenRouter, OpenAI, Anthropic, 직접 띄운 로컬 모델 등 hermes model 로 바꾼다
  • 노트북에만 있지 않다. 서버에 띄워 두고 텔레그램, 디스코드, 슬랙에서 말을 건다
  • 크론이 들어 있다. "매일 아침 9시에 ~ 정리해서 보내줘" 같은 걸 말로 건다
  • 제일 큰 차이는 스스로 배우는 루프다. 쓰다 보면 메모리와 스킬을 알아서 쌓고, 안 쓰는 건 알아서 치운다

이번 글은 마지막 학습 루프 위주로 정리했다.

Claude Code 의 스킬 ㆍ훅 얘기는 Superpowers 사용법, oh-my-claudecode 사용법 에 써뒀으니 비교하면서 보면 좋다.

아래 내용은 레포(커밋 088f657, 2026-10-29)의 문서와 코드를 읽고, 윈도우 PC 에 소스로 깔아서 돌려본 것이다.

모델 API 키 없이 돌렸다. 그래서 메모리 도구, 스킬 린터, 큐레이터, 위험 명령 판별은 직접 돌린 결과고, 실제 대화와 뒤에서 도는 리뷰는 문서 ㆍ코드 기준이다. 구분해서 적어뒀다.

 

 

설치

Linux, macOS, WSL2 는 한 줄이다.

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

윈도우는 PowerShell 에서.

iex (irm https://hermes-agent.nousresearch.com/install.ps1)

윈도우는 WSL 없이 그냥 돈다고 한다. 설치하면 %LOCALAPPDATA%\hermes 아래에 들어가고, 파이썬 ㆍNode ㆍripgrep 같은 건 설치기가 알아서 받는다.

cf. 백신이 %LOCALAPPDATA%\hermes\bin\uv.exe 를 악성코드로 잡는 경우가 있다고 README 에 따로 적혀 있다. uv(파이썬 패키지 관리자)가 서명 없는 바이너리라 생기는 오탐이라고 하고, 진짜인지 확인하는 명령도 README 에 있다.

설치 후에는 이것만 알면 된다.

hermes setup     # 처음 설정 마법사 (모델, 도구 한 번에)
hermes model     # 모델 ㆍ제공자 고르기
hermes           # 대화 시작
hermes doctor    # 뭔가 안 될때 진단

hermes setup 은 ~/.claude, ~/.codex, ~/.cursor 가 있으면 먼저 "가져올까?" 를 묻는다. 이건 아래에서 따로 본다.

소스로 깔때 함정

설치 스크립트 대신 레포를 받아서 파이썬 3.12 에 pip install -e . 를 해봤다.

설치는 끝나는데 실행하면 이렇게 죽는다.

ModuleNotFoundError: No module named 'ruamel'

pyproject.toml 을 보면 의존성마다 python_version >= '3.14' 조건이 붙어 있다. 3.12 에서는 조건에 안 맞아서 하나도 안 깔린 것.

공급망 공격을 막으려고 버전을 정확히 고정하고 3.14 기준으로만 관리한다고 주석에 적혀 있다.

uv 로 잠금 파일 그대로 3.14 환경을 만들면 된다.

pip install uv
uv sync --frozen --python 3.14 --no-dev

회사망처럼 인증서를 중간에서 바꾸는 곳이면 파이썬을 받다가 invalid peer certificate: UnknownIssuer 가 난다. UV_NATIVE_TLS=1 을 주면 윈도우 인증서 저장소를 써서 해결된다.

HERMES_HOME 을 지정하면 설정 ㆍ메모리 ㆍ스킬이 전부 그 폴더로 들어가서 시험해 보기 좋다.

Hermes Agent vgit.088f657 (2026.9.24) · stable
Python: 3.14.10
OpenAI SDK: 2.54.0

처음 실행은 홈 폴더를 만드느라 꽤 오래 걸렸다. 시간 제한을 짧게 걸었더니 중간에 잘려서 늘려서 다시 돌렸다.

hermes doctor 를 돌리면 메모리, 스킬, 크론, 터미널 같은 기본 도구는 통과하고 API 키와 .env 를 만들라는 안내 2개만 남았다.

 

 

학습 루프 1 - 메모리 파일 두 개

메모리는 ~/.hermes/memories/ 의 파일 두 개가 전부다.

MEMORY.md : 에이전트 자기 메모. 환경, 프로젝트 규칙, 해 보니 되더라 같은 것. 2,200자 제한

USER.md : 사용자 프로필. 말투 취향, 싫어하는 것, 작업 습관. 1,375자 제한

글자 수 제한이 꽤 빡빡하다.

넘치면 자동으로 잘라내지 않고 memory 도구가 에러를 돌려준다. 그러면 에이전트가 같은 턴 안에서 비슷한 항목을 합치거나 지워서 자리를 만든 뒤 다시 쓴다.

도구를 직접 불러 2,305자짜리 항목을 넣어봤다. 앞서 32자가 들어 있는 상태다.

add memory -> success: False
Memory at 32/2,200 chars; adding this entry (2305 chars) would exceed the limit by 140 chars.
Retry as ONE 'operations' batch that removes or shortens (patch) stale entries ...

저장은 안 되고, 몇 자가 넘었는지와 어떻게 다시 하라는 것까지 에러에 들어 있다. 사람이 아니라 모델이 읽으라고 쓴 에러다.

수정은 patch 로 한다. 예전에 있던 replace 는 다른 내용까지 날려서 뺐다고 하는데, 불러보면 이렇게 막힌다.

replace memory -> 'replace' is not available; use 'patch'. ... Nothing was written.

파일은 그냥 텍스트라 cat 으로 바로 볼수 있다.

세션이 시작될때 두 파일이 시스템 프롬프트에 통째로 들어간다. 문서에 나온 모양은 이렇다.

══════════════════════════════════════════════
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

몇 % 찼는지까지 같이 보여줘서 에이전트가 남은 자리를 안다.

여기서 하나 헷갈리기 쉬운게, 대화 중에 메모리를 새로 써도 지금 세션 프롬프트에는 안 들어간다.

세션 시작할때 한 번 찍어둔 걸(frozen snapshot) 끝까지 쓰고, 새로 쓴 건 디스크에만 바로 저장된다. 프롬프트 캐시를 안 깨려고 일부러 그렇게 했다고 한다.

그래서 문서도 일이 하나 끝나면 /new 로 세션을 끊으라고 권한다. 텔레그램 같은 메신저는 재부팅해도 같은 세션이 몇 주씩 이어지는데, 그러면 쌓인 메모리를 다시 읽을 기회가 없다.

"기억해 달라고 했는데 다음에 까먹었다" 는 문의가 제일 많다고 하는데, 문서가 먼저 보라는 건 이거다.

  • 정말 썼는지 cat ~/.hermes/memories/MEMORY.md 로 본다. "기억했습니다" 라고 말만 하고 도구를 안 부르는 경우가 있다. 30B 아래 작은 로컬 모델에서 자주 그런다고 한다
  • 프로필이 다른지 본다. hermes -p work 로 띄우면 ~/.hermes/profiles/work/memories/ 를 쓴다
  • 지금 세션은 옛날 스냅샷이라 다음 세션부터 보인다

 

 

학습 루프 2 - 리뷰 포크가 뒤에서 정리한다

메모리 ㆍ스킬을 언제 쓰냐면, 대화하는 에이전트가 직접 쓸 때도 있고, 이와 별개로 뒤에서 도는 리뷰가 챙겨 쓰기도 한다.

코드(agent/agent_init.py)를 보면 기본값이 둘 다 10 이다.

agent._memory_nudge_interval = 10   # memory.nudge_interval 로 바꿈
agent._skill_nudge_interval = 10    # skills.creation_nudge_interval 로 바꿈
  • 사용자 질문이 10번 쌓이면 -> 지금까지 대화를 보고 메모리에 남길게 있는지 검토
  • 모델이 도구를 부르며 도는 반복이 10바퀴 쌓이면 -> 스킬로 남길 만한 작업이었는지 검토

그 사이에 에이전트가 직접 memory 나 skill_manage 를 부르면 숫자는 0 으로 돌아간다. 이미 챙겼으니 또 볼 필요가 없다는 것.

cf. 문서에는 스킬 쪽이 "한 턴 안에서 10번" 이라고 돼 있는데, 코드(turn_iteration_prep.py, turn_finalizer.py)를 보면 턴이 바뀐다고 0 이 되지는 않고 검토가 돌거나 skill_manage 를 부를때만 0 이 된다.

검토는 지금 대화하는 에이전트가 하는게 아니라 에이전트를 하나 복제(fork)해서 뒤에서 돌린다. 대화는 안 끊긴다.

복제본이 쓸 수 있는 도구도 막혀 있다 (agent/background_review.py 의 _review_tool_whitelist). 스킬 도구, 메모리 도구(메모리 검토일 때만), 그리고 읽기 전용인 read_file ㆍsearch_files 뿐이다. 파일 쓰기나 터미널은 못 쓴다.

Hermes Agent 학습 루프 - 리뷰 포크, 메모리, 스킬, 큐레이터
Hermes Agent 학습 루프 - 리뷰 포크, 메모리, 스킬, 큐레이터

도구를 10바퀴씩 돌렸다는건 꽤 손이 간 일이었다는 뜻이니까 그걸 절차로 남겨 두자는 것.

문서에 적힌 스킬을 만드는 때는 이렇다.

  • 여러 단계짜리 작업을 해냈고 다시 쓸 만할때
  • 에러 ㆍ막다른 길을 헤매다 되는 길을 찾았을때
  • 사용자가 방식을 고쳐줬을때

재밌는건 스킬에 뭘 쓰라는 규칙이다. "lessons, not logs" 라고 해서 PR 번호, 날짜, 대화 인용 같은 사건 기록은 넣지 말고 "이렇게 하면 된다 + 왜" 만 남기라고 한다.

skill_manage 로 스킬을 쓰면 린터도 돈다. PR ㆍ이슈 번호가 너무 많으면 incident-log-shape, 참고 파일이 60개를 넘으면 references-sprawl, SKILL.md 가 24k 자를 넘으면 oversized-body 경고를 준다.

일부러 PR 번호와 날짜로만 30줄을 채운 스킬을 만들어봤다.

success: True
lint_warnings: missing-metadata, missing-metadata, missing-metadata, missing-metadata, missing-section, incident-log-shape

incident-log-shape 가 잡혔다. 그래도 success: True 로 저장은 된다. 막지는 않고 경고만 한다.

missing-metadata 는 frontmatter 에 version 같은 값이 없다는 경고다. 이름과 설명만 쓴 간단한 스킬에도 똑같이 나온다.

자동으로 쓰는게 불안하면 승인을 걸 수 있다.

# ~/.hermes/config.yaml
skills:
  write_approval: true   # 스킬 쓰기 전에 사람이 승인

메모리 쪽에도 같은 이름의 write_approval 이 있다. 켜 두면 대화형 CLI 밖(메신저 등)에서 쓴 메모리는 바로 안 들어가고 /memory pending 에 쌓였다가 /memory approve all 로 들어간다.

 

 

메모리와 스킬은 들어가는 자리가 다르다

둘 다 "기억" 인데 쓰임이 다르다.

메모리는 짧고 항상 필요한 사실이라 매 세션 프롬프트에 통째로 들어간다.

스킬은 긴 절차라 평소엔 이름 ㆍ설명만 목록으로 들어가 있고, 필요할때 skill_view 로 본문을 연다. Claude Code 스킬이랑 같은 방식이다.

Hermes Agent 메모리와 스킬이 프롬프트에 들어가는 자리
Hermes Agent 메모리와 스킬이 프롬프트에 들어가는 자리

그래서 문서도 "매번 쓰는 작업 경로 같은건 메모리보다 스킬에 두라" 고 한다. 메모리 2,200자를 아끼라는 것.

스킬은 ~/.hermes/skills/ 에 있고, 설치된 스킬은 다 슬래시 명령이 된다.

/github-pr-workflow create a PR for the auth refactor
/github-pr-workflow /test-driven-development fix issue #123 and open a PR

두 번째처럼 앞에 스킬을 5개까지 붙여서 한 번에 불러올 수 있다.

/learn 도 있다. 문서 주소, 로컬 SDK 폴더, PDF 책, 방금 한 작업을 주면 그걸로 스킬을 만들어준다.

/learn https://docs.example.com/api/quickstart
/learn how I just deployed the staging server

책처럼 큰 자료는 SKILL.md 하나에 우겨넣지 않고 장마다 references/ 파일로 나눈 지식 베이스 스킬로 만든다고 한다.

 

 

학습 루프 3 - 큐레이터가 안 쓰는 스킬을 치운다

알아서 스킬을 만들면 금방 비슷한 스킬이 수십 개 쌓인다.

그걸 치우는게 큐레이터다. 기본 설정은 이렇다.

curator:
  enabled: true
  interval_hours: 168          # 7일마다
  min_idle_hours: 2            # 2시간 이상 안 쓰고 있을때만
  stale_after_days: 14         # 14일 안 쓰면 stale
  archive_after_days: 30       # 30일 안 쓰면 .archive 로
  consolidate: false           # LLM 으로 합치기는 기본 꺼짐
  prune_builtins: false

크론처럼 정해진 시각에 도는게 아니라, CLI 를 켜거나 게이트웨이가 정리 작업을 할때 "7일 지났나, 2시간 쉬었나" 를 보고 돈다.

기본으로 하는 일은 LLM 없이 사용 기록만 보고 상태를 바꾸는 것이다. 지우지 않고 ~/.hermes/skills/.archive/ 로 옮기기만 해서 되살릴 수 있다.

이건 모델이 없어도 돌아서 직접 해봤다. 전환 함수 apply_automatic_transitions 에 날짜를 앞당겨 넘겼다. 스킬은 deploy-staging 과 pin 해둔 bug-diary 두 개.

+1d  marked_stale: 0, archived: 0  deploy-staging: active
+15d marked_stale: 1, archived: 0  deploy-staging: stale
+31d marked_stale: 0, archived: 1  deploy-staging: archived
skills  ['bug-diary', ...]
archive ['deploy-staging']

문서 그대로 15일째 stale, 31일째 .archive/ 로 옮겨졌다. pin 한 bug-diary 는 끝까지 active 다.

그런데 처음엔 아무 일도 안 일어났다. checked 만 늘고 stale 이 안 됐다.

사용 기록(~/.hermes/skills/.usage.json)을 보니 만든 스킬이 created_by: learn 으로 찍혀 있었다.

코드(tools/skill_manager_tool.py, tools/skill_usage.py)를 보면 리뷰 포크가 만든 스킬만 agent 로 찍히고, 대화 중에 만든 스킬은 learn 으로 찍힌다. 큐레이터는 agent 만 관리한다.

사용자가 시켜서 만든 스킬은 안 쓴다고 멋대로 치우지 않겠다는 것 같다. mark_agent_created 로 agent 로 바꾼 뒤에야 위 결과가 나왔다.

hermes curator status 에도 따로 나온다.

unmanaged (no provenance marker): 1 total
  foreground-created  1
  never auto-staled or archived — `hermes curator adopt <name>` hands one over

손대지 않는 것도 정해져 있다.

  • 리뷰 포크가 만든 스킬만 본다. 대화 중에 만든 스킬은 hermes curator adopt 로 넘겨야 관리한다. 기본 내장 스킬은 prune_builtins: true 일때만, 허브에서 받은 스킬은 아예 안 본다
  • pin 한 스킬, 크론 작업이 쓰는 스킬은 건너뛴다
  • 한 번도 안 쓴 스킬도 만든지 14일은 지나야 치운다

consolidate: true 로 켜면 비슷한 스킬을 LLM 이 읽고 하나로 합친다. 한 번에 API 호출이 50~100번 든다고 해서 기본은 꺼져 있다.

처음 설치하면 바로 안 돌고 7일 뒤에 처음 돈다. 그 전에 뭘 할지 보고 싶으면 이렇게.

hermes curator status            # 마지막 실행, 개수, 오래 안 쓴 것
hermes curator run --dry-run     # 바꾸지 않고 보고서만
hermes curator pin <스킬이름>     # 이건 건드리지 마
hermes curator rollback          # 마지막 백업으로 되돌리기

 

 

프로젝트 지시 파일 - CLAUDE.md 도 읽는다

프로젝트마다 주는 지시 파일은 이 순서로 찾고 처음 찾은 하나만 쓴다.

.hermes.md -> AGENTS.override.md -> AGENTS.md -> CLAUDE.md -> .cursorrules

Claude Code 쓰던 프로젝트면 CLAUDE.md 가 그대로 먹는다. 둘 다 있으면 AGENTS.md 가 이긴다.

SOUL.md 는 따로다. 프로젝트가 아니라 ~/.hermes/SOUL.md 에 두는 에이전트 성격 파일이고 항상 맨 앞에 들어간다. 레포에 있는 기본 SOUL.md 는 "묻는 무게만큼만 답해라, 같은 말 반복하지 마라" 같은 내용이다.

git 저장소 안이면 루트부터 지금 폴더까지 AGENTS.md 를 다 이어 붙이고, 작업하다 하위 폴더에 들어가면 그 폴더 AGENTS.md 를 그때 끼워 넣는다.

 

 

Claude Code 에서 옮겨오기

이미 Claude Code 를 쓰고 있으면 설정을 가져올 수 있다.

hermes plugins install agent-importers
hermes import-agent claude-code --dry-run   # 뭐가 옮겨지는지 미리보기
hermes import-agent claude-code

옮겨지는건 이렇다 (문서 표 기준).

  • ~/.claude/CLAUDE.md -> MEMORY.md 항목
  • settings.json 의 permissions.allow 의 Bash(...) -> command_allowlist, deny -> approvals.deny
  • mcpServers -> mcp_servers
  • skills/<이름>/ -> ~/.hermes/skills/claude-code-imports/<이름>/
  • commands/*.md 슬래시 명령 -> 안 옮김. 스킬로 바꾸라고 알려만 준다

Bash(npm run test:*) 는 npm run test* 글롭으로 바뀌고, Read(...) ㆍWebFetch 같은 Bash 아닌 권한은 대응하는게 없어서 리포트에만 남는다.

키 파일(~/.claude/.credentials.json)은 아예 안 읽고, MCP 환경변수 중 *_TOKEN, *_API_KEY 같은 이름은 빼고 목록만 보여준다. 키는 다시 직접 넣어야 한다.

글로벌 CLAUDE.md 가 길면 2,200자 메모리에 다 안 들어갈텐데.. 이건 문서에 따로 없어서 직접 해봐야 알 것 같다.

 

 

위험한 명령 승인

서버에 띄워 두고 메신저로 시키는 에이전트라 승인 설정은 꼭 보고 쓰자.

approvals:
  mode: smart            # smart | manual | off
  cron_mode: deny        # 크론에서 위험한 명령 나오면 막음
  single_query_mode: deny  # hermes chat -q 한 번 실행에서도 막음

smart(기본) : 보조 LLM 이 위험도를 본다. 확실히 안전하면 통과, 확실히 위험하면 거절, 애매하면 사람한테 묻는다

manual : 위험한 명령은 항상 묻는다

off : 다 통과. --yolo 랑 같다. 세션 중에 /yolo 로 켰다 껐다 한다

크론 ㆍ-q 처럼 대답해 줄 사람이 없는 실행은 기본이 deny 다. 그리고 크론 안에서는 크론을 또 만들 수 없게 막혀 있다.

위험한 명령인지 먼저 거르는 판별 함수(detect_dangerous_command)만 따로 불러봤다. smart 의 LLM 판단은 키가 없어서 못 봤다.

'ls -la'                       통과
'npm test'                     통과
'rm -rf /'                     delete in root path
'rm -rf build'                 recursive delete
'git push --force origin main' git force push (rewrites remote history)
'git reset --hard'             git reset --hard (destroys uncommitted changes)
'curl https://x.sh | bash'     pipe remote content to shell
'DROP TABLE users'             SQL DROP
'chmod 777 /etc/passwd'        world/other-writable permissions

rm -rf build 처럼 평소에 자주 쓰는 명령도 걸린다. 여기 걸린 뒤에 smart 면 보조 LLM 이, manual 이면 사람이 본다.

 

 

마치며...

Claude Code 는 CLAUDE.md 랑 스킬을 사람이 직접 챙기는 비중이 큰 쪽이라면, Hermes 는 스킬 만들기 ㆍ정리까지 에이전트가 알아서 하게 만든 쪽이다.

대신 알아서 쌓이는 만큼 가끔 cat ~/.hermes/memories/MEMORY.md 랑 hermes curator status 로 뭐가 쌓였는지 들여다보는게 좋을 것 같다.

모델을 붙여서 정말 쓸만한 스킬을 만드는지는 아직 못 봤다. 이건 키를 넣고 다음에 돌려봐야 알 것 같다 ㅎㅎ

반응형