Signal 설정
Hermes는 HTTP 모드로 동작하는 signal-cli daemon을 통해 Signal에 연결됩니다. Adapter는 SSE (Server-Sent Events)로 메시지를 실시간 스트리밍하고 JSON-RPC로 응답을 전송합니다.
Signal은 가장 프라이버시 중심적인 주류 messenger입니다 — 기본 end-to-end 암호화, open-source 프로토콜, 최소 메타데이터 수집. 보안에 민감한 agent workflow에 이상적입니다.
Signal adapter는 모든 통신에 httpx (이미 Hermes 핵심 dependency)를 사용합니다. 추가 Python 패키지 불필요. signal-cli만 외부에 설치하면 됩니다.
사전 요구사항
- signal-cli — Java 기반 Signal client (GitHub)
- Java 17+ runtime — signal-cli가 요구
- 전화번호 Signal 설치된 것 (보조 기기로 linking)
signal-cli 설치
# macOS
brew install signal-cli
# Linux (download latest release)
VERSION=$(curl -Ls -o /dev/null -w %{url_effective} \
https://github.com/AsamK/signal-cli/releases/latest | sed 's/^.*\/v//')
curl -L -O "https://github.com/AsamK/signal-cli/releases/download/v${VERSION}/signal-cli-${VERSION}.tar.gz"
sudo tar xf "signal-cli-${VERSION}.tar.gz" -C /opt
sudo ln -sf "/opt/signal-cli-${VERSION}/bin/signal-cli" /usr/local/bin/
signal-cli는 apt나 snap repository에 없음. 위 Linux 설치는 GitHub releases에서 직접 다운로드합니다.
Step 1: Signal 계정 linking
signal-cli는 linked device로 동작합니다 — WhatsApp Web과 비슷하지만 Signal용. 폰이 주 기기로 유지됩니다.
# Generate a linking URI (displays a QR code or link)
signal-cli link -n "HermesAgent"
- 폰에서 Signal 열기
- Settings → Linked Devices 이동
- Link New Device 탭
- QR code 스캔 또는 URI 입력
Step 2: signal-cli daemon 시작
# Replace +1234567890 with your Signal phone number (E.164 format)
signal-cli --account +1234567890 daemon --http 127.0.0.1:8080
백그라운드에서 계속 실행. systemd, tmux, screen 사용하거나 서비스로 실행 가능.
실행 확인:
curl http://127.0.0.1:8080/api/v1/check
# Should return: {"versions":{"signal-cli":...}}
Step 3: Hermes 구성
가장 쉬운 방법:
hermes gateway setup
플랫폼 메뉴에서 Signal 선택. Wizard가 수행:
- signal-cli 설치 여부 확인
- HTTP URL 입력 요청 (기본값:
http://127.0.0.1:8080) - Daemon 연결 테스트
- 계정 전화번호 요청
- 허용 사용자 및 access policy 구성
수동 구성
~/.hermes/.env에 추가:
# Required
SIGNAL_HTTP_URL=http://127.0.0.1:8080
SIGNAL_ACCOUNT=+1234567890
# Security (recommended)
SIGNAL_ALLOWED_USERS=+1234567890,+0987654321 # Comma-separated E.164 numbers or UUIDs
# Optional
SIGNAL_GROUP_ALLOWED_USERS=groupId1,groupId2 # Enable groups (omit to disable, * for all)
SIGNAL_HOME_CHANNEL=+1234567890 # Default delivery target for cron jobs
Gateway 시작:
hermes gateway # Foreground
hermes gateway install # Install as a user service
sudo hermes gateway install --system # Linux only: boot-time system service
Access Control
DM 접근
DM 접근은 다른 모든 Hermes 플랫폼과 동일한 패턴:
SIGNAL_ALLOWED_USERS설정 → 해당 사용자만 메시지 가능- Allowlist 미설정 → 알 수 없는 사용자는 DM pairing code 수신 (
hermes pairing approve signal CODE으로 승인) SIGNAL_ALLOW_ALL_USERS=true→ 누구나 메시지 가능 (주의해서 사용)
Group 접근
Group 접근은 SIGNAL_GROUP_ALLOWED_USERS 환경 변수로 제어:
| 구성 | 동작 |
|---|---|
| 미설정 (기본값) | 모든 group 메시지 무시. Bot은 DM에만 응답. |
| Group ID 설정 | 나열된 group만 모니터링 (예: groupId1,groupId2). |
*로 설정 | Bot이 소속된 모든 group에 응답. |
기능
첨부파일
Adapter는 양방향 미디어 송수신 지원.
수신 (사용자 → agent):
- 이미지 — PNG, JPEG, GIF, WebP (매직 바이트로 자동 감지)
- 오디오 — MP3, OGG, WAV, (Whisper 구성 시 음성 메시지 transcribe)
- 문서 — PDF, ZIP, 기타 파일 타입
송신 (agent → 사용자):
Agent는 응답 내 MEDIA: tag로 미디어 파일 전송 가능. 지원 전송 방식:
- 이미지 —
send_multiple_images및send_image_file은 PNG, JPEG, GIF, WebP를 native Signal 첨부파일로 전송 - 음성 —
send_voice은 오디오 파일 (OGG, MP3, WAV, AAC)을 첨부파일로 전송 - 비디오 —
send_video은 MP4 비디오 파일 전송 - 문서 —
send_document은 모든 파일 타입 (PDF, ZIP 등) 전송
모든 송신 미디어는 Signal 표준 첨부파일 API 경유. 일부 플랫폼과 달리 Signal은 프로토콜 수준에서 음성 메시지와 파일 첨부를 구분하지 않습니다.
첨부파일 크기 제한: 100 MB (양방향).
Signal 서버는 첨부파일 업로드 rate-limit 적용, adapter는 다중 이미지 전송용 스케줄러로 이미지를 32개 그룹으로 묶고 Signal 서버 정책에 맞게 업로드를 throttle 합니다.
Native 서식, Reply Quote, 리액션
Signal 메시지는 리터럴 markdown 문자 대신 native 서식으로 렌더링됩니다. Adapter는 markdown (**bold**, *italic*, code, ~~strike~~, ||spoiler||, 헤딩)을 Signal bodyRanges로 변환해서 텍스트가 수신자 client에 보이는 ** / ` 문자로 나타나지 않고 실제 스타일로 표시됩니다.
Reply quote. Hermes가 특정 메시지에 답장할 때 원본을 인용하는 native reply 게시 — Signal 사용자가 직접 "Reply" 사용 시 보는 UI와 동일. 수신 메시지에 대한 응답은 자동 적용.
리액션. Agent는 표준 reaction API로 메시지에 반응 가능; 리액션은 추가 텍스트가 아니라 참조된 메시지의 emoji 리액션으로 Signal에 표시.
추가 구성 불필요 — 최신 signal-cli 빌드에서 기본 활성화. signal-cli 버전이 너무 오래되면 Hermes는 plaintext 전송으로 fallback하고 일회성 경고를 로그.
Typing Indicator
Bot은 메시지 처리 중 typing indicator 전송, 8초마다 갱신.
전화번호 마스킹
모든 전화번호는 로그에서 자동 마스킹:
+15551234567→+155****4567- Hermes gateway 로그와 전역 마스킹 시스템 모두 적용
Note to Self (단일 번호 설정)
별도 bot 번호 대신 본인 전화번호로 signal-cli를 linked 보조 기기로 실행하면 Signal "Note to Self" 기능으로 Hermes와 상호작용 가능.
폰에서 본인에게 메시지 전송 — signal-cli가 수신하고 Hermes가 같은 대화에서 응답.
동작 방식:
- "Note to Self" 메시지는
syncMessage.sentMessageenvelope로 도착 - Adapter는 이것이 bot 자체 계정 대상임을 감지하고 일반 수신 메시지로 처리
- Echo-back 보호 (sent-timestamp tracking)가 무한 루프 방지 — bot 자체 응답은 자동 필터링
추가 구성 불필요. SIGNAL_ACCOUNT이 폰 번호와 일치하기만 하면 자동 작동.
Health 모니터링
Adapter는 SSE 연결을 모니터링하고 다음 경우 자동 재연결:
- 연결 끊김 (exponential backoff: 2s → 60s)
- 120초 동안 활동 미감지 (signal-cli에 ping으로 확인)
문제 해결
| 문제 | 해결 |
|---|---|
| 설정 중 "Cannot reach signal-cli" | signal-cli daemon 실행 확인: signal-cli --account +YOUR_NUMBER daemon --http 127.0.0.1:8080 |
| 메시지 수신 안 됨 | SIGNAL_ALLOWED_USERS에 발신자 번호가 E.164 형식 (+ 접두사 포함)으로 포함되어 있는지 확인 |
| "signal-cli not found on PATH" | signal-cli 설치 후 PATH에 추가, 또는 Docker 사용 |
| 연결 계속 끊김 | signal-cli 로그에서 오류 확인. Java 17+ 설치 확인. |
| Group 메시지 무시됨 | 특정 group ID로 SIGNAL_GROUP_ALLOWED_USERS 구성, 또는 *로 모든 group 허용. |
| Bot이 아무에게도 응답 안 함 | SIGNAL_ALLOWED_USERS 구성, DM pairing 사용, 또는 광범위 접근 원하면 gateway policy로 모든 사용자 명시적 허용. |
| 중복 메시지 | 폰 번호로 단일 signal-cli 인스턴스만 수신 중인지 확인 |
보안
반드시 access control 구성. Bot은 기본적으로 terminal 접근 권한 보유. SIGNAL_ALLOWED_USERS 또는 DM pairing 없으면 gateway가 안전 조치로 모든 수신 메시지 거부.
- 전화번호는 모든 로그 출력에서 마스킹
- 신규 사용자 안전 온보딩에 DM pairing 또는 명시적 allowlist 사용
- Group 지원이 특별히 필요하지 않으면 group 비활성화 유지, 또는 신뢰하는 group만 allowlist
- Signal의 end-to-end 암호화가 전송 중 메시지 내용 보호
~/.local/share/signal-cli/의 signal-cli 세션 데이터는 계정 자격증명 포함 — 비밀번호처럼 보호
환경 변수 레퍼런스
| 변수 | 필수 | 기본값 | 설명 |
|---|---|---|---|
SIGNAL_HTTP_URL | 예 | — | signal-cli HTTP endpoint |
SIGNAL_ACCOUNT | 예 | — | Bot 전화번호 (E.164) |
SIGNAL_ALLOWED_USERS | No | — | 쉼표 구분 전화번호/UUID |
SIGNAL_GROUP_ALLOWED_USERS | No | — | 모니터링할 group ID, 또는 모두 허용 시 * (group 비활성화 시 생략) |
SIGNAL_ALLOW_ALL_USERS | No | false | 모든 사용자 상호작용 허용 (allowlist 우회) |
SIGNAL_HOME_CHANNEL | No | — | Cron 작업용 기본 전송 대상 |