Telegram / Discord 봇을 Claude Code가 실행 중인 tmux 세션과 연결해, 원격으로 범용 bot 모드 스킬 (plan-review 등) 을 사용하기 위한 Rust 브리지 서비스.
- 데스크탑 앞에 없을 때도 스킬을 돌리고 싶다.
- Claude Code는 tmux 안에서 돌고, 봇은 SSH 경유로 파일을 읽고
tmux send-keys로 키를 주입하는 브리지 역할. - 봇은 투명 통과 러너 —
{name}+{task}만 주입하고 나머지는 사용자 입력 그대로 통과. 분기 로직은 스킬 본문에서 Claude가 처리.
[사용자(Telegram / Discord)]
│ 메시지 / document
▼
[봇 서버] ──────── SSH (tmux send-keys) ───────► [Claude tmux 세션]
│ ▲ │
│ │ │ 출력 파일 갱신
│ │ ▼
│ └─ SSH polling (stat/read, 2s) ──────── [Claude 호스트 파일]
│
└─ attach 시 target SSH → SKILL.md lazy 로드 → manifest 파싱
PromptWatcher: tmux pane visible 캡처 2s 주기, prev/cur 전체 String 동등 비교 + 동일 캡처 3-tick 누적 시 대기 확정 → streaming 메시지 갱신 (마지막 변경 인덱스 기준 visible 위쪽 N줄, footer 자동 회피), 확정 시 waiting 메시지로 마감.
OutputWatcher: 파일 변경 감지 시 pending 누적 → 대기 감지(WaitingDetected) 시점에 최종본 한 번에 전송.
화면 캡처 수동 조회는 /snap (무인자=visible pane, N=scrollback 포함 최근 N줄).
자세한 설계: docs/architecture.md
배포 가이드: docs/deploy.md
- 단일 owner 인증 (Telegram user id / Discord user id)
- 다중 백엔드 — Telegram·Discord 동시 운영 가능.
default_bot으로 기본 백엔드 지정 boot.json평문 설정 +secrets_blobAES-256-GCM 암호화 +/unlock복호화 플로우- SSH target 관리 (
/target add/list/rm/default) — key_file · password · ssh_agent - 다중 target 등록, 활성 세션 1개
- 스킬 lazy 로드 —
/attach·/use시 target SSH로cat {skill_root}/{skill}/SKILL.md→ manifest 파싱 (봇 서버에 파일 불필요) - 투명 통과 invoke — 봇은
{name}+{task}만 주입하고 나머지는 사용자 입력 원문 그대로 전달 - task 멱등 관리 —
/task start가 기존 파일 있으면 자동 resume - Streaming 메시지 — invoke/reply 직후
⏳ Agent 작업중...메시지 시작 → 2s 주기 visible pane 캡처를 prev/cur 전체 String 동등 비교, 변동 시 마지막 변경 인덱스 기준 visible 위쪽 N줄 로 갱신 (footer 자동 회피, 변경량과 무관하게 항상 N줄 → 메시지 출렁거림 방지) → 동일 캡처 3-tick 누적되면 대기 확정, 상단(Collapsible) + tail(CodeBlock) 청크로 마감. Telegram:<blockquote expandable>+<pre>, Discord:>인용 + 코드블록 (N=boot.watcher_tail_lines, 표시 전용 tail 길이, 기본 10) - 대기 시점 flush — 출력 파일 변경은 pending에 누적 → Claude 대기 상태 도달 시 최종본 한 번에 전송 (작업 중 중간본 전송 없음)
/open·/kill로 원격 tmux 세션 수명 제어 (프로파일 기반 agent 자동 실행)- 재시작 시
active복원 (잠금 해제 후 target SSH로 SKILL.md 재로드)
- 빌드 —
cargo build --release /opt/kkuepark/gecko_dev/에 바이너리 설치 후 실행 →boot.json템플릿 자동 생성bots.telegram.bot_token·owner_chat_id(또는 Discord 설정) 편집 후 재실행- Telegram(
/cmd) 또는 Discord(!cmd)에서:/ping (Discord: !ping) ← pong 확인 /unlock <pp> ← 첫 실행이면 임의 passphrase /target add work me@host:22 key_file ~/.ssh/id_ed25519 /target default work /open myproj [profile] ← 원격 세션 생성 + agent 실행 (또는 /attach) /task start feature-x ← 작업 시작 (기존 파일 있으면 자동 resume) /invoke plan 목표: HTTP 서버 ← 스킬 실행 (task 자동 주입, 목표: 는 스킬 규약) /task done ← 작업 종료 + 출력 파일 rename
#N (N=0..=9) — boot.json aliases 의 N번 시퀀스를 실행. ; 으로 구분된 토큰을 1s 간격으로 순차 주입.
등록/삭제: boot.json 직접 편집 후 재시작 필요 (런타임 reload 없음). 조회: /alias 명령.
@는 Discord 멘션(<@user_id>) syntax 와 충돌해 봇이 이벤트로 못 받음.#은 양쪽 백엔드 공통.
alias body 는 텔레그램 식 prefix 통일 (/cmd, //cmd, 자유텍스트). Discord 백엔드 사용자도 alias body 에는 !cmd / !!cmd 가 아니라 /cmd / //cmd 로 작성. 토큰 분류기는 backend 무관하게 텔레그램 룰로 동작.
동시 실행 한계 — alias 시퀀스는 tokio::spawn 으로 떼어내 1s delay 동안 다른 inbound 를 막지 않음. 사용자가 alias 진행 중에 또 다른 alias 트리거 시 두 sequence 가 병행되며 streaming slot 은 마지막 set 만 take — 첫 sequence 의 waiting 메시지 마감이 묻힐 수 있다. 봇 측 동시성 제어 없음, 사용자가 alias 종료 후 다음 트리거 보내는 운영을 권장.
명령 prefix: Telegram
/cmd, Discord!cmd.#N(N=0..=9) 트리거는 양쪽 백엔드 공통 (prefix 없음).
| 명령 | 설명 | 잠금 필요 |
|---|---|---|
ping help status |
시스템 | |
unlock <passphrase> |
잠금 해제 + active 복원 시도 |
|
lock |
Secrets·Passphrase 메모리 폐기 | ✓ |
target add <name> <user@host[:port]> <key_file|password|ssh_agent> [...] |
SSH target 등록 | ✓ |
target list · rm <name> · default <name> |
관리 | ✓ |
attach [target:]<session> |
기존 tmux 세션 연결 + watcher 시작 | ✓ |
open [target:]<session> [profile] |
원격 tmux 세션 신규 생성 + 프로파일 agent 실행 + attach | ✓ |
kill [target:]<session> |
원격 tmux 세션 종료 + detach | ✓ |
detach |
해제 | ✓ |
skills · skills reload |
target에서 스킬 목록 조회 / 현재 manifest 재로드 | ✓ |
use <name> |
활성 스킬 전환 (target에서 새 SKILL.md 로드) | ✓ |
task start <name> |
작업 시작/재개 (멱등) — last_task 설정 + 출력 파일 감시 | ✓ |
task done |
작업 종료 — 출력 파일 .done rename + 감시 중단 |
✓ |
invoke <rest> |
스킬 실행 — {name} + {task} 자동 주입, rest 원문 전달 |
✓ |
snap [N] |
화면 캡처 — 무인자=visible pane 전체, N=scrollback 포함 최근 N줄. 한도 초과 시 청크 분할 전송 (Telegram 4096자, Discord 2000자) |
✓ |
alias |
등록된 alias 목록 조회 (등록/삭제는 boot.json 직접 편집 후 재시작) |
✓ |
| 일반 텍스트 | 활성 세션에 자유 텍스트 주입 (reply) | ✓ |
#N (N=0..=9) |
boot.json aliases\[N\] 시퀀스 실행 (; 구분, 1s 간격) |
✓ |
{
"bots": {
"telegram": {
"bot_token": "TELEGRAM_BOT_TOKEN_HERE",
"owner_chat_id": 0
},
"discord": {
"bot_token": "DISCORD_BOT_TOKEN_HERE",
"owner_user_id": 0,
"allowed_channel_id": 0
}
},
"default_bot": "telegram",
"skill_root": "~/myenv/skills",
"default_skill": "plan-review",
"profiles": {
"claude": { "agent_cmd": "claude", "session_init_cmd": "dev {session}", "cancel_chars": "Escape", "cancel_delay": 0.5 },
"opencode": { "agent_cmd": "opencode", "session_init_cmd": "opdev {session}", "cancel_chars": "Escape Escape", "cancel_delay": 0.5 }
},
"default_profile": "claude",
"watcher_tail_lines": 10,
"aliases": { "1": "//clear;/invoke plan 목표: 어쩌고", "2": "정지" },
"active": null
}bots— 백엔드별 설정 맵.owner_chat_id/owner_user_id가 0 이면 해당 백엔드 비활성. 최소 1개 활성 필요default_bot— 기본 응답 백엔드 ("telegram"|"discord"). 지정 백엔드 비활성이면 첫 활성 백엔드로 폴백skill_root— target(Claude 호스트) 경로.~사용 가능. 봇 서버에 파일 불필요default_skill—/attach·/open시 기본 스킬명profiles—/open시 선택할 프로파일 목록. 각 프로파일 ={ agent_cmd, session_init_cmd, cancel_chars, cancel_delay }default_profile—/open시 인자 생략하면 사용할 기본 프로파일명watcher_tail_lines— streaming/waiting 메시지의 tail 표시 줄 수 (기본 10). 표시 전용 — 안정 비교는 visible 전체 String 동등 비교라 본 값과 무관aliases—#N트리거 시퀀스 맵. 키"0"~"9"(그 외 키는 silent ignore — 등록은 되지만 트리거 안 됨). 값은;구분 토큰 본문. 편집 후 재시작 필요 (런타임 reload 없음)
name: plan-review
invoke: "{name} {task} {rest}"
outputs:
- pattern: ".contexts/{task}_PLAN.md"
- pattern: ".contexts/{task}_DESIGN.md"봇이 실제로 쓰는 필드:
| 필드 | 용도 |
|---|---|
name |
{name} 치환 (필수) |
invoke |
payload 템플릿. {name}·{task} 필수, 보통 {rest} 로 사용자 입력 받음 |
outputs |
/task start 시 감시할 파일 패턴 ({task} 치환) |
actions / modes 는 봇 검증 없음 — 참고 목록일 뿐, 분기 로직은 SKILL.md 본문에서 Claude가 처리.
목표: 같은 서브 규약도 봇 개입 없음 — 스킬 본문의 Claude에게 맡김.
- 작업 PLAN이 있을 때는
.contexts/<task>_PLAN.md가 구현 정본. Step별[Step N]접두어로 커밋. git add -A금지 — CLAUDE.md/AGENTS.md(symlink)·.claude/는 untracked 유지. 명시적 파일만 add.- GROUP·OTHER 권한 없는 파일 접근 금지.
- 실행 규칙: Step별 테스트 통과 후 커밋, 명시 범위 밖 파일 수정 금지.
- 스킬 본체(
~/myenv/skills/*/SKILL.md)는 본 프로젝트에서 수정 불가. - 데이터 경로는
/opt/kkuepark/gecko_dev/만 사용.
docs/architecture.md— 런타임 토폴로지, Actor 통신, 잠금 모델, 복원 전략docs/deploy.md— systemd, SSH 사전 설정, 트러블슈팅.contexts/context.md— 현재 상태 · 다음 목표 · 핵심 메모- 글로벌 사용자 프로필:
~/.claude/CLAUDE.md