📝 한줄 요약
Hermes 프로필이 늘어나자 “타디스가 일을 나누고, 전문 에이전트가 결과를 돌려주는 구조”가 필요해졌다. 처음에는 에이전트끼리 session send를 주고받는 방법을 떠올렸지만, 현재 설치본에는 임의의 다른 프로필 세션으로 보내는 공개 범용 API가 없었다. 그래서 Slack을 눈에 보이는 공용 회의실로 삼고, TARDIS만 자유롭게 지휘하며 다섯 전문 봇은 명시적으로 배정받은 일만 처리하도록 라우팅을 다시 설계했다.
바쁘시면 이것만 읽어도 됩니다.
공용 회의실은 하나, coordinator는 TARDIS 하나로 고정했다.
C&B, 한비자:상앙, Picasso, Libro Vitae, 워런버핏은 TARDIS가 배정한 작업만 받는다.
bot message는 모든 채널에서 허용하지 않고 공용 회의실 하나에만 opt-in했다.
[TARDIS_ASSIGN]와[TARDIS_RESULT]를 사용해 배정과 결과를 구분했다.지정 채널 밖 bot message 차단, 자기 메시지 재수신 차단, 멘션 gate를 실제 harness로 확인했다.
설정과 수신 guard는 완료했지만 실제 Slack assignment→result 왕복 canary는 아직 실행하지 않았다.
🎯 이런 분들께 도움됩니다
여러 Hermes 프로필을 한 명의 총괄 에이전트가 조 정해야 하는 사람
전문 봇이 서로 끼어들거나 같은 결과를 반복하는 문제가 걱정되는 사람
“봇끼리 직접 대화”와 “작업을 안정적으로 인계”를 구분하고 싶은 운영자
Slack을 에이전트 회의실처럼 사용하되 기존 전문 채널은 보존하고 싶은 사람
설정값만 믿지 않고 guard·테스트·실행 상태를 따로 검증하려는 사람
😫 문제 상황 — 봇이 많아졌다고 지휘 체계가 생기는 것은 아니었다
출발점은 간단한 질문이었다.
헤르메스에서 타디스가 다른 에이전트들에게 작업을 지시하고 에이전트들끼리 session send를 통해 소통하며, 타디스가 다른 에이전트를 지휘, 통할하도록 하는 방법은 어떻게 구현해?
이 질문에는 사실 세 가지 문제가 겹쳐 있었다.
TARDIS가 어떤 전문 봇에게 일을 맡길지 결정해야 했다.
전문 봇이 결과를 TARDIS에게 다시 전달해야 했다.
전문 봇끼리 서로 호출하면서 끝없이 대화하는 상황은 막아야 했다.
처음에는 “각 프로필의 세션을 직접 연결하면 되지 않을까?”라고 생각하기 쉽다. 하지만 Hermes의 짧은 위임 호출과 장기 작업용 control plane, Slack gateway는 서로 역할이 다르다. 현재 설치본에서 delegate_task는 짧은 격리 작업에 적합하고, Kanban은 지속 작업의 상태·소유권·의존성을 관리하는 control plane이다. Slack 메시지는 사람이 볼 수 있는 인계면이지, 다른 프로필의 transcript를 직접 조작하는 버스가 아니다.
따라서 이번 문제를 “session send 하나를 찾는 일”로 풀지 않고, 지휘 구조·작업 인계·무한루프 방지·검증 증거를 분리하는 일로 다시 정의했다.
Before와 After
항목
Before
After
지휘 공간
전문 채널과 공용 대화가 섞일 수 있음
공용 회의실 하나를 TARDIS 지휘실로 지정
응답권
bot message 허용 범위가 넓어지면 루프 위험
지정 회의실만 channel-scoped opt-in
작업 인계
자유로운 봇 멘션만으로는 의도가 불명확
assignment/result envelope로 구분
전문 봇의 역할
다른 봇의 대화에도 끼어들 가능성
자기 배정과 자기 멘션이 함께 있을 때만 처리
검증
설정 파일을 읽은 것과 실제 수신을 혼동
read-back·harness·회 귀·gateway 상태를 분리
수동 시간 절약이나 비용 절감은 측정하지 않았다. 그러므로 이번 사례에서는 임의의 “몇 분 단축” 수치를 만들지 않고, 라우팅 구조의 변화와 검증 범위만 기록한다.
🌱 처음에는 무엇을 몰랐나 — 메시지를 보낸다고 작업이 관리되지는 않는다
처음에는 전문 봇끼리 직접 메시지를 보내면 협업이 자연스럽게 이어질 것처럼 보였다. 그러나 실제 운영에서는 다음 질문이 바로 따라온다.
이 메시지는 새 작업인가, 이전 결과의 재전송인가?
누가 이 봇을 호출할 권한이 있는가?
어느 채널에서만 봇 메시지를 허용할 것인가?
같은 결과가 두 번 들어오면 누가 통합을 멈출 것인가?
gateway가 재시작된 뒤에도 같은 thread가 계속 권한을 갖는가?
이 질문에 답하지 않은 채 봇 간 멘션만 열면, 대화가 이어지는 것처럼 보이지만 작업의 소유권과 종료 조건은 사라진다. 그래서 이번에는 “누가 말했는가”보다 먼저 “어떤 종류의 작업 메시지인가”를 정했다.
🛠️ 사용한 도구와 근거
Hermes Agent: 프로필·gateway·toolset·Slack adapter 운영
Slack Socket Mode: 공용 회의실의 가시적인 작업 인계면
Slack adapter: bot message channel scope, mention gate, 자기 메시지 차단
Hermes 설정: TARDIS root와 다섯 specialist 프로필의 역할별 channel prompt
회귀 테스트와 asyncio harness: 허용·차단 경계 확인
Kanban/작업 registry 개념: 장기 작업의 authoritative 상태와 Slack 표면 분리
이번 글에서 다루는 것은 Slack 라우팅과 수신 guard의 실제 적용이다. 전문 봇끼리의 임의 transcript 조작이나 비공개 인증값 연결은 수행하지 않았다.
🔧 작업 과정
1. “봇끼리 session send”를 “지휘실 + control plane + visible handoff”로 다시 나누다
첫 번째 전환점은 도구 이름을 찾는 대신 책임을 나눈 일이었다.
봇끼리 자유롭게 session send를 하는 것보다, 타디스가 한 채널에서 전문 봇을 지휘하도록 설정해줘.
이 요청을 세 층으로 분리했다.
짧은 추론 위임: 필요할 때
delegate_task를 사용한다.지속 작업 상태: 작업 ID·소유권·의존성·완료 상태는 Kanban/작업 registry가 맡는다.
사람이 보는 협업면: Slack 공용 회의실에서는 TARDIS가 배정하고 결과를 통합한다.
이렇게 나누자 “session send를 직접 연결할 수 있는가?”라는 질문과 “작업이 안전하게 왕복하는가?”라는 질문이 서로 다른 문제가 되었다. 직접 transcript를 건드리지 않고도, 사용자는 한 채널에서 전체 흐름을 볼 수 있다.
배운 점: 에이전트 협업에서는 통신 경로보다 상태의 권위(authority)를 먼저 정해야 한다.
2. 공용 회의실의 유일한 coordinator를 정하다
다음 요청은 역할을 명확히 고정했다.
TARDIS가 다른 에이전트들을 지휘하고, 공용 회의실에서 나머지 설정을 완료한다.
공용 회의실에서는 TARDIS만 멘션 없는 일반 요청에 응답하도록 하고, 다섯 전문 봇은 기존 전문 채널 소유권을 유지하면서 공용 회의실에서는 명시적 배정에만 반응하도록 했다.
역할은 다음처럼 정리했다.
역할
책임
TARDIS
요청 판독, 전문 봇 배정, 결과 통합, 최종 보고
C&B
PDF/HWP/HWPX/DOCX와 미디어 변환
한비자:상앙
법률 근거·쟁점·위험 구조화
Picasso
이미지·시각 자료 제작
Libro Vitae
위키·지식베이스 구조화와 등록
워런버핏
가정·출처·가치·위험 검토
그림 1. 실제 Slack 화면이 아니라, 적용된 역할과 연결 방향을 검증 가능한 구조로 다시 그린 evidence card다.
배운 점: 전문 봇을 많이 연결하는 것보다, 최종 결정을 내리는 허브를 하나로 고정하는 편이 책임 소재를 분명하게 만든다.
3. bot message를 전역 허용하지 않고 한 채널에만 열다
두 번째로 위험했던 부분은 “봇 메시지를 허용하는 순간 기존 모든 채널에서도 봇끼리 대화하지 않을까?”라는 문제였다.
그래서 allow_bots=mentions만 추가하지 않고, 봇 메시지가 들어올 수 있는 채널 목록을 별도로 제한했다. 기존 전문 채널에는 이 통신면을 열지 않고, 공용 회의실에만 channel-scoped opt-in을 적용 했다.
adapter의 admission 순서는 다음과 같다.
bot message인지 확인한다.
지정된 공용 회의실인지 확인한다.
TARDIS 멘션이 있는지 확인한다.
자기 메시지라면 폐기한다.
모든 경계를 통과한 경우에만 model dispatch로 보낸다.
그림 2. 지정 채널 밖 bot message와 멘션 없는 bot message를 처리 단계 전에 차단하는 구조다.
배운 점: “봇을 허용한다”는 boolean 하나가 아니라, 누가·어디서·어떤 조건으로 들어오는지를 함께 제한해야 한다.
4. 배정과 결과를 envelope로 분리하다
자유로운 문장만으로는 메시지의 수명과 목적을 알기 어렵다. 그래서 공용 라우팅 규칙에 다음 계약을 넣었다.
배정:
[TARDIS_ASSIGN]결과:
[TARDIS_RESULT]식별자:
run_id,task_id,step대상: 배정받는 전문 봇의 멘션
결과 회신: TARDIS 멘션과 한 번의 요약 결과
전문 봇은 자기 배정과 자기 멘션이 함께 있을 때만 작업을 처리한다. 전문 봇끼리 직접 확인 메시지를 반복하지 않고, 이미 통합된 결과나 형식 오류는 loop guard 대상이 된다.
중요한 점은 이것이 Slack을 완전한 workflow database로 만든다는 뜻은 아니라는 것이다. envelope는 메시지의 의도를 표면에서 읽기 위한 계약이고, 장기 작업의 소유권·의존성·완료 상태는 Kanban 또는 작업 registry에 남겨야 한다.
배운 점: 대화형 메시지는 사람이 읽기 쉬워야 하지만, 반복 실행을 막으려면 사람이 읽는 표지와 작업 식별자를 함께 가져야 한다.
5. 설정 파일을 읽는 데서 멈추지 않고 실제 경계를 시험하다
마지막 전환점은 “설정이 들어갔다”와 “올바른 메시지만 model dispatch에 도착한다”를 분리한 것이다.
검증한 항목은 다음과 같다.
TARDIS root와 다섯 specialist의 설정 read-back
공용 회의실 밖 bot message 차단
공용 회의실에서 TARDIS 멘션 assignment 수신
자기 메시지 재수신 차단
동기 Slack 회귀 테스트
specialist gateway와 TARDIS gateway lifecycle 반영
반대로 아직 하지 않은 것도 분명히 남겼다.
현재 환경에
pytest-asyncio가 없어 async Slack suite 182개는 실행하지 않았다.실제 Slack에서 하나의 assignment가 하나의 result로 돌아오는 live canary는 아직 실행하지 않았다.
따라서 “end-to-end 왕복까지 검증 완료”라고 말하지 않는다.
그림 3. 완료된 검증과 아직 실행하지 않은 canary를 같은 완료 문장으로 섞지 않기 위한 경계 카드다.
배운 점: 테스트가 실행되지 않은 이유도 검증 결과의 일부다. “실패하지 않았다”와 “실제로 시험했다”는 같은 말이 아니다.
✅ 결과 — 한 채널의 지휘 구조는 생겼고, 검증 범위도 분리됐다
Before vs After
항목
Before
After
지휘 구조
여러 프로필의 역할과 호출면이 분리되어 보 임
TARDIS 1개 허브 + 5개 전문 worker
공용 대화
일반 대화와 bot-to-bot 가능성이 섞일 수 있음
공용 회의실 1개에만 제한된 봇 통신면
배정 표시
일반 멘션만으로 목적을 추정
TARDIS_ASSIGN·run_id·task_id·step
결과 표시
회신이 새 작업인지 결과인지 모호함
TARDIS_RESULT + TARDIS 회신 계약
기존 전문 채널
변경 위험
기존 채널 소유권과 free-response는 보존
검증 선언
설정 파일 중심
read-back·harness·회귀·gateway 상태 분리
실제로 확인한 결과
검증 항목
결과
의미
6개 프로필 설정 read-back
PASS
coordinator·worker 설정이 저장됨
지정 회의실 밖 bot message
PASS
허용 범위 밖 메시지가 차단됨
지정 회의실 assignment 수신
PASS
허용된 봇 인계면은 열림
동기 회귀
1 passed, 248 deselected
추가한 범위의 동기 테스트 통과
specialist gateway 갱신
PASS
변경된 설정을 프로세스에 반영
async Slack suite
NOT RUN
테스트 의존성 미설치
실제 Slack canary
NOT RUN
플랫폼 end-to-end는 후속 검증
이 결과의 정확한 해석은 다음과 같다.
설정·수신 guard·프로세스 재적용은 확인했다. 실제 Slack에서 assignment가 result로 왕복하는 최종 canary는 아직 남아 있다.
💬 이 과정에서 배운 AI 활용 팁
효과적이었던 것
원하는 통신보다 원하는 책임을 먼저 적기
“session send가 되게 해줘”에서 멈추지 않고, 누가 배정하고 누가 최종 통합하는지 먼저 정했다.
한 채널을 회의실로 고정하기
봇마다 다른 채널을 열어 주는 대신, 사람과 봇이 같은 흐름을 볼 수 있는 허브를 하나 만들었다.
bot message 허용 범위를 channel-scoped로 제한하기
allow_bots만 전역으로 켜지 않고, 실제 통신이 필요한 방만 열었다.
설정·수신·실행·라이브를 별도 증거로 보기
config read-back은 설정 증거이고, harness는 admission 증거이며, live canary는 플랫폼 증거다.
완료하지 않은 검증을 본문에 남기기
async suite가 실행되지 않았고 live 왕복을 하지 않았다는 사실을 숨기지 않았다.
이렇게 하면 안 됩니다
session send라는 이름을 찾았다는 이유만으로 다른 프로필의 transcript를 직접 수정하지 않 는다.allow_bots=all처럼 넓은 허용을 먼저 켜고 나중에 루프를 막으려 하지 않는다.Slack thread가 이어진다는 이유만으로 모든 전문 봇에게 계속 응답 권한을 주지 않는다.
[TARDIS_RESULT]라고 쓰여 있다는 이유만으로 결과가 실제로 검증되었다고 가정하지 않는다.설정 read-back만으로 live end-to-end 성공을 선언하지 않는다.
🌍 다른 업무에 적용한다면?
예를 들어 한 팀이 “문서 접수 → 법률 검토 → 시각 자료 제작 → 지식베이스 등록”을 반복한다고 하자. 이 구조를 그대로 옮기면 다음처럼 운영할 수 있다.
TARDIS가 접수 내용을 읽고 작업 ID를 만든다.
C&B가 원본 변환과 파일 무결성을 확인한다.
한비자:상앙이 법률 쟁점과 위험을 검토한다.
Picasso가 필요한 그림과 캡처를 만든다.
Libro Vitae가 검증된 결과를 지식베이스 좌표에 등록한다.
TARDIS가 각 결과를 모아 사용자에게 하나의 완료 보고를 만든다.
이때 Slack은 진행상황을 사람이 보는 회의실로 사용하고, 작업 ID·상태·의존성·완료 증거는 별도의 durable control plane에 남긴다. 그러면 “누가 어떤 파일을 만들었는가”와 “전체 작업이 끝났는가”를 분리해서 확인할 수 있다.
🤝 배워서 남 주기
이번 사례의 핵심은 특정 채널 ID나 프로필 이름이 아니다. 다른 Hermes 사용자도 다음 네 가지를 먼저 정하면 같은 구조를 만들 수 있다.
공용 회의실은 어디인 가?
coordinator는 누구인가?
worker가 처리할 수 있는 assignment의 모양은 무엇인가?
결과를 언제 닫고, 중복을 어떻게 멈출 것인가?
재사용 템플릿 1: 공용 지휘실 설계 요청
Hermes에서 [총괄 에이전트]를 유일한 coordinator로 두고 [전문 에이전트 목록]을 worker로 연결해 주세요. 기존 전문 채널은 보존하고, [공용 회의실]에서는 총괄이 배정하고 worker가 결과를 회신하는 hub-and-spoke 구조로 제한해 주세요. 임의의 다른 프로필 transcript를 직접 수정하지 말고, Slack 표면·durable control plane·검증 증거를 분리해 설명해 주세요.
재사용 템플릿 2: bot-to-bot loop guard 요청
bot message를 전역 허용하지 말고 [허용할 회의실]에만 channel-scoped opt-in으로 열어 주세요. 배정은
[TARDIS_ASSIGN], 결과는[TARDIS_RESULT]로 구분하고run_id,task_id,step, 대상 멘션을 포함해 주세요. 자기 메시지 재수신·다른 채널의 bot message·멘션 없는 bot message·중복 결과를 각각 어떻게 차단하는지 테스트와 함께 검증해 주세요. 실행하지 않은 async suite나 live canary는 완료로 표현하지 마세요.
🕊️ 이 사례가 줄이는 것
이 구조가 줄이는 것은 단순한 메시지 수가 아니다.
전문 봇끼리 서로 호출하면서 생기는 응답 루프
여러 채널에 흩어진 작업의 소유권 불명확성
설정 파일만 보고 실제 수신도 된 것으로 착각하는 위험
“결과”와 “새 작업”을 구분하지 못하는 혼선
직접 transcript를 건드려 세션 경계를 깨뜨리는 위험
특히 AI를 처음 운영하는 사람에게는 “봇을 여러 개 연결하면 자동으로 협업한다”는 기대 대신, 지휘관·회의실·작업원장·검증 gate가 각각 필요하다는 운영 감각을 남긴다.
🚀 앞으로의 계획
이번 사례의 다음 항로는 세 가지다.
실제 Slack에서 단일 assignment와 단일 result의 canary 왕복을 실행한다.
pytest-asyncio를 보완한 뒤 async Slack suite를 다시 실행한다.장기 작업은 Slack thread만 믿지 않고 Kanban/작업 registry의 상태와 연결한다.
이 세 단계가 실행되기 전까지는 현재 상태를 설정·수신 guard 완료, live end-to-end 후속 검증으로 유지한다.
🔗 근거와 공개 경계
근거는 Hermes Slack adapter 변경, 6개 프로필 설정 read-back, Slack routing rule, 회귀 harness, shared devlog·Chronicle이다.
공개 본문에는 로컬 절대경로, Slack 내부 식별자, 인증값, 세션 식별자를 넣지 않았다.
delegate_task, Kanban, Slack gateway는 서로 다른 책임을 가진다는 점을 구분했다.실제 Slack canary와 async suite가 실행되지 않았다는 사실을 본문에 명시했다.
Library 발 행은 로컬 human-facing artifact promotion이며, 외부 웹·커뮤니티 게시와는 별개의 상태다.
📦 산출물과 상태
생성된 산출물
이 사례게시글 Markdown 원본
공용 회의실 hub-and-spoke 구조 카드
bot message admission guard 카드
검증 범위와 남은 경계 카드
상태
원본 lane: 사례게시글 source/workbench 보존
Library: 공용 publisher를 통한
case-library발행 대상외부 웹·커뮤니티 발행: 수행하지 않음
live Slack assignment→result canary: 아직 수행하지 않음