Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

202 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

gecko_dev — Claude Code 원격 제어 봇

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_blob AES-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 재로드)

빠른 시작

  1. 빌드 — cargo build --release
  2. /opt/kkuepark/gecko_dev/에 바이너리 설치 후 실행 → boot.json 템플릿 자동 생성
  3. bots.telegram.bot_token·owner_chat_id (또는 Discord 설정) 편집 후 재실행
  4. 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
    

alias 트리거

#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 간격)

BootConfig · 스킬 스키마

boot.json 주요 필드

{
  "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_roottarget(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 없음)

SKILL.md 프론트매터 주요 필드

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

About

텔레그램을 이용한 원격 에이전트 실행기

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages