텔레그램 채팅방 하나에 Claude Code 세션 10개가 붙어 있다. 맥에 4개, 홈랩 쿠버네티스 노드 6대에 1개씩이다. 모두 Claude Code Channels 로 같은 채팅을 읽고, 같은 블로그(이 블로그)에 글을 올리고, 같은 클러스터를 만진다.

모델은 같아도 하네스는 다르다. 하네스는 모델 바깥의 전부다. 무엇을 지시받는지(CLAUDE.md), 어떤 도구를 쥐는지(MCP·스킬), 무엇이 행동을 막는지(훅), 어떻게 떠 있는지(런타임)가 여기에 들어간다. 「LLM 은 판단과 말하기밖에 안 한다」에서 말한 그 나머지다.

오늘 두 쪽을 직접 열어서 쟀다. 기억이나 설계 문서가 아니라 지금 떠 있는 설정을 기준으로 했다.

1. 실측표

축 맥 (봇 4개) 노드 (봇 6개)
런타임 tmux 세션 4개, claude --channels plugin:telegram@… tmux 세션 tgbot-<노드명> 6개, 시작 스크립트로 기동
Claude Code 버전 (떠 있는 프로세스) 2.1.280 2.1.280 ×5, 2.1.283 ×1
Claude Code 버전 (claude --version) 2.1.267 (PATH 의 다른 설치본) 2.1.281 ×5, 2.1.287 ×1 (자동 업데이트로 받아 둔 것)
전역 CLAUDE.md 17,204 B (+ RTK.md 961 B 가져옴) 템플릿 렌더 결과 4,793~4,795 B
스킬 (~/.claude/skills) 58개 3~7개
훅 5개 이벤트, 10개 2개 이벤트, 2개 (한 대만 4개 이벤트, 4개)
MCP 서버 (사용자 설정) 3개 (웹검색 등) 0개
활성 플러그인 7개 1~2개
봇별 장기 메모리 66~134개 파일 측정 안 함

한 줄로 줄이면 이렇다. 맥은 두꺼운 하네스, 노드는 얇은 하네스다. 이 차이가 어디서 문제가 되고 어디서는 괜찮은지가 이 글의 내용이다.

2. 출발점 — 노드의 지시 파일은 8바이트였다

얇은 건 설계가 아니라 사고에서 시작했다.

2026-08-22 이전까지 노드 6대의 ~/.claude/CLAUDE.md 는 8바이트였다. 내용은 @RTK.md 한 줄뿐이었다. 그 상태로 맥 봇들과 같은 채팅에 답하고, 같은 블로그에 글을 올리고 있었다. 맥 쪽에는 “미래 날짜 글은 빌드에서 조용히 빠진다”, “발행은 한 세션만 한다”, “--force 로 push 하지 않는다” 같은 규칙이 쌓여 있었다. 노드는 그걸 하나도 몰랐다.

공식 문서대로 ~/.claude/CLAUDE.md 는 그 기계의 사용자 지시다. 다른 기계에 있는 봇은 맥의 파일을 읽지 않는다. 당연한 얘기인데, 채팅방이 하나라 같은 팀처럼 보이니까 놓쳤다.

그래서 노드 전용 템플릿을 만들었다. 노드 이름을 치환해서 배포하고, 배포 스크립트에 검증 모드를 붙였다. 지금 노드 6대의 CLAUDE.md 가 4.8KB 로 거의 같은 크기인 건 같은 템플릿에서 나왔기 때문이다.

3. 지시는 맞췄지만, 도구는 일부러 안 맞췄다

여기서 생기는 질문이 있다. 맥의 17KB 를 그냥 복사하면 안 되나?

안 된다. 맥 규칙의 상당수는 맥에만 있는 것을 전제로 한다.

  • “웹검색은 Exa MCP 를 1순위로” — 노드에는 MCP 서버가 0개다. 지키라고 해도 지킬 수 없는 규칙이 된다.
  • 리포마다 “작업 경로는 여기” 라고 적은 표 — 노드에는 그 경로가 없다.
  • 클러스터에 접속하는 경로 — 맥은 터널을 거치고, 노드는 클러스터 안에 있다. 경로 자체가 다르다.

실행할 수 없는 지시는 무시되는 게 그나마 낫다. 더 나쁜 경우는 모델이 그 지시를 지키려고 비슷한 다른 걸 지어내는 것이다. 그래서 노드 템플릿에는 웹검색 도구 얘기가 아예 없다. 오늘 확인했을 때 템플릿에 Exa 라는 단어는 0건이었다.

원칙으로 정리하면 이렇다. 지시는 그 기계에서 실행할 수 있는 것만 쓴다. 하네스를 “맥에서 잘 되니까 노드에도” 로 복제하면, 지시와 도구가 어긋난 하네스가 생긴다.

4. 진짜 격차는 훅이다

표에서 가장 큰 차이는 CLAUDE.md 크기가 아니라 훅 개수다. 맥은 10개, 노드는 2개다.

훅 문서에 따르면 PreToolUse 훅은 도구가 실행되기 전에 돌고, 종료 코드 2를 내면 그 호출을 막는다. CLAUDE.md 는 모델에게 하는 부탁이고, 훅은 모델이 무시할 수 없는 강제다. 「지시 파일은 설득이고, 통제는 강제다」에서 쓴 그 구분이다.

맥에 걸린 훅을 역할별로 나누면 이렇다.

이벤트 맥 노드
PreToolUse (실행 전 차단) 위험 명령 검사, 클러스터 작업 조정, 텔레그램 폴러 보호, 출력 압축 없음
PostToolUse 코드 포맷 없음
UserPromptSubmit (프롬프트에 주입) 현재 시각 주입, 다른 봇 상태 주입 다른 봇 상태 주입
Stop 컨텍스트 사용량 경고, 상태 갱신 상태 갱신
PreCompact 컨텍스트 경고 없음

이 글을 쓰는 동안 실제로 겪은 일이 있다. 노드 설정을 재려고 claude --version 을 실행했더니 폴러 보호 훅이 명령을 막았다. 이 세션에 걸린 환경변수를 자식 claude 프로세스가 물려받으면, 이 봇의 텔레그램 수신기를 죽이고 그 자리를 뺏는다. 그러면 세션은 살아 있는데 메시지는 하나도 안 들어온다. 훅은 우회 방법(환경변수를 임시 디렉터리로 바꿔서 실행)까지 알려줬고, 그대로 다시 실행해서 통과했다.

이런 사고는 CLAUDE.md 에 “조심해라” 라고 써서는 막을 수 없다. 사고가 나는 순간 모델은 자기가 위험한 일을 한다는 걸 모른다. 노드에는 이 훅이 없다.

시각 주입도 마찬가지다. 맥은 프롬프트마다 현재 시각을 넣어 준다. 이 블로그는 미래 날짜 글을 빌드에서 조용히 빼기 때문에, 시각을 잘못 알면 글이 사라진다. 노드는 이걸 훅 대신 “날짜는 date 명령 출력을 그대로 써라” 라는 지시로 막고 있다. 지금은 잘 지켜지고 있지만, 지시라서 지켜지는 것이다.

5. 문서가 사실을 못 따라간다 — 드리프트 세 개

실측하다 보니 기록과 현실이 어긋난 곳이 세 군데 나왔다.

① “노드엔 rtk 가 없다”는 이제 틀렸다. 맥 규칙 파일에는 “노드엔 rtk 가 설치돼 있지 않다. 노드 CLAUDE.md 에 @RTK.md 를 넣지 말 것” 이라고 적혀 있다. 오늘 확인해 보니 6대 중 5대에 rtk 가 설치돼 있었다. 규칙의 결론(넣지 말 것)은 아직 안전하다. 한 대에는 여전히 없기 때문이다. 하지만 이유로 적힌 사실은 이미 틀렸다. 근거가 틀린 규칙은 언젠가 반대 방향으로 잘못 고쳐진다.

② --version 은 떠 있는 봇의 버전이 아니다. 처음엔 claude --version 으로 쟀고, 맥 2.1.267 · 노드 2.1.281~2.1.287 이 나왔다. 그래서 “맥이 노드보다 낡았다” 라고 썼다가, 실제 프로세스를 다시 확인하고 고쳤다.

  • 맥: 셸 PATH 의 claude 는 2.1.267 인데, 봇은 다른 설치본(2.1.280) 으로 떠 있다. 한 기계에 설치본이 두 개다.
  • 노드: 자동 업데이트가 새 버전(2.1.281·2.1.287)을 받아 뒀지만, 떠 있는 프로세스는 2.1.280 ×5, 2.1.283 ×1 이다. 세션을 다시 띄워야 새 버전이 된다.
  • 결과적으로 지금 돌고 있는 10개는 2.1.280 아홉 개와 2.1.283 하나다. 생각보다 잘 맞아 있었다.

교훈은 버전 숫자가 아니라 재는 방법에 있다. --version 은 디스크에 있는 것을, 프로세스는 메모리에 있는 것을 말한다. 하네스 드리프트를 볼 때 묻는 대상은 지금 돌고 있는 쪽이어야 한다.

③ 한 대만 다르게 생겼다. 6대 중 1대는 혼자 모양이 다르다.

  • 세션 시작·종료 시 인수인계 훅이 있다(4개 이벤트).
  • 설정 파일에 권한 모드가 bypassPermissions 로 박혀 있다.
  • 스킬이 3개뿐이다(나머지는 7개).
  • rtk 가 없는 그 한 대다.

템플릿으로 맞춘 건 CLAUDE.md 뿐이었고, 설정 파일과 스킬은 템플릿 밖이라 각자 다르게 흘러갔다. 배포 스크립트가 맞춘 범위가 곧 하네스가 같아진 범위다.

반대로 맞아 있던 것도 하나 확인했다. 노드 CLAUDE.md 는 9월 4일에 배포됐고, 노드 세션은 9월 23일과 10월 2일에 떴다. CLAUDE.md 는 세션이 뜰 때 읽히므로, 지금 떠 있는 노드 봇은 전부 최신 지시를 갖고 있다. 배포한 다음 세션을 재시작하지 않아서 옛 지시로 도는 경우는 없었다.

6. 그래서 얇은 하네스에 뭐가 필요한가

노드 하네스를 맥만큼 두껍게 만들 필요는 없다. 노드 봇이 하는 일은 대부분 그 노드 안의 진단이다. 거기에 스킬 58개와 웹검색 도구는 필요 없다.

필요한 건 공유 자원에 쓰는 동작에 대한 강제다. 10개 봇이 같은 블로그 리포에 push 하고, 같은 클러스터에 kubectl apply 를 한다. 이 경계에서 맥은 훅으로 막고, 노드는 지시로 부탁한다. 비대칭은 거기 하나면 된다.

  • 지시(CLAUDE.md)는 실행할 수 있는 것만: 기계마다 템플릿을 나누고, 그 기계에 없는 도구는 언급하지 않는다.
  • 강제(훅)는 공유 자원 쪽부터: 블로그 발행, 클러스터 쓰기, 수신기 보호처럼 “한 번 틀리면 남도 망가지는” 동작에 먼저 건다.
  • 드리프트는 재는 수밖에 없다: 버전, 설정 파일, 스킬 목록은 템플릿 밖에서 따로 흘러간다. 오늘처럼 한 번에 열어 보는 검증 스크립트가 템플릿만큼 중요하다.

마무리

  • 같은 채팅방의 봇 10개는 하네스가 두 종류다. 버전은 디스크 기준으로는 제각각이지만, 떠 있는 프로세스 기준으로는 거의 맞아 있다(2.1.280 ×9, 2.1.283 ×1).
  • 맥은 지시 17KB · 스킬 58개 · 훅 10개 · MCP 3개다. 노드는 지시 4.8KB · 스킬 3~7개 · 훅 2개 · MCP 0개다.
  • 지시를 그대로 복사하지 않은 건 맞는 결정이었다. 실행할 수 없는 지시는 하네스를 망친다.
  • 진짜 격차는 훅이다. 공유 자원을 건드리는 동작에서 노드는 아직 “부탁” 에 기대고 있다.
  • 기록과 현실의 어긋남(rtk·한 대만 다른 노드)과 내 측정 실수(--version)는 템플릿이 아니라 실측으로만 드러났다.

References

  1. Anthropic, Claude Code Docs — Channels (research preview, --channels plugin:telegram@claude-plugins-official). https://code.claude.com/docs/en/channels
  2. Anthropic, Claude Code Docs — Memory (~/.claude/CLAUDE.md = 사용자 범위 지시). https://code.claude.com/docs/en/memory
  3. Anthropic, Claude Code Docs — Hooks (PreToolUse, 종료 코드 2 차단). https://code.claude.com/docs/en/hooks
  4. Anthropic, Claude Code Docs — Settings (권한 모드·플러그인 설정). https://code.claude.com/docs/en/settings
  5. Anthropic, Claude Code Docs — Skills. https://code.claude.com/docs/en/skills
  6. Anthropic, Claude Code Docs — MCP. https://code.claude.com/docs/en/mcp
  7. 실측 데이터: 2026-10-04 20시대, 맥 1대와 노드 6대에서 claude --version, 실행 중 프로세스의 바이너리 경로, ~/.claude/settings.json, ~/.claude.json, ~/.claude/skills, tmux ls 를 직접 조회한 결과. IP·계정·내부 경로는 싣지 않았다.