텔레그램을 통한 코딩 에이전트, 파트 2: 기초부터 답변 가능한 에이전트까지
요약
텔레그램을 통해 코딩 에이전트를 제어할 수 있는 환경을 구축하는 실습 가이드입니다. tmux와 특정 Node.js 버전을 활용하여 에이전트가 서버의 셸을 제어하고 메시지에 답변하도록 설정하는 과정을 다룹니다.
핵심 포인트
- 텔레그램 메시지로 코딩 에이전트를 제어하는 환경 구축
- tmux를 활용한 서버 셸 제어 및 세션 유지 방법
- Node.js 24.11.1 및 pnpm 11.2.2 등 특정 런타임 버전 고정의 중요성
- OpenClaw를 이용한 에이전트 게이트웨이 설정 실습
이 포스트는 시리즈 중 여러분이 단순히 읽기만 하는 것이 아니라, 직접 수행해야 하는 유일한 포스트입니다. 이 과정이 끝나면 여러분은 메시지를 입력하면 코딩 에이전트가 답변하고 여러분의 서버(box)에 있는 tmux 창을 제어하는 단일 텔레그램 토픽을 갖게 될 것입니다. 그것이 유일한 목표이며, 그 이상은 아닙니다. 메모리(Memory), 모니터(monitors), 도구 서버(tool servers), 그리고 감독관(supervisor)은 모두 나중에 다룰 내용입니다. 에이전트가 답변하게 만드는 데에는 이 중 어느 것도 필요하지 않습니다.
예상 소요 시간은 약 30~45분입니다. 딱 한 가지만 한다면, '빠른 경로(Fast path)'를 수행한 다음 '준비 게이트(readiness gate)'로 이를 증명하세요. 게이트 아래의 모든 내용은 수동 설명과 디버깅 과정이며, 필요할 때까지 건너뛰어도 좋습니다.
필수 요구 사항 (개별 설정이 실패하는 지점)
텔레그램 연결은 기계적인 부분입니다. 진짜 실패 원인은 로컬 상태(local state)에 숨어 있습니다. 시작하기 전에 모든 라인을 확인하십시오:
tmux가 설치되어 있고, 연결이 끊겨도 유지되는 셸(shell) 액세스 권한을 가진 제어 가능한 서버(box) (게이트웨이를 계속 실행해 두어야 합니다).- 이미 tmux 창에서 작동 중인 코딩 에이전트 (opencode, Codex, 또는 Claude Code)로서, 지금 당장 수동으로 제어할 수 있는 에이전트. 만약 아직 설치되지 않았거나 **인증(authenticated)**되지 않았다면, 중단하고 그것부터 해결하십시오. OpenClaw는 에이전트를 구동하는 것이지, 에이전트를 대체하는 것이 아닙니다.
- 해당 에이전트를 위한 확인된 안정적인 창(pane) 대상 (예:
mybox:1.1). 이를 적어 두십시오. 에이전트의 지침(instructions)에 하드코딩할 것입니다. - 에이전트의 실행 명령: 세션을 재개하는 방법을 포함하여, 창에서 코딩 에이전트를 시작하는 정확한 명령(또는 래퍼 스크립트). OpenClaw의 재시작 흐름에는 이 명령이 그대로 필요합니다.
- 고정된(pinned) OpenClaw 런타임(아래 매트릭스 참조). 잘못된 Node 버전은 가장 흔하게 발생하는 무음 실패(silent failure) 원인입니다.
- 텔레그램 계정과 휴대폰에 설치된 텔레그램 앱.
버전 매트릭스
이 버전들을 고정하십시오. "Node에서 실행된다"는 것만으로는 부족합니다. 게이트웨이는 런타임에 민감합니다.
| 구성 요소 | 고정 버전 | 비고 |
|---|---|---|
| Node.js | 24.11.1 | 게이트웨이는 Node 24를 기준으로 빌드되었습니다. 더 높은 메이저 버전은 네이티브 빌드에 실패할 수 있습니다. |
| ... |
빠른 경로 (Fast path)
두 개의 스크립트가 전체 로컬 설정을 수행합니다. Gist에서 스크립트를 가져온 다음, 텔레그램 단계 전후로 실행하세요:
# 부트스트랩(bootstrap) + 준비 상태 확인(readiness) 스크립트 다운로드
curl -fsSL "https://gist.githubusercontent.com/jerilkuriakose/cd0f8353aac74e47c591111b758943e9/raw/setup-openclaw.sh" -o setup-openclaw.sh
curl -fsSL "https://gist.githubusercontent.com/jerilkuriakose/7cf94af3e96526f9f14d0c28b6c26b69/raw/ready-check.sh" -o ready-check.sh
...
setup-openclaw.sh는 Node 24.11.1과 pnpm 11.2.2를 고정(pins)하며 (nvm 및 corepack을 통해), github.com/openclaw/openclaw를 클론(clone) 및 빌드하고, 게이트웨이(gateway)를 실행합니다. ready-check.sh는 사용자를 대신해 준비 상태 게이트(readiness gate)를 실행합니다. 각 단계를 직접 이해하는 것을 선호하시나요, 아니면 문제가 발생했나요? 그렇다면 수동 경로(manual path)를 따르세요.
수동 경로 (Manual path)
세 부분으로 나뉩니다: 텔레그램 측, 박스(box) 측, 그리고 이 둘을 서로 연결하는 과정입니다.
텔레그램 측 (Telegram side)
당신은 반드시 해당 그룹의 **생성자(creator)**여야 하므로, 본인의 텔레그램 계정에서 다음을 수행하세요:
- 봇(bot) 생성.
@BotFather에게 메시지 전송 →/newbot→ 이름 지정 → 제공되는 **봇 토큰(bot token)**을 저장합니다. 토큰은 비밀번호처럼 취급하세요 (Secrets 섹션 참조). - 그룹 생성, 이름을 지정한 후 봇을 그룹에 추가합니다.
- 봇을 관리자(admin)로 승격 (그룹 → 편집 → 관리자). 이는 필수 사항입니다. 텔레그램의 개인정보 보호 모드(privacy mode)는 관리자가 아닌 봇에게 일반 그룹 메시지를 숨기기 때문에, 이 설정을 하지 않으면 봇은 당신이 입력하는 내용을 볼 수 없습니다.
- 토픽(Topics) 활성화 (그룹 → 편집 → 토픽). 이를 통해 그룹이 포럼 슈퍼그룹(forum supergroup)으로 전환됩니다.
- 첫 번째 토픽 생성 및 에이전트가 구동할 프로젝트 이름으로 지정 (예:
project-a). - 해당 토픽에 메시지 하나 전송 (무엇이든 상관없음). 이렇게 하면 그룹과 토픽이 게이트웨이 로그에 나타나므로 ID를 가져올 수 있습니다.
또한 허용 목록(allowlist)을 위해 **본인의 숫자 형태 텔레그램 사용자 ID(user ID)**가 필요합니다. 가장 쉬운 방법은 @userinfobot에게 메시지를 보내면 ID를 답장해 주는 것입니다. (또는 다음 단계에서 메시지 흐름이 시작되면 게이트웨이 로그에 발신자로 나타납니다.)
박스 측 (Box side): 최소 설정 후 게이트웨이 시작
박스 측 (Box side): 최소 설정 후 게이트웨이 시작
게이트웨이는 봇(bot)에 대해 알아야만 Telegram을 폴링할 수 있으므로, 먼저 최소한의 유효한 설정을 작성해야 합니다. ~/.openclaw/openclaw.json 파일을 봇 계정 정보만으로 만드세요. 게이트웨이가 파싱하고 사용자가 검증할 내용이 바로 이것이므로 엄격한 JSON (주석 없음, 트레일링 콤마 없음)을 사용해야 합니다:
{
"channels": {
"telegram": {
...
배포하기 전에 잠그고(lock down) 검증하세요:
chmod 600 ~/.openclaw/openclaw.json
python3 -c "import json; json.load(open('$HOME/.openclaw/openclaw.json')); print('JSON OK')"
OpenClaw를 받아 빌드하세요. 이것은 오픈 소스입니다. 런타임 환경을 고정하고, 클론한 다음 corepack이 제공하는 pnpm으로 설치하고 빌드합니다:
nvm install 24.11.1 && nvm use 24.11.1
corepack enable && corepack prepare pnpm@11.2.2 --activate
...
이제 게이트웨이를 별도의 tmux 세션에서 실행하여 연결이 끊겨도 유지되게 하세요:
pnpm gateway:watch # 게이트웨이를 시작하고 자체 tmux 세션을 관리합니다.
로그 경로를 찾은 다음(설정에 따라 다름), 게이트웨이가 정상적으로 작동하고 봇이 폴링하는지 확인하세요:
# logging.file이 설정되어 있다면, ~/.openclaw/logs/openclaw.log을 사용합니다. 그렇지 않으면 날짜가 지정된 기본 경로를 사용합니다:
ls -t /tmp/openclaw/openclaw-*.log | tail -1 # 기본 위치
grep -a 'gateway ready' <your-log-path> | tail -1 # 최근 라인을 기대합니다.
로그 디렉토리는 잠겨 있으므로(
0700), 에디터의 파일 브라우저가 아닌 셸에서 읽어야 합니다. 이 초기 실행, 그리고 나중에logging또는plugins.load변경 사항은 게이트웨이(재)시작이 필요합니다. 다음 섹션의 그룹/토픽/라우팅 편집은 재시작 없이 핫 리로드됩니다.
연결하기 (Wire them together)
설정 파일은 ~/.openclaw/openclaw.json에 있습니다. 게이트웨이는 라우팅/토픽/채널 편집을 핫 리로드하므로, 이들에 대해서는 재시작이 필요 없습니다. 우리는 두 단계로 진행합니다. 왜냐하면 채팅 ID와 토픽 ID가 로그에서 필요하고, 이것들이 나타나게 하는 유일한 방법은 먼저 메시지가 통과하도록 하는 것이기 때문입니다.
1단계: 채팅 ID를 찾고 그룹을 일시적으로 열기.
게이트웨이(gateway)가 이제 폴링(polling)을 수행하고 있으므로, 해당 토픽(topic)에 메시지를 보내세요. 아직 그룹 설정이 되지 않았기 때문에 메시지가 차단될 것이며, 이 과정에서 채팅 ID(chat ID)가 편리하게 로그에 기록됩니다:
grep -a 'not-allowed' <your-log-path> | tail -1
# → {"chatId":<CHAT_ID>,"title":"<your group>","reason":"not-allowed"}
메시지가 흐르고 토픽 ID(topic ID)가 로그에 기록될 수 있도록 계정(account)에 groups 블록을 추가하세요. 다음은 코드 조각(fragment)입니다. 파일의 엄격한 JSON 형식을 유지하면서, 이미 생성한 계정에 groups 키를 병합하세요:
"groups": {
"<CHAT_ID>": { "groupPolicy": "open", "requireMention": false }
}
저장하세요. 게이트웨이가 핫 리로드(hot-reloads)됩니다 (재시작 불필요).
개방된 창을 최소한으로 유지하세요.
groupPolicy: "open"설정은 그룹 내의 누구라도 셸(shell) 실행이 가능한 에이전트(agent)를 구동할 수 있게 합니다. 그룹은 반드시 본인만 포함된 비공개 상태여야 하며, 이는 일시적인 부트스트랩(bootstrap) 단계입니다. 토픽 ID를 모두 수집했다면, 다른 사람을 추가하거나 실제 작업을 수행하기 전에 즉시allowlist방식(2단계)으로 전환하세요.
1b단계: 토픽 스레드 ID(topic thread IDs) 수집. 각 토픽에 메시지를 보내세요 (토픽 ID는 생성 순서대로 연속적이지 않으므로, 구분할 수 있도록 텍스트로 라벨을 붙이세요). 그 다음:
grep -ao 'Inbound message telegram:group[^"\']*' <your-log-path> | sort -u
# → ...:topic:<TOPIC_THREAD_ID>
2단계: 보안을 강화하고 토픽을 에이전트에 라우팅(route)하기. 이제 그룹을 허용 목록(allowlist, 소유자 전용) 방식으로 전환하고, 본인을 추가하며, 토픽을 에이전트에 매핑(map)한 뒤 해당 에이전트를 선언하세요. 기존 설정에 병합된 엄격한 JSON 형식은 다음과 같습니다:
"channels": {
"telegram": {
"enabled": true,
...
requireMention: false 설정을 사용하면 모든 메시지에 @mention을 접두사로 붙일 필요 없이 자연스럽게 타이핑할 수 있습니다. allowFrom에 본인의 사용자 ID만 지정하면 그룹 내의 다른 사람이 셸 실행이 가능한 에이전트를 구동하는 것을 방지할 수 있습니다. 이는 본인의 숫자형 Telegram ID이며, 설정에서 요구하는 대로 따옴표로 감싸진 문자열 형태(예: ["123456789"])로 유지해야 합니다.
에이전트에게 지침을 부여하세요. 이 단계는 status, send, restart가 작동하게 만드는 단계입니다. 에이전트의 동작은 전적으로 workspace 내의 파일들로부터 결정됩니다. 먼저 워크스페이스 디렉토리를 생성하세요 (agentDir은 에이전트마다 고유해야 하며, 게이트웨이가 첫 실행 시 이를 생성합니다):
mkdir -p ~/.openclaw/workspace-<name>
그런 다음, 최소한의 명령 계약(command contract)인 내용을 ~/.openclaw/workspace-<name>/AGENTS.md에 넣으세요:
# <your-agent-id>
당신은 대화형 코딩 에이전트 세션인 tmux pane `<PANE>`에 종속됩니다.
...
<PANE>과 재시작 명령어를 실제 값으로 교체하세요. 값을 모호하게 남겨두면 에이전트가 임의로 판단하게 되어 세션을 잃을 수 있습니다. 이 단일 파일이 곧 당신의 에이전트입니다. 워크스페이스는 시작 단계에서AGENTS.md만 포함하고 있어도 됩니다.
필수 사항: 저장하기 전에 반드시 검증하세요. 잘못된 openclaw.json은 위험합니다. 재시작 시 게이트웨이가 이를 거부하고, 마지막으로 확인된 정상 상태(last-known-good)로 자동 복구하며, watch 프로세스가 종료됩니다 (즉, 서비스 중단이 발생합니다). 실행 중인 게이트웨이를 편집하는 것이 더 안전합니다 (잘못된 편집은 다운타임 없이 되돌려집니다). 하지만 검증되지 않은 설정으로 절대 재시작하지 마세요. 매번 다음을 수행하세요:
# 1. JSON 파싱 가능 여부 확인
python3 -c "import json; json.load(open('$HOME/.openclaw/openclaw.json')); print('JSON OK')"
...
준비 상태 확인 (Readiness gate)
설정이 저장되었다고 해서 작업이 끝난 것이 아닙. 전체 경로가 작동한다는 증거를 확보해야 작업이 완료된 것입니다. 다음 다섯 가지를 모두 확인하세요. 이것이 바로 세션 관리자에게 확인해 줄 내용입니다:
- 봇이 토픽 내에서 응답하는가. 토픽에
status를 입력했을 때 응답이 오는지 확인하세요 (침묵이 아니어야 합니다). - 프롬프트가 pane에 도달하는가. 실제 명령을 보내고, pane이 이를 수신했는지 확인하세요:
tmux capture-pane -t <PANE> -p | tail -n 40
당신의 텍스트가 코딩 에이전트에 주입된 것을 볼 수 있어야 합니다.
- 패널이 실제로 움직임: 구체적으로 말하면, 코딩 에이전트가 프롬프트(prompt)를 가져가서 턴(turn)을 시작했습니다(단순히 입력 줄에 텍스트가 머물러 있는 것이 아니라, 에이전트가 생각하거나 스트리밍하는 모습 또는 새로운 명령어가 실행되는 것을 볼 수 있습니다).
- 라우팅(Routing)이 올바름. 세션/로그 아티팩트(artifact)를 통해 당신의 에이전트가 당신의 주제를 처리했음을 증명합니다:
ls -t ~/.openclaw/agents/<name>/sessions/*topic-<TOPIC_THREAD_ID>* 2>/dev/null
- 잠금 상태임. 최종 설정(config)을 보면
groupPolicy: "allowlist",allowFrom에 당신의 ID, 그리고requireMention: false가 표시됩니다. 당신은 더 이상 1단계(Phase 1)의open모드 상태가 아닙니다.
이 다섯 가지 사항이 모두 충족되면 세션을 시작할 준비가 된 것입니다. 준비 완료를 증명하는 아티팩트(artifact)로서 1~2번 항목의 민감 정보가 삭제된(redacted) 스크린샷 또는 로그 스니펫(snippet)을 캡처하세요. 이때 스크린샷뿐만 아니라 로그 발췌본에서도 채팅 ID, 스레드 ID, 사용자 ID 및 메시지 텍스트와 같은 정보를 반드시 삭제(redact)해야 합니다.
작동이 중단될 경우
복구가 우선입니다. 만약 재시작으로 인해 게이트웨이(gateway)가 다운되었다면, 편집한 내용이 손실된 것이 아닙니다. 게이트웨이는 마지막으로 확인된 정상 상태(last-known-good)를 자동으로 복구하고, 당신의 버전을 그와 함께 저장했습니다. ~/.openclaw/openclaw.json.clobbered.*에서 복구하십시오(또한 .last-good / .bak 파일도 확인하세요). 원인을 수정한 후, 위에서 언급한 사항들을 **검증(validate)**하고 다시 시작하세요:
nvm use 24.11.1
tmux kill-session -t openclaw-gateway-watch-main
cd ~/repos/openclaw && pnpm gateway:watch
...
| 증상 | 원인 | 해결 방법 |
|---|---|---|
봇이 응답 없음; 로그에 "reason":"not-allowed" 표시 | 그룹이 설정되지 않았거나, allowFrom에 포함되지 않음 | 그룹을 추가하거나, allowFrom에 숫자 ID를 입력하세요 (또는 테스트 중에는 open 모드 사용) |
| ... |
보안 사항 (Secrets)
이것은 셸(shell) 접근 권한을 가진 퍼블릭 인터넷 봇입니다. 그에 걸맞게 취급하십시오:
- 봇 토큰(bot token)은
openclaw.json에 저장됩니다. **chmod 600**을 설정하고, 절대 커밋하거나 스크린샷을 찍지 마십시오. 토큰이 유출되면@BotFather를 통해 교체(rotate)하십시오. - 그룹을 **비공개(private)**로 유지하십시오: 오직 당신과 봇만 있어야 합니다. 소유자 전용 허용 목록(allowlist)이 관문 역할을 합니다. 그룹에 누군가를 추가하더라도 그들의 ID가
allowFrom에 없다면 여전히 봇을 제어할 수 없습니다. - 블로그 게시/스크린샷/공유 시: 봇 핸들(bot handles), 채팅 ID(chat IDs), 사용자 ID(user ID), 호스트 이름(hostnames), 경로(paths)를 가리십시오. 여기에는 이러한 정보와 원문 메시지 텍스트를 모두 포함하는 **로그 발췌본(log excerpts)**도 포함됩니다.
- 자격 증명(Credentials) (클라우드, 레지스트리)은 이 릴레이(relay)의 문제가 아니라 **운영 에이전트(ops-agent)**의 관심사입니다. 이 토픽에 비밀 정보(secrets)를 절대 붙여넣지 마시고, 에이전트가 이를 에코(echo)하거나 전달하게 두지 마십시오.
범위 외 사항 (의도적으로 보류됨)
준비 단계(readiness gate)를 완료하는 데 다음 사항들은 필요하지 않습니다. 이 모든 내용은 파트 4 / 세션에서 다룹니다:
- 토픽별 시맨틱 메모리(semantic memory) 및 모든 네이티브 임베딩 빌드(native embedding build)
- 진행/완료 알림 데몬(notification daemons)
- 에이전트를 위한 도구 서버(Tool servers) (MCP)
- 로드 가능한 기술(Loadable skills)
- 빠른 결정론적 의도 라우터(fast deterministic intent router) (현재의
AGENTS.md는 이미 프롬프트 기반으로status/send/restart/옵션 응답을 처리합니다. 라우터는 이를 더 빠르고 엄격하게 만들 뿐입니다) ops에이전트 (박스 전체 셸). 하나의 릴레이 + 하나의 창(pane)이 이번 과제의 전부입니다.
세션 시작 전
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기