게이트웨이는 serve 데몬 안에서 메신저 메시지를 받아 GEODE 실행으로 넘기는 라우터입니다. Slack Socket Mode와 플랫폼 poller가 메시지를 받고, binding이 어느 채널을 받을지 결정하며, lane queue가 동시성을 제한합니다. 라우팅은 정적 규칙만 씁니다.
동작 구조
| 구성 요소 | 역할 | 코드 |
|---|---|---|
| 메신저 receiver | Slack은 Socket Mode push를 바운드 큐에 넣은 뒤 ACK하고 처리합니다(큐가 가득 차면 unACK로 Slack 재전송). Discord와 Telegram은 주기적으로 조회합니다. 공통 스레드 수명주기는 BasePoller가 가집니다. | core/server/supervised/ |
| ChannelManager | binding 규칙으로 인바운드 메시지를 라우팅합니다. channel과 channel_id가 정확히 일치해야 통과합니다. | core/messaging/binding.py |
| LaneQueue | 세션 키 단위 직렬화와 전역 동시성 상한입니다. 모든 실행 경로가 SessionLane과 global lane을 차례로 통과합니다. | core/orchestration/lane_queue.py |
| CLIPoller | thin CLI의 IPC 요청을 받는 데몬 쪽 서버입니다. 메신저 receiver와 같은 lane 규칙을 따릅니다. | core/server/ipc_server/poller.py |
receiver는 플랫폼 payload 전체를 넘기지 않고 필요한 필드만 geode.gateway.v1 InboundMessage로 투영합니다. 본문은 64 KiB, JSON metadata는 32 KiB로 제한되고, 플랫폼 메시지 ID가 응답 처리까지 상관관계 ID로 전달됩니다. 알 수 없는 upstream 필드는 이 투영 경계에서 무시됩니다.
데몬 모드 세션은 headless이므로 승인을 받을 사용자가 없습니다. 그래서 run_bash와 delegate_task는 게이트웨이 경로에서 차단됩니다 (core/server/supervised/services.py).
시작과 종료
geode serve는 gateway_enabled가 꺼져도 CLI IPC와 스케줄러를 시작합니다. 외부 채널도 운영하려면~/.geode/.env에 GEODE_GATEWAY_ENABLED=true를 추가합니다. 대화만 한다면 bare geode가 데몬을 자동으로 시작합니다.
# 게이트웨이 켜기 echo 'GEODE_GATEWAY_ENABLED=true' >> ~/.geode/.env geode serve # 포그라운드, --poll은 poll 기반 receiver 주기 # 살아 있는지 확인 pgrep -f "geode serve" # 재시작 (설정 변경 후) pkill -f "geode serve" geode serve &
종료는 단계적입니다. SHUTDOWN_STARTED 훅 발화, 신규 연결 차단, 활성 세션 30초 drain, 스케줄러 저장과 정지, MCP 종료, 게이트웨이 정지 순서입니다 (core/cli/typer_serve.py).
binding 설정
어느 채널이 GEODE를 깨울 수 있는지는 binding 규칙이 결정합니다. 규칙 작성법은 바인딩 설정 가이드에서 다루고, 형식만 요약하면 이렇습니다.
# .geode/config.toml [gateway] pollers = ["slack"] # 띄울 receiver 등록명 time_budget_s = 120 # 메시지당 wall-clock 기본값 [[gateway.bindings.rules]] channel = "slack" channel_id = "C0ABCDEF1" # 필수. 비어 있으면 규칙이 건너뜀 require_mention = true
실환경 검증
2026-08-17의 PR #3007 head를 Slack Socket Mode에서 직접 실행했다. 일상 대화는 도구 없이 답했고, browser DOM 경로는 실제 example.com 탭과 제목을 확인했다. Strict pixel computer_use는 캡처에는 성공했지만 OpenAI subscription source에 호환 visual grounding이 없어 좌표를 추측하지 않고 중단했다. 공개 E2E 영수증은 세 결과와 raw evidence digest를 보존한다. Primary 답변은 Codex OAuth subscription이었지만 post-turn GLM PAYG 호출도 관측돼 전체 lifecycle은 subscription-only가 아니다.
실패 모드
| 증상 | 원인 | 해법 |
|---|---|---|
| 외부 채널 메시지가 들어오지 않음 | gateway_enabled 꺼짐 | CLI IPC는 계속 동작합니다. 외부 채널도 쓰려면 GEODE_GATEWAY_ENABLED=true를 설정합니다. |
| 메시지에 반응이 없음 | binding 불일치, 앱 토큰 누락, 또는 채널 멤버십 없음 | geode doctor slack으로 점검하고, 출력된 링크의 채널에서 /invite @geode를 실행합니다. |
| 배너 모델과 응답 모델이 다름 | 데몬이 둘 이상 떠서 소켓을 두고 경합 | pkill -f "geode serve"로 전부 내린 뒤 하나만 다시 띄웁니다. ps aux | grep은 경로가 잘려 빈 결과가 나오므로 pgrep -f를 씁니다. |
| 같은 채널 요청이 밀림 | 같은 세션 키는 의도적으로 직렬화 | 정상 동작입니다. 다른 스레드나 채널로 보내면 병렬로 처리됩니다. |
Receivers do not forward whole platform payloads. They select the required fields into a geode.gateway.v1 InboundMessage. Content is capped at 64 KiB, JSON metadata at 32 KiB, and the platform message ID remains the correlation ID through response processing. Unknown upstream fields are ignored at this projection boundary.
데몬 로그는 ~/.geode/logs/serve.log에 10MB 단위 5개 파일로 로테이션됩니다 (core/observability/logging_config.py).