서로 다른 머신에서 돌아가는 Claude Code 세션끼리 질문을 푸쉬하고 답을 받는 시스템입니다.
Claude Code의 Channels(리서치 프리뷰)를 사용했습니다.
사내에서 협업하다 발생한 게으름을 단순 아이디어로 사용하여, 클로드를 이용하여 100% 구현하였습니다.
문제
내 레포는 내가 잘 알고, 옆 팀 레포는 그쪽이 잘 압니다. 지금은 그 간극을 Slack과
복붙으로 메웁니다. "billing-api 쪽 재시도 정책이 어디 정의돼 있어?"라고 물으면,
그 레포에 띄워 둔 동료의 Claude가 코드를 직접 읽고 파일:라인
까지 붙여 답합니다.
동작 방식
- 개발자 머신마다 Claude Code 세션이 뜨고, 세션당 채널 서버(MCP) 하나가 stdio로 붙습니다
- 채널 서버는 브로커로
나가는wss 연결만 맺습니다 — 개발자 머신에 인바운드 포트가 필요 없습니다 - 노트북이 NAT 뒤에 있든 VPN을 오가든 상관없고, 방화벽 예외도 없습니다
- 푸쉬는 이미 열려 있는 WebSocket을 타고 거꾸로 내려옵니다
- 브로커는 파이썬 단일 인스턴스 + SQLite. 요청은 REST, 푸쉬는 WebSocket입니다
ask_peer
는 즉시 반환합니다. 답을 기다리며 블로킹하지 않고, 나중에 채널 이벤트로 도착합니다
Claude Code의 네이티브 세션 간 메시징과 뭐가 다른가
Claude Code에 cross-session messaging(/list-agents
, SendMessage
)이 이미 있습니다.
같은 머신이면 그쪽이 훨씬 간단하니 그걸 쓰시면 됩니다. 이 프로젝트가 남는 자리는 이렇습니다.
**다른 사람, 다른 계정.**네이티브는 "your other sessions" — 내 계정, 내 OS 유저의
세션만 잇습니다. 백엔드 개발자 노트북과 프론트 개발자 노트북은 두 계정이라 안 됩니다.**자체 인프라.**네이티브의 크로스 머신 전달은 Anthropic 서버를 경유합니다.
이건 사내 브로커 안에서 끝납니다.**Bedrock / Vertex / Foundry.**네이티브 크로스 머신은 claude.ai 로그인이 필요해서
이 환경들에서는 동작하지 않습니다.**VPN 없이.**비슷한 목적의 기존 프로젝트들은 양쪽이 서로 HTTP로 닿아야 해서
Tailscale 같은 걸 요구합니다. 릴레이 구조라 필요 없습니다.
브로커가 강제하는 것
Claude끼리 자유롭게 묻게 두면 곧바로 문제가 됩니다. 클라이언트를 믿지 않고 전부 서버에서 막았습니다.
무한 전파— 열린 질문의 hops 최댓값 + 1로 깊이를 서버가 계산합니다.
클라이언트가 hops를 보내지 않습니다. 보내게 두면 누구나 0으로 위조합니다. 기본 상한 1핑퐁— 나에게 열린 질문을 보낸 세션에게 되묻는 것을 422로 막고,reply
에 담으라고 안내영원히 기다리기— 질문 TTL 15분, 만료되면 질문자에게 notice를 푸쉬하고 늦은 답은 410질문 폭주— 10분 창으로 사용자당·상대당 rate limit. Claude는 사람보다 훨씬 빨리 질문합니다컨텍스트 유출— 질문 4000자 / 컨텍스트 12000자 / 답변 16000자
messages
테이블 하나가 큐이자 감사 로그입니다. 전달 상태와 감사 기록이 갈라지면
둘 중 하나는 반드시 틀리기 때문에 따로 만들지 않았습니다.
보안
- 채널 본문은
다른 사람의 Claude가 쓴 신뢰할 수 없는 입력입니다. 프롬프트 인젝션 경로입니다 - 방어 세 겹: 서버 instructions, 스킬 규칙, 그리고
응답 전용 세션의 도구 제한 - 앞의 둘은 모델의 판단에 기대지만 세 번째는 아닙니다.
--disallowedTools
로
Bash/Edit/Write를 막아 두면 본문이 무엇을 시키든 할 수 없는 일입니다 - permission relay(
claude/channel/permission
)는일부러 선언하지 않았습니다.
선언하면 채널로 메시지를 보낼 수 있는 사람이 내 세션의 도구 사용을 승인할 수 있게 됩니다 - 토큰은 SHA-256 해시만 저장합니다
한계
**이론상 남의 클로드를 빌려 사용할 수 있습니다.**프롬프트 인젝션에 취약할 것 같습니다.리서치 프리뷰 기능입니다.--channels
플래그와 프로토콜이 바뀔 수 있습니다.
그래서 로직은 전부 브로커에 두고 채널 서버는 200줄로 얇게 유지했습니다.
프로토콜이 바뀌면 그 200줄만 고치면 되고 정책과 감사 기록은 남습니다**브로커는 단일 인스턴스여야 합니다.**presence와 rate limit 카운터가 메모리에 있어서,
2대를 띄우면 서로 다른 인스턴스에 붙은 세션끼리는 보이지 않습니다.
이중화하려면 sessions dict와 push()를 Redis pub/sub으로 옮기는 것이 첫 순서입니다**방은 접근 통제가 아닙니다.**멤버 목록도 초대도 없고, 이름을 아는 사람은 누구나 들어옵니다.
대화 맥락을 묶는 수단일 뿐입니다- 푸쉬는 세션이 열려 있을 때만 도착합니다. 놓친 것은
check_inbox
로 받습니다 - 모든 질문과 답변이 브로커 DB에 남습니다. 감사 로그이자 프라이버시 고려사항입니다
돌려보기
브로커 없이 로컬에서 먼저 확인할 수 있습니다. 저장소 루트를 로컬 마켓플레이스로 등록하면
캐시가 아니라 원본 경로의 server.py를 직접 실행하므로, 고치고 새 세션만 띄우면 반영됩니다.
E2E 테스트가 브로커와 채널 서버 여러 개를 실제로 띄우고 가짜 Claude Code로 16개 시나리오를
돌립니다 — 푸쉬 왕복, 중복 답변 409, 남의 질문 403, hops 422, 핑퐁 422, TTL 만료와 늦은 답 410,
세션 재시작 후 재전달, rate limit 429 등. 모킹이 아니라 진짜 stdio 연결입니다.
문서는 용도별로 나눠 두었습니다 — USAGE(사용), MARKETPLACE(배포), OPERATIONS(운영),
ARCHITECTURE(설계 결정), INTERNALS(인프라와 메시지 흐름).