OpenClaw·Hermes 마이그레이션 (13/13) — Cutover 당일: 전환 6단계 절차와 설정 트랩
에이전트 스택 전체를 교체할 때 필요한 단계, 검증 체크포인트, 그리고 설정 결합에서 발생하는 대표적 트랩 2종.
핵심 요약
- 에이전트 Cutover는 6단계로 나뉜다: 기존 스택 종료 → 신규 스택 부팅 검증 → config 설정 → cron 등록 → Gateway/메신저 연결 → 24h 검증.
- 재현성 있게 걸리는 설정 트랩 2종: sandbox 환경에서의
$HOME오염,smart_model_routing과 기본 모델 간 불일치. - 롤백은 "LaunchAgent + cron 복구" 한 줄로 유지해두는 것이 안전 설계의 최소 단위다.
Phase 1 — 기존 스택 종료
에이전트 교체에서 포트/토큰/프로세스 충돌을 피하려면 기존 스택을 완전히 정지한 뒤 다음 단계로 진입해야 한다. cron·LaunchAgent·메신저 봇 연결이 각각 독립된 경로로 재기동될 수 있으므로 세 지점을 모두 차단한다.
crontab -r # OpenClaw 전체 cron 제거
launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.openclaw.gateway.plist
완전 정지를 확인하지 않고 Phase 2로 넘어가면 신규 스택 부팅 시 포트 충돌로 heartbeat가 경쟁한다. 이 경우 로그상 원인 분리가 어려워지므로 "프로세스 잔류 0" 확인이 게이트다.
Phase 2 — 신규 스택 부팅 검증
인증 토큰은 기존 CLI 계열에서 그대로 승계 가능한 경우가 많다. Codex CLI 토큰, OAuth refresh_token, 메신저 봇 토큰 세 축을 재배치한다.
cp ~/.codex/auth.json ~/.hermes/auth.json
cat ~/.hermes/config.yaml | grep provider
부팅 후 hermes doctor 같은 자체 진단 커맨드로 3개 축(아이덴티티 파일, 사용자 파일, Auth)을 확인한다.
SOUL.md ✓
USER.md ✓
Auth ✓
세 항목 모두 통과해야 Phase 3로 진입한다. 하나라도 실패하면 해당 파일/토큰 교정 후 재검증. 부팅 단계의 미검증 오류는 뒤 단계에서 훨씬 비싸게 드러난다.
Phase 3 — config.yaml 설정
config 설계에서는 세 가지가 동시에 잡혀야 한다: 스킬 로드 경로, 비활성 플랫폼/스킬 목록, 라우팅 규칙.
skills:
disabled: 45
external_dirs:
- ~/Hermes/.claude/skills
platform_disabled:
discord: 14
routing:
smart_model_routing: true
default_model: gpt-4o-mini # 이후 문제가 된 설정
provider: openai-codex
external_dirs는 스킬 파일이 기본 경로 밖에 있을 때 로드 경로를 추가한다. 누락 시 Tier 2 스킬이 로드되지 않는다.
smart_model_routing: true와 gpt-4o-mini 조합은 뒤에 설명하는 트랩 2번과 직접 연결된다. 라우팅이 켜져 있는 상태에서 기본 모델이 특정 모드의 지원 모델 집합과 어긋나면 런타임에 unsupported model error가 발생한다.
Phase 4 — Cron 등록
상시 실행 에이전트의 "숨쉬기"는 cron으로 분해해 관리한다. 정각 충돌을 피하기 위해 heartbeat는 7분/37분 오프셋을 준다.
| 잡 이름 | 스케줄 | 설명 |
|---|---|---|
| heartbeat-tick | 7,37 * * * * | 30분 간격 heartbeat |
| daily-brief | 40 22 * * * | 22:40 일일 브리핑 |
| research-scan | 0 9 * * * | 09:00 리서치 스캔 |
| reflect | 0 3 * * * | 03:00 반성 루프 |
| monthly-memory | 0 9 1 * * | 매월 1일 09:00 메모리 정리 |
crontab -e
crontab -l # 등록 확인
정각(0분/30분)은 시스템 다른 잡과 충돌 가능성이 있어 heartbeat 류는 7/37 같은 홀수 오프셋이 안전하다.
Phase 5 — Gateway + 메신저 연결
hermes gateway install
launchctl load ~/Library/LaunchAgents/com.hermes.gateway.plist
launchctl list | grep hermes
Discord 연결 시 확인 포인트:
- 봇 계정(Mir#4703) 연결
- 슬래시 커맨드 50개 동기화
- Cron ticker 60초 간격 시작
Discord 슬래시 커맨드 동기화는 API 특성상 최대 1시간까지 지연될 수 있다. 동기화 직후 테스트하면 커맨드가 안 보일 수 있으므로 5~10분 대기 후 확인이 기본이다.
Phase 6 — 24시간 검증
Cutover 성공/실패 판정은 24시간 관측 구간으로 정의한다. 모든 주기 잡이 최소 1회 이상 실행되고, 오류 발생 시 자동 복구 여부까지 본다.
관측 구간의 대표 이벤트:
| 구간 | 이벤트 |
|---|---|
| T+0 | Cutover 시작 / 검증 카운트다운 개시 |
| T+20m | 첫 heartbeat-tick 실행 (정상) |
| T+4h대 | daily-brief 실행 (정상) |
| T+9h대 | reflect 실행 (정상) |
| T+15h대 | research-scan 실행 + dawn heartbeat 오류 발생 |
dawn heartbeat 오류 로그:
unsupported model error: 1회
mode info recognition failure: 1회
→ 자동 복구 완료
오류 원인은 Phase 3 config의 라우팅 설정과 맞물린다. 아래 트랩 2번에서 분리 분석한다.
설정 트랩 1: Sandbox $HOME 오염
증상: 신규 스택이 ~/.hermes/ 대신 예상치 못한 경로로 데이터를 쓴다.
원인: Claude Code sandbox 환경은 $HOME을 실제 사용자 홈(/Users/username)이 아닌 sandbox 격리 경로로 설정한다. 로더 스크립트가 $HOME을 그대로 참조하면 설치 경로가 어긋난다.
수정:
HERMES_HOME="$HOME/.hermes"
REAL_HOME=$(eval echo ~$USER)
HERMES_HOME="$REAL_HOME/.hermes"
eval echo ~$USER는 사용자 레코드에서 홈 경로를 직접 조회하므로 sandbox의 $HOME 재정의 영향을 받지 않는다.
추가 권고: 최초 설치는 사용자 터미널에서 직접 수행한다. sandbox 내부에서 설치하면 심링크 대상이 sandbox 경로로 고정되어 재기동 시 깨진다.
설정 트랩 2: Smart Model Routing과 기본 모델 불일치
증상: 24h 검증 중 dawn heartbeat에서 unsupported model error가 1회 발생하고 자동 복구.
원인: smart_model_routing: true 상태에서 기본 모델이 gpt-4o-mini로 설정되어 있다. 특정 모드(예: heartbeat의 특정 사고 단계)에서 라우터가 해당 모드에 허용되지 않는 모델을 선택하면 런타임에서 모델 로드가 거부된다.
수정:
routing:
smart_model_routing: false # 라우팅 비활성화
default_model: gpt-5.4 # 고정 모델로 전환
원리: 라우팅 테이블의 모드별 허용 모델 집합과 default_model이 교집합을 갖지 않으면 폴백 경로가 실패한다. 해법은 두 가지다.
- 라우팅을 유지하되
default_model을 모든 모드에서 허용되는 모델로 고정 - 라우팅을 끄고 단일 모델로 통일
운영 초기에는 2번이 안전하다. 실패 지점이 줄어들고, 비용/성능 프로파일이 안정되면 1번으로 확장한다.
롤백 경로
Cutover 실패 또는 심각한 오류 시 이전 스택으로 회귀한다.
launchctl load ~/Library/LaunchAgents/com.openclaw.gateway.plist && crontab ~/openclaw_cron_backup.txt
핵심 설계: 롤백은 "LaunchAgent 로드 + cron 복구" 한 줄로 정의 가능해야 한다. 여러 명령이 필요하면 롤백 자체가 실패할 여지가 커진다. 24h 검증이 통과하기 전까지 cron 백업 파일을 보관한다.
최종 상태 체크리스트
| 항목 | 결과 |
|---|---|
| 이전 스택 프로세스 잔류 | 0 |
| 이전 스택 토큰 잔류 | 0 |
| 보조 토큰 잔류 | 0 |
| heartbeat-tick | 정상 |
| daily-brief | 정상 |
| reflect | 정상 |
| research-scan | 정상 (오류 1회 → 자동 복구) |
| Discord 슬래시 커맨드 | 50개 동기화 완료 |
적용 가능 범위와 열린 질문
이 6단계 구조는 OpenClaw → Hermes에 한정되지 않는다. "상시 실행 에이전트 스택"이 cron + LaunchAgent + 메신저 봇 + 라우팅 레이어로 구성된다면 동일한 뼈대로 옮겨 쓸 수 있다. 구체적으로는 다음 조합에 그대로 대응한다.
- Claude Code 기반 로컬 에이전트 ↔ 다른 로컬 에이전트 하네스
- ChatGPT Plus OAuth + Codex CLI 토큰 기반 스택 간 이식
- 단일 메신저 봇(Discord/Slack)을 공유하는 두 백엔드 사이 전환
열린 질문 두 가지:
smart_model_routing을 다시 켤 가치가 있는가? 모드별 비용/성능 프로파일이 유의미하게 갈릴 때만 가치가 있다. 모든 모드에서 단일 모델이 "충분히 좋다"면 라우팅은 복잡도만 늘린다.- 24h 검증 구간은 충분한가? 월 1회 잡(
monthly-memory)은 24h에 포함되지 않는다. 저빈도 잡을 별도 관측 구간으로 떼어내 2단계 검증으로 확장하는 쪽이 안전하다.
시리즈 전체 안내: 시리즈 목차
댓글
댓글 쓰기