Bot tokens + Auth credential Hermes 이전
결론
- OpenClaw 원본은 유지했고, 필요한 credential 파일을 Hermes 쪽으로 복사했다.
- 복사 대상:
/Users/ron/.openclaw/bot_tokens.json→/Users/ron/.hermes/bot_tokens.json/Users/ron/.openclaw/auth/profiles/*→/Users/ron/.hermes/auth/profiles/*- 권한:
/Users/ron/.hermes/bot_tokens.json:600/Users/ron/.hermes/auth:700/Users/ron/.hermes/auth/profiles:700- profile 파일들:
600 - Hermes workspace scripts의 bot token 참조는 이미
.hermes/bot_tokens.json으로 rewrite 되어 있었다. auth/profiles/github-copilot.json을 직접 참조하는 Hermes workspace script는 발견되지 않았다.- 현재 Hermes agent 계열은 Copilot credential을
COPILOT_GITHUB_TOKEN/GH_TOKEN/GITHUB_TOKEN또는~/.hermes/auth.json경로로 찾는 구조다. - 이번 복사는 OpenClaw compatibility/rollback용 credential 이전으로 판단된다.
claude_telegram_listener.py는 아직 OpenClaw launchd가 띄운 PID61612가 OpenClaw 경로를 사용 중이다. Hermes 쪽 listener 파일은.hermes/bot_tokens.json을 보도록 rewrite 되어 있지만, launchd cutover는 아직 안 됐다.
1. 참조 grep 결과
bot_tokens.json 참조 — Hermes workspace/scripts
/Users/ron/.hermes/workspace/scripts/codex_telegram_listener.py:32:_TOKENS_PATH = Path.home() / ".hermes" / "bot_tokens.json"
/Users/ron/.hermes/workspace/scripts/shared/telegram_multibot.py:17:_CONFIG_PATH = Path.home() / ".hermes" / "bot_tokens.json"
/Users/ron/.hermes/workspace/scripts/claude_telegram_listener.py:43:_TOKENS_PATH = Path.home() / ".hermes" / "bot_tokens.json"
판정:
| 파일 | 참조 방식 | 실제 runtime path |
|---|---|---|
codex_telegram_listener.py |
Path.home() / ".hermes" / "bot_tokens.json" |
/Users/ron/.hermes/bot_tokens.json |
shared/telegram_multibot.py |
Path.home() / ".hermes" / "bot_tokens.json" |
/Users/ron/.hermes/bot_tokens.json |
claude_telegram_listener.py |
Path.home() / ".hermes" / "bot_tokens.json" |
/Users/ron/.hermes/bot_tokens.json |
즉 absolute literal은 아니지만, home-relative absolute path로 안전하게 Hermes 파일을 가리킨다.
github-copilot.json / auth profiles 참조
Hermes workspace/scripts에서 auth/profiles/github-copilot.json 직접 참조는 없음.
관련 grep에서는 Copilot model label만 다수 발견됐다.
예:
/Users/ron/.hermes/workspace/scripts/agent_registry.py:36: "github-copilot/gpt-5-mini"
/Users/ron/.hermes/workspace/scripts/agent_queue_worker.py:110: fallback_chain = ["github-copilot/gpt-5-mini", "openai-codex/gpt-5.4", "ollama/qwen2.5:3b"]
/Users/ron/.hermes/workspace/scripts/shared/llm.py:487: if model_id.startswith("github-copilot/"):
shared/llm.py의 GitHub/Copilot 계열 token 로딩은 profile JSON이 아니라 다음 순서다.
_token = os.environ.get("GITHUB_TOKEN", "")
if not _token:
gh auth token
if not _token:
~/.hermes/.env 의 OPENCLAW_TOKEN
Hermes agent 본체 쪽도 github-copilot.json 직접 참조는 없고, Copilot provider 문서/코드는 다음 방식을 사용한다.
COPILOT_GITHUB_TOKEN / GH_TOKEN / GITHUB_TOKEN
~/.hermes/auth.json
따라서 이번에 복사한 /Users/ron/.hermes/auth/profiles/github-copilot.json은 현재 active lookup 경로라기보다 OpenClaw 호환/롤백 credential 보존으로 보는 게 맞다.
2. 복사 결과
원본 메타데이터:
-rw------- 1 ron staff 106 Mar 10 19:46 /Users/ron/.openclaw/auth/profiles/github-copilot.json
-rw------- 1 ron staff 107 Mar 10 19:43 /Users/ron/.openclaw/auth/profiles/github-copilot.json.bak-20260310194317
-rw-------@ 1 ron staff 106 Apr 15 12:54 /Users/ron/.openclaw/auth/profiles/github-copilot.json.bak-403-20260415-125406
복사 후 target:
drwx------@ 3 ron staff 96 Apr 15 13:42 /Users/ron/.hermes/auth
drwx------@ 5 ron staff 160 Apr 15 12:54 /Users/ron/.hermes/auth/profiles
-rw-------@ 1 ron staff 106 Mar 10 19:46 /Users/ron/.hermes/auth/profiles/github-copilot.json
-rw-------@ 1 ron staff 107 Mar 10 19:43 /Users/ron/.hermes/auth/profiles/github-copilot.json.bak-20260310194317
-rw-------@ 1 ron staff 106 Apr 15 12:54 /Users/ron/.hermes/auth/profiles/github-copilot.json.bak-403-20260415-125406
-rw-------@ 1 ron staff 525 Apr 15 13:42 /Users/ron/.hermes/bot_tokens.json
파일 크기 비교:
github-copilot.json src_size= 106 dst_exists= True dst_size= 106
github-copilot.json.bak-20260310194317 src_size= 107 dst_exists= True dst_size= 107
github-copilot.json.bak-403-20260415-125406 src_size= 106 dst_exists= True dst_size= 106
3. 권한/소유권 확인
bot_mode= 0o600 owner_uid= 501
copilot_mode= 0o600 owner_uid= 501
소유자는 현재 사용자 ron이며, 민감 파일은 600으로 설정했다.
4. 라이브 파싱 테스트 — 마스킹 출력
bot_tokens.json
bot_tokens_path= /Users/ron/.hermes/bot_tokens.json
bot_tokens_type= dict
bot_count= 4
bot= claude bot_name= CLAUDE CODE(LOCAL) username= openclaw_harybot token_mask= 83820953...GkLw
bot= claude_bridge bot_name= CLAUDE CODE BRIDGE(LOCAL) username= ronbridgebot token_mask= 87122366...I__U
bot= codex bot_name= CODEX(LOCAL) username= ronclawBot token_mask= 84231387...WFCU
non_bot_entry= collab_chat_id type= int mask= -1003522...8967
bot_token_entry_count= 3
판정:
- JSON parse OK.
- 봇 token dictionary 3개 확인.
- 추가 scalar entry
collab_chat_id1개 존재. - 토큰 값은 보고서에 평문 노출하지 않고 prefix/suffix만 마스킹했다.
github-copilot.json
copilot_path= /Users/ron/.hermes/auth/profiles/github-copilot.json
copilot_keys= ['token']
copilot_token_mask= github...ZtKG
copilot_mode= 0o600 owner_uid= 501
profile_files= ['github-copilot.json', 'github-copilot.json.bak-20260310194317', 'github-copilot.json.bak-403-20260415-125406']
판정:
- JSON parse OK.
- token key 존재.
- 값은 마스킹 확인만 수행.
5. claude_telegram_listener 의존성 판단
현재 OpenClaw launchd listener는 여전히 OpenClaw 경로를 사용 중이다.
gui/501/com.openclaw.claude-listener = {
state = running
program = /usr/bin/python3
arguments = {
/usr/bin/python3
-u
/Users/ron/.openclaw/workspace/scripts/claude_telegram_listener.py
}
working directory = /Users/ron/.openclaw/workspace
pid = 61612
last exit code = (never exited)
}
소스 token path 비교:
/Users/ron/.openclaw/workspace/scripts/claude_telegram_listener.py:43:_TOKENS_PATH = Path.home() / ".openclaw" / "bot_tokens.json"
/Users/ron/.hermes/workspace/scripts/claude_telegram_listener.py:43:_TOKENS_PATH = Path.home() / ".hermes" / "bot_tokens.json"
/Users/ron/.hermes/workspace/scripts/codex_telegram_listener.py:32:_TOKENS_PATH = Path.home() / ".hermes" / "bot_tokens.json"
/Users/ron/.hermes/workspace/scripts/shared/telegram_multibot.py:17:_CONFIG_PATH = Path.home() / ".hermes" / "bot_tokens.json"
판정:
- PID
61612의 live listener는 아직 OpenClaw 소유이며/Users/ron/.openclaw/bot_tokens.json을 읽는다. - Hermes workspace에는 listener 사본이 있고
.hermes/bot_tokens.json을 보도록 rewrite 되어 있다. - 하지만 launchd plist 자체가 아직
/Users/ron/.openclaw/workspace/scripts/claude_telegram_listener.py를 가리키므로, listener cutover는 별도 작업으로 남아 있다. - 지금 원본
~/.openclaw/bot_tokens.json을 유지한 판단은 맞다. 이걸 삭제하면 PID 61612 listener가 깨질 수 있다.
6. Hermes Gateway와 bot_tokens.json 관계
추가 맥락과 확인을 합치면:
- Hermes Gateway는 현재
~/.hermes/.env의TELEGRAM_BOT_TOKEN을 사용한다. ~/.hermes/.env에서 확인된 관련 key:
env_exists= True keys_of_interest= ['TELEGRAM_ALLOWED_USERS', 'TELEGRAM_BOT_TOKEN']
따라서 Gateway 자체는 bot_tokens.json에 직접 의존하지 않는다. bot_tokens.json은 listener/bridge 계열 스크립트의 dependency다.
7. 변경 파일
생성/복사:
/Users/ron/.hermes/bot_tokens.json/Users/ron/.hermes/auth/profiles/github-copilot.json/Users/ron/.hermes/auth/profiles/github-copilot.json.bak-20260310194317/Users/ron/.hermes/auth/profiles/github-copilot.json.bak-403-20260415-125406
수정하지 않은 것:
/Users/ron/.openclaw/bot_tokens.json/Users/ron/.openclaw/auth/profiles/*- Hermes/OpenClaw scripts 코드
- LaunchAgents
8. 남은 작업
com.openclaw.claude-listenercutover 결정 필요- 현 상태 유지: OpenClaw listener 계속 사용, OpenClaw bot_tokens 유지 필요.
- Hermes 이전: launchd plist를 Hermes script 경로로 바꾸고,
/Users/ron/.hermes/bot_tokens.json을 사용하게 전환. - Copilot credential active path 정리 필요
- copied profile은 현재 direct lookup 경로가 아니다.
- Hermes agent는
COPILOT_GITHUB_TOKEN또는~/.hermes/auth.json방식이 canonical이다. - 필요하면
github-copilot.json의 token을.hermes/.env의COPILOT_GITHUB_TOKEN또는 Hermes auth store로 import하는 별도 작업이 필요하다.
자체평가
- 정확성: 4.7/5 — 요청 파일 복사/권한/파싱/참조 판단 완료.
- 완성도: 4.6/5 — listener cutover는 범위 밖으로 남겼고, 현 의존성은 명확히 기록.
- 검증: 4.8/5 — grep, metadata, chmod, JSON parse, masked token 확인 수행.
- 최소 변경: 5.0/5 — credential 복사와 권한 설정만 수행, 코드/원본/LaunchAgent 수정 없음.
종합: 4.8/5.