2026년 OpenClaw 게이트웨이·대시보드·다채널 알림이 한 축으로 묶이는 흐름 위에서, Bundler 프리체크와 HTTP Webhook만 최소 명령으로 고정합니다.
트리거 →
게이트웨이(원격 Mac) →
WORK_ROOT에서
bundle check·
bundle outdated·
lock diff →
JSON Webhook. 참고:
CircleCI·
Jenkins·
헬스·LaunchAgent·
Bundler 매트릭스.
구매·
도움말.
Node LTS·openclaw CLI·openclaw doctor로 TLS·PATH를 확인합니다. 게이트웨이는 127.0.0.1, 토큰은 chmod 600. 외부 수신은 SSH 터널 또는 승인된 프록시 한 경로만.
# 예: 헬스 확인 (포트·경로는 환경에 맞게)
curl -fsS "http://127.0.0.1:18789/health"
# doctor (PATH·인증서)
openclaw doctor
plist에 NODE_BINARY(·CA) 명시: LaunchAgent·헬스.
이 단계 점검
which node가 에이전트·수동 SSH 세션에서 동일
/health가 모니터링 간격마다 2xx
토큰이 저장소·로그에 노출되지 않음
WORK_ROOT/<job_id>/repo에 umask 027·git clone --depth 1·동시 클론 상한으로 격리합니다.
export WORK_ROOT="/var/lib/openclaw/work"
JOB_ID="${JOB_ID:-manual-$(date +%s)}"
REPO_DIR="${WORK_ROOT}/${JOB_ID}/repo"
mkdir -p "$REPO_DIR"
git clone --depth 1 "https://github.com/org/app.git" "$REPO_DIR"
CI와 동일 BUNDLE_*·미러·Git 토큰: 매트릭스.
bundle check·bundle outdated --parseable·git diff origin/main -- Gemfile.lock로 요약 필드를 채우고 스킬에서 JSON으로 넘깁니다.
cd "$REPO_DIR"
export BUNDLE_JOBS="${BUNDLE_JOBS:-4}"
export BUNDLE_RETRY="${BUNDLE_RETRY:-3}"
LOG="${WORK_ROOT}/${JOB_ID}/bundler-precheck.log"
: > "$LOG"
bundle check >>"$LOG" 2>&1
CHECK_RC=$?
bundle outdated --parseable >"${WORK_ROOT}/${JOB_ID}/outdated.txt" 2>>"$LOG" || true
OUTDATED_LINES=$(wc -l < "${WORK_ROOT}/${JOB_ID}/outdated.txt" | tr -d ' ')
git fetch origin main --depth 1 2>>"$LOG" || true
git diff origin/main -- Gemfile.lock >"${WORK_ROOT}/${JOB_ID}/lock.diff" 2>>"$LOG" || true
CHECK_RC·outdated_lines·lock 변경 여부를 status와 함께 실어 알림 규칙을 단순화합니다.
플레이크는 2·4·8초·최대 3회; 401·lock 문제는 실패 분류로 분리. 로그는 타임스탬프 파일·gzip 보관.
attempt=1
max=3
delay=2
while [ "$attempt" -le "$max" ]; do
bundle check >>"$LOG" 2>&1 && break
[ "$attempt" -eq "$max" ] && exit 1
sleep "$delay"
delay=$((delay * 2))
attempt=$((attempt + 1))
done
gzip -k "${WORK_ROOT}/${JOB_ID}/bundler-precheck.log" 2>/dev/null || true
application/json으로 status·job_id·revision·check_rc·outdated_lines·log_tail 등 최소 필드만. HMAC·Retry-After·502 시 짧은 백오프 POST.
# python으로 JSON 이스케이프 안전하게 생성 후 POST
export ALERT_WEBHOOK_URL="https://hooks.example.com/bundler-precheck"
export JOB_ID REVISION CHECK_RC OUTDATED_LINES LOG_PATH # LOG_PATH=bundler-precheck.log 절대경로
python3 <<'PY' | curl -fsS -X POST "$ALERT_WEBHOOK_URL" \
-H "Content-Type: application/json" \
--data-binary @-
import json, os, subprocess
log_path = os.environ.get("LOG_PATH", "")
tail = ""
if log_path:
try:
tail = subprocess.check_output(["tail", "-c", "1600", log_path], text=True, stderr=subprocess.DEVNULL)
except Exception:
pass
body = {
"status": "ok" if os.environ.get("CHECK_RC") == "0" else "fail",
"job_id": os.environ.get("JOB_ID", ""),
"revision": os.environ.get("REVISION", ""),
"check_rc": int(os.environ.get("CHECK_RC", "1")),
"outdated_lines": int(os.environ.get("OUTDATED_LINES", "0")),
"log_tail": tail,
}
print(json.dumps(body))
PY
핸들러는 즉시 2xx 후 워커에서 Bundler 실행(CircleCI 예시와 동일).
bundle outdated가 느립니다.
BUNDLE_USER_HOME 고정·이벤트당 1회·동시 잡 상한.
lock diff는 있는데 CI --frozen만 실패.
Ruby·Bundler·미러·플랫폼 블록을 CI와 동일하게.
204인데 대시보드에 없음.
스키마·필수 키를 수신측과 맞추고 스테이징 curl로 검증.
정리: 헬스·샌드박스·프리체크·재시도·Webhook 순으로 고정하면 Ruby CI 사고를 앞당겨 잡을 수 있습니다. 구매·도움말·요금·고객 지원·블로그는 로그인 없이 이용 가능합니다.
OpenClaw·Bundler 게이트웨이
MacPull 전용 Apple Silicon에 게이트웨이와 Bundler 스크립트를 두고 팀과 동일한 풀 경로를 재현하세요. 요금·구매·도움말(SSH)·고객 지원·기술 블로그는 로그인 없이 이용할 수 있습니다.