Hermes 멀티 프로필로 여러 Slack 워크스페이스에 에이전트 붙이기
한 대의 머신에서 Hermes Agent를 프로필(profile) 단위로 여러 개 띄우고, 각 프로필을 서로 다른 Slack 워크스페이스에 연결하는 방법 정리. 실제로 특정 프로필(custom_profile)을 새 워크스페이스(New_Workspace, team T_NEW)에 붙이다가 “연결된 것 같은데 답장을 안 하는” 증상으로 한참 헤맸고, 원인은 Slack bot 토큰 무효(invalid_auth) 였다. 다음에 프로필을 더 만들 때 같은 데서 막히지 않도록 과정을 통째로 박제해 둔다.
1. 큰 그림: 프로필이 뭐고 왜 쓰나
Hermes의 프로필은 완전히 격리된 인스턴스다. 각 프로필은 자기만의 HERMES_HOME 디렉토리를 가진다 — config, API 키(.env), 세션 DB, 메모리, 스킬, 게이트웨이 상태까지 전부 분리된다.
- 기본(루트) 인스턴스 →
~/.hermes/ - 이름 있는 프로필 →
~/.hermes/profiles/<name>/내부적으로hermes -p <name> ...를 주면_apply_profile_override()가 모든 모듈 import 전에HERMES_HOME을 그 프로필 폴더로 바꿔치기한다. 그래서 코드 전역의get_hermes_home()이 자동으로 해당 프로필로 스코프된다.
핵심 효과: 프로필마다 게이트웨이를 따로 띄울 수 있고, 각 게이트웨이가 다른 메신저 계정/워크스페이스에 붙는다. 우리 머신에선 지금 두 개가 동시에 돈다.
| |
두 게이트웨이가 같이 떠 있는 건 정상이다. 격리만 제대로 돼 있으면 충돌하지 않는다. “제대로 돼 있으면"이 함정의 핵심 — 아래 4·6장 참고.
2. 새 프로필 만들기 (단계별)
1) 프로필 생성
| |
2) 이 프로필 컨텍스트로 설정 (모든 명령에 -p )
| |
3) 게이트웨이 실행
| |
- 프로필 관련 서브커맨드:
create,list,switch,use,delete. - 주의:
hermes profile delete <name>은 그 프로필의HERMES_HOME전체(세션·메모리 포함)를 날린다. 함부로 쓰지 말 것.
3. Slack 토큰 2종 — 여기서 90%가 막힌다
Hermes의 Slack 연동은 Socket Mode 기반이고, 토큰이 두 종류 필요하다. 이 둘의 역할이 다르고, 유효성이 따로 논다는 게 핵심이다.
| .env 키 | 토큰 형태 | 용도 | 어디서 발급 |
|---|---|---|---|
| SLACK_APP_TOKEN | xapp-... | 이벤트 수신 (Socket Mode 연결) | Slack 앱 → Basic Information → App-Level Tokens (connections:write 스코프) |
| SLACK_BOT_TOKEN | xoxb-... | Web API 호출 (메시지 전송, 채널 조회 등) | Slack 앱 → OAuth & Permissions → Bot User OAuth Token (워크스페이스 설치 시 발급) |
추가로 보통 함께 두는 것들:
SLACK_HOME_CHANNEL— 기본 응답 채널/DM ID (예:C0B5M...)SLACK_ALLOWED_USERS— 허용 사용자 ID 목록 (예:U1923...) 왜 둘로 나뉘는가xapp (app-level token)은 앱 자체에 묶인다. 앱을 워크스페이스에 재설치해도 보통 그대로 살아남는다. → Socket Mode가 계속 붙는다.
xoxb (bot token)은 “이 앱이 이 워크스페이스에 설치된 인스턴스” 에 묶인다. 앱을 재설치하거나 토큰을 재생성하면 값이 바뀐다. 옛 값은 즉시 무효가 된다.
결과적으로 xapp는 맞는데 xoxb만 틀린 어긋난 상태가 너무 쉽게 만들어진다. 이게 정확히 우리가 겪은 증상이다.

4. 우리가 겪은 증상과 진단
증상
- 봇이 워크스페이스에 인증된 것처럼 보임. DM/멘션도 들어옴 (channel directory가 실시간 갱신됨).
- 그런데 답장을 안 함. “잘 되다가 안 되고 꼬인” 느낌. 실제로 일어난 일
게이트웨이 로그에 이게 5분마다 1,400번 넘게 찍히고 있었다:
| |
그리고 첫 인증 로그 바로 그 순간부터 깨져 있었다:
| |
| 토큰 | 상태 |
|---|---|
| SLACK_APP_TOKEN (xapp) | ✅ 정상 — Socket Mode로 New_Workspace에 인증됨 → 이벤트는 들어옴 |
| SLACK_BOT_TOKEN (xoxb) | ❌ invalid_auth — 모든 답장/조회 API가 실패 |
즉 받기만 하고 못 보내는 반쪽 연결. 겉보기엔 연결돼 보여서 더 헷갈렸다.
결정적 확인 — auth.test
토큰 유효성은 Slack auth.test(읽기 전용)로 1초 만에 판별된다. 토큰을 화면에 찍지 말고 .env에서 바로 읽어 헤더로 넘긴다:
| |
- **정상이면:**JSON
| |
- **무효면:**JSON
| |
우리 케이스: custom_profile bot 토큰 → invalid_auth, 루트 bot 토큰 → ok: true. 끝. 범인 확정.
해결
New_WorkspaceSlack 앱 → OAuth & Permissions → Bot User OAuth Token(xoxb-) 최신 값을 복사. (앱을 재설치/토큰 재생성했으면 값이 바뀌어 있다.)
- ⚠️ 이 bot 토큰은 지금 쓰는 app 토큰(
xapp)과 같은 앱의 것이어야 한다. 서로 다른 앱의 토큰을 섞으면 정확히 이 증상(Socket은 붙는데 Web API는invalid_auth)이 난다.
~/.hermes/profiles/custom_profile/.env의SLACK_BOT_TOKEN교체.- 게이트웨이 재시작 (아래 5장 — 이걸 안 해서 두 번 헤맸다).
auth.test재확인 →ok: true뜨면 끝.
5. 두 번째 함정: .env 고쳐도 재시작 안 하면 그대로
게이트웨이는 시작 시점에 .env를 메모리로 읽는다. 떠 있는 프로세스는 이후 .env를 고쳐도 반영하지 않는다. 우리 케이스 타임라인이 정확히 이거였다:
| |
토큰을 고쳐도 게이트웨이가 옛 토큰을 물고 있으니 계속 깨진 것처럼 보인다. → .env를 만졌으면 반드시 재시작.
| |
⚠️ gateway stop/restart --all은 모든 프로필의 게이트웨이를 전부 죽인다. 루트 게이트웨이까지 같이 내려가니, 특정 프로필만 만질 땐 --all 빼고 -p <name>만 줄 것.
6. 세 번째 함정: 프로필 간 토큰 공유 = 락 충돌
게이트웨이 플랫폼 어댑터는 고유 크리덴셜(봇 토큰)에 scoped lock을 건다. 두 프로필이 같은 토큰을 쓰면 나중에 뜬 쪽이 막힌다. 우리도 초기에 custom_profile이 루트와 같은 Telegram 봇 토큰을 써서 이게 났었다:
| |
- 원칙: 프로필마다 그 플랫폼의 크리덴셜은 별도로 둔다.
- Slack이면 워크스페이스별로 다른 Slack 앱 + 다른 xapp/xoxb 쌍.
- 안 쓰는 플랫폼은 그 프로필
.env에서 토큰을 빼버린다 (우리는custom_profile의 Telegram 토큰을 제거해서 락을 없앴다). 참고:gateway_state.json은 상태 전이 때만 갱신된다. 며칠 전 값이 그대로 남아 stale할 수 있으니, 현재 상태는 항상 로그로 교차 확인할 것.
7. 진단 레시피 (다음에 막히면 이 순서로)
| |
토큰을 비교만 하고 싶을 땐(노출 없이) sha256 앞 8자리로 동일성만 확인:
| |
8. 다음 프로필 만들 때 체크리스트
[ ] hermes profile create <name>
[ ] 새 워크스페이스마다 새 Slack 앱을 만든다 (기존 앱 재사용 X).
[ ] 그 앱에서 App-Level Token(xapp, connections:write) 발급 → SLACK_APP_TOKEN
[ ] 그 앱을 워크스페이스에 설치 후 Bot User OAuth Token(xoxb) 복사 → SLACK_BOT_TOKEN
[ ] xapp와 xoxb가 같은 앱의 것인지 확인 (섞이면 invalid_auth).
[ ] SLACK_HOME_CHANNEL, SLACK_ALLOWED_USERS 설정.
[ ] 다른 프로필과 토큰을 공유하지 않는다. 안 쓰는 플랫폼 토큰은 .env에서 제거.
[ ] .env 저장 → auth.test로 ok:true 먼저 확인 → 그 다음 게이트웨이 기동.
[ ] .env를 나중에 고쳤으면 → gateway restart (절대 -all 말고 p <name>).
[ ] gateway.error.log에 invalid_auth / _lock이 없는지 확인.
9. 부록
프로필 디렉토리 구조
| |
명령어 레퍼런스
| |

한 줄 요약
Socket Mode(xapp)는 붙는데 답장을 안 하면 십중팔구 xoxb 봇 토큰이 무효다. auth.test로 즉시 판별하고, .env 고쳤으면 게이트웨이 재시작을 잊지 말 것. 토큰은 프로필·워크스페이스마다 같은 앱에서 한 쌍씩, 절대 공유하지 말 것.