하트비트 (게이트웨이)

하트비트 vs 크론? 각각 언제 사용해야 하는지는 크론 vs 하트비트를 참조하세요.

하트비트는 메인 세션에서 주기적 에이전트 턴을 실행하여 모델이 스팸 없이 주의가 필요한 사항을 표면화할 수 있게 합니다.

문제 해결: /automation/troubleshooting

빠른 시작 (초보자)

  1. 하트비트를 활성화된 상태로 유지합니다 (기본값은 30m, Anthropic OAuth/setup-token의 경우 1h) 또는 자체 주기를 설정합니다.
  2. 에이전트 워크스페이스에 작은 HEARTBEAT.md 체크리스트를 생성합니다 (선택 사항이지만 권장).
  3. 하트비트 메시지가 어디로 가야 하는지 결정합니다 (target: "none"이 기본값; 마지막 연락처로 라우팅하려면 target: "last" 설정).
  4. 선택 사항: 투명성을 위해 하트비트 추론 전달을 활성화합니다.
  5. 선택 사항: 하트비트 실행에 HEARTBEAT.md만 필요한 경우 경량 부트스트랩 컨텍스트를 사용합니다.
  6. 선택 사항: 하트비트를 활성 시간(로컬 시간)으로 제한합니다.

설정 예시:

{
  agents: {
    defaults: {
      heartbeat: {
        every: "30m",
        target: "last", // 마지막 연락처로 명시적 전달 (기본값은 "none")
        directPolicy: "allow", // 기본값: 직접/DM 대상 허용; 억제하려면 "block" 설정
        lightContext: true, // 선택 사항: 부트스트랩 파일에서 HEARTBEAT.md만 주입
        // activeHours: { start: "08:00", end: "24:00" },
        // includeReasoning: true, // 선택 사항: 별도의 `Reasoning:` 메시지도 전송
      },
    },
  },
}

기본값

  • 간격: 30m (감지된 인증 모드가 Anthropic OAuth/setup-token인 경우 1h). agents.defaults.heartbeat.every 또는 에이전트별 agents.list[].heartbeat.every를 설정합니다. 0m으로 비활성화.
  • 프롬프트 본문 (agents.defaults.heartbeat.prompt로 설정 가능): Read HEARTBEAT.md if it exists (workspace context). Follow it strictly. Do not infer or repeat old tasks from prior chats. If nothing needs attention, reply HEARTBEAT_OK.
  • 하트비트 프롬프트는 사용자 메시지로 그대로 전송됩니다. 시스템 프롬프트에 “Heartbeat” 섹션이 포함되며 실행이 내부적으로 표시됩니다.
  • 활성 시간(heartbeat.activeHours)은 설정된 시간대에서 확인됩니다. 범위 밖에서는 범위 내 다음 틱까지 하트비트가 건너뛰어집니다.

하트비트 프롬프트의 용도

기본 프롬프트는 의도적으로 광범위합니다:

  • 백그라운드 작업: “보류 중인 작업을 검토하세요”는 에이전트가 후속 작업 (받은편지함, 캘린더, 알림, 대기 중인 작업)을 검토하고 긴급한 사항을 표면화하도록 유도합니다.
  • 사람 체크인: “낮 시간에 가끔 사람에게 안부를 확인하세요”는 가벼운 “필요한 것이 있나요?” 메시지를 유도하지만, 설정된 로컬 시간대를 사용하여 야간 스팸을 방지합니다 (/concepts/timezone 참조).

하트비트가 매우 구체적인 작업(예: “Gmail PubSub 통계 확인” 또는 “게이트웨이 상태 확인”)을 수행하길 원하면, agents.defaults.heartbeat.prompt (또는 agents.list[].heartbeat.prompt)를 커스텀 본문(그대로 전송)으로 설정하세요.

응답 계약

  • 주의가 필요한 사항이 없으면 **HEARTBEAT_OK**로 응답합니다.
  • 하트비트 실행 중, OpenClaw는 응답의 시작 또는 끝HEARTBEAT_OK가 나타나면 확인으로 처리합니다. 토큰이 제거되고 나머지 내용이 ackMaxChars 이하(기본값: 300)이면 응답이 삭제됩니다.
  • HEARTBEAT_OK가 응답의 중간에 나타나면 특별하게 처리되지 않습니다.
  • 알림의 경우, HEARTBEAT_OK포함하지 말고 알림 텍스트만 반환합니다.

하트비트 외부에서, 메시지 시작/끝의 불필요한 HEARTBEAT_OK는 제거되고 기록됩니다. HEARTBEAT_OK만으로 구성된 메시지는 삭제됩니다.

설정

{
  agents: {
    defaults: {
      heartbeat: {
        every: "30m", // 기본값: 30m (0m으로 비활성화)
        model: "anthropic/claude-opus-4-6",
        includeReasoning: false, // 기본값: false (사용 가능 시 별도의 Reasoning: 메시지 전달)
        lightContext: false, // 기본값: false; true면 워크스페이스 부트스트랩 파일에서 HEARTBEAT.md만 유지
        target: "last", // 기본값: none | 옵션: last | none | <채널 id> (코어 또는 플러그인, 예: "bluebubbles")
        to: "+15551234567", // 선택적 채널별 오버라이드
        accountId: "ops-bot", // 선택적 다중 계정 채널 ID
        prompt: "Read HEARTBEAT.md if it exists (workspace context). Follow it strictly. Do not infer or repeat old tasks from prior chats. If nothing needs attention, reply HEARTBEAT_OK.",
        ackMaxChars: 300, // HEARTBEAT_OK 후 허용되는 최대 문자 수
      },
    },
  },
}

범위 및 우선순위

  • agents.defaults.heartbeat는 전역 하트비트 동작을 설정합니다.
  • agents.list[].heartbeat는 위에 머지됩니다. 에이전트에 heartbeat 블록이 있으면, 해당 에이전트만 하트비트를 실행합니다.
  • channels.defaults.heartbeat는 모든 채널의 가시성 기본값을 설정합니다.
  • channels.<channel>.heartbeat는 채널 기본값을 오버라이드합니다.
  • channels.<channel>.accounts.<id>.heartbeat (다중 계정 채널)는 채널별 설정을 오버라이드합니다.

에이전트별 하트비트

agents.list[] 항목에 heartbeat 블록이 포함된 경우, 해당 에이전트만 하트비트를 실행합니다. 에이전트별 블록은 agents.defaults.heartbeat 위에 머지됩니다 (공유 기본값을 한 번 설정하고 에이전트별로 오버라이드 가능).

예시: 두 에이전트, 두 번째 에이전트만 하트비트 실행.

{
  agents: {
    defaults: {
      heartbeat: {
        every: "30m",
        target: "last", // 마지막 연락처로 명시적 전달 (기본값은 "none")
      },
    },
    list: [
      { id: "main", default: true },
      {
        id: "ops",
        heartbeat: {
          every: "1h",
          target: "whatsapp",
          to: "+15551234567",
          prompt: "Read HEARTBEAT.md if it exists (workspace context). Follow it strictly. Do not infer or repeat old tasks from prior chats. If nothing needs attention, reply HEARTBEAT_OK.",
        },
      },
    ],
  },
}

활성 시간 예시

특정 시간대에서 업무 시간으로 하트비트를 제한합니다:

{
  agents: {
    defaults: {
      heartbeat: {
        every: "30m",
        target: "last", // 마지막 연락처로 명시적 전달 (기본값은 "none")
        activeHours: {
          start: "09:00",
          end: "22:00",
          timezone: "America/New_York", // 선택 사항; userTimezone이 설정되면 사용, 아니면 호스트 시간대
        },
      },
    },
  },
}

이 범위 외(동부 시간 오전 9시 전 또는 오후 10시 후)에는 하트비트가 건너뛰어집니다. 범위 내 다음 예정된 틱은 정상적으로 실행됩니다.

24/7 설정

하트비트를 하루 종일 실행하려면 다음 패턴 중 하나를 사용합니다:

  • activeHours를 완전히 생략합니다 (시간 제한 없음; 기본 동작).
  • 전일 범위를 설정합니다: activeHours: { start: "00:00", end: "24:00" }.

동일한 startend 시간(예: 08:00에서 08:00)을 설정하지 마세요. 이는 너비가 0인 범위로 처리되어 하트비트가 항상 건너뛰어집니다.

다중 계정 예시

Telegram과 같은 다중 계정 채널에서 특정 계정을 대상으로 하려면 accountId를 사용합니다:

{
  agents: {
    list: [
      {
        id: "ops",
        heartbeat: {
          every: "1h",
          target: "telegram",
          to: "12345678:topic:42", // 선택 사항: 특정 토픽/스레드로 라우팅
          accountId: "ops-bot",
        },
      },
    ],
  },
  channels: {
    telegram: {
      accounts: {
        "ops-bot": { botToken: "YOUR_TELEGRAM_BOT_TOKEN" },
      },
    },
  },
}

필드 참고 사항

  • every: 하트비트 간격 (기간 문자열; 기본 단위 = 분).
  • model: 하트비트 실행용 선택적 모델 오버라이드 (provider/model).
  • includeReasoning: 활성화 시, 사용 가능한 경우 별도의 Reasoning: 메시지도 전달합니다 (/reasoning on과 동일한 형태).
  • lightContext: true일 때, 하트비트 실행은 경량 부트스트랩 컨텍스트를 사용하고 워크스페이스 부트스트랩 파일에서 HEARTBEAT.md만 유지합니다.
  • session: 하트비트 실행용 선택적 세션 키.
    • main (기본값): 에이전트 메인 세션.
    • 명시적 세션 키 (openclaw sessions --json 또는 세션 CLI에서 복사).
    • 세션 키 형식: 세션그룹 참조.
  • target:
    • last: 마지막으로 사용한 외부 채널로 전달.
    • 명시적 채널: whatsapp / telegram / discord / googlechat / slack / msteams / signal / imessage.
    • none (기본값): 하트비트를 실행하지만 외부로 전달하지 않음.
  • directPolicy: 직접/DM 전달 동작을 제어합니다:
    • allow (기본값): 직접/DM 하트비트 전달 허용.
    • block: 직접/DM 전달 억제 (reason=dm-blocked).
  • to: 선택적 수신자 오버라이드 (채널별 ID, 예: WhatsApp의 E.164 또는 Telegram 채팅 ID). Telegram 토픽/스레드의 경우, <chatId>:topic:<messageThreadId> 사용.
  • accountId: 다중 계정 채널용 선택적 계정 ID. target: "last"일 때, 계정 ID는 해석된 마지막 채널이 계정을 지원하는 경우 적용되며, 그렇지 않으면 무시됩니다. 계정 ID가 해석된 채널의 설정된 계정과 일치하지 않으면 전달이 건너뛰어집니다.
  • prompt: 기본 프롬프트 본문을 오버라이드합니다 (머지 아님).
  • ackMaxChars: HEARTBEAT_OK 후 전달 전 허용되는 최대 문자 수.
  • suppressToolErrorWarnings: true일 때, 하트비트 실행 중 도구 오류 경고 페이로드를 억제합니다.
  • activeHours: 하트비트 실행을 시간 범위로 제한합니다. start (HH:MM, 포함; 하루 시작에 00:00 사용), end (HH:MM 제외; 하루 끝에 24:00 허용), 선택적 timezone을 가진 객체.
    • 생략 또는 "user": agents.defaults.userTimezone이 설정되면 사용, 아니면 호스트 시스템 시간대로 폴백.
    • "local": 항상 호스트 시스템 시간대 사용.
    • 모든 IANA 식별자 (예: America/New_York): 직접 사용; 유효하지 않으면 위의 "user" 동작으로 폴백.
    • 활성 범위를 위해 startend가 같으면 안 됩니다. 같은 값은 너비가 0으로 처리됩니다 (항상 범위 밖).
    • 활성 범위 밖에서는 범위 내 다음 틱까지 하트비트가 건너뛰어집니다.

전달 동작

  • 하트비트는 기본적으로 에이전트의 메인 세션(agent:<id>:<mainKey>)에서 실행되며, session.scope = "global"일 때는 global에서 실행됩니다. session을 설정하여 특정 채널 세션(Discord/WhatsApp 등)으로 오버라이드할 수 있습니다.
  • session은 실행 컨텍스트에만 영향을 미칩니다. 전달은 targetto로 제어됩니다.
  • 특정 채널/수신자에게 전달하려면 target + to를 설정합니다. target: "last"이면 해당 세션의 마지막 외부 채널로 전달됩니다.
  • 하트비트 전달은 기본적으로 직접/DM 대상을 허용합니다. directPolicy: "block"을 설정하면 하트비트 턴을 실행하면서도 직접 대상 전송을 억제합니다.
  • 메인 큐가 바쁘면 하트비트가 건너뛰어지고 나중에 재시도됩니다.
  • target이 외부 대상으로 해석되지 않으면, 실행은 여전히 발생하지만 아웃바운드 메시지는 전송되지 않습니다.
  • 하트비트 전용 응답은 세션을 활성 상태로 유지하지 않습니다. 마지막 updatedAt이 복원되어 유휴 만료가 정상적으로 동작합니다.

가시성 제어

기본적으로 HEARTBEAT_OK 확인은 억제되고 알림 내용은 전달됩니다. 채널별 또는 계정별로 이를 조정할 수 있습니다:

channels:
  defaults:
    heartbeat:
      showOk: false # HEARTBEAT_OK 숨기기 (기본값)
      showAlerts: true # 알림 메시지 표시 (기본값)
      useIndicator: true # 인디케이터 이벤트 발생 (기본값)
  telegram:
    heartbeat:
      showOk: true # Telegram에서 OK 확인 표시
  whatsapp:
    accounts:
      work:
        heartbeat:
          showAlerts: false # 이 계정의 알림 전달 억제

우선순위: 계정별 → 채널별 → 채널 기본값 → 내장 기본값.

각 플래그의 기능

  • showOk: 모델이 OK만 응답한 경우 HEARTBEAT_OK 확인을 전송합니다.
  • showAlerts: 모델이 OK가 아닌 응답을 반환한 경우 알림 내용을 전송합니다.
  • useIndicator: UI 상태 표면을 위한 인디케이터 이벤트를 발생시킵니다.

세 가지 모두 false이면, OpenClaw는 하트비트 실행을 완전히 건너뜁니다 (모델 호출 없음).

채널별 vs 계정별 예시

channels:
  defaults:
    heartbeat:
      showOk: false
      showAlerts: true
      useIndicator: true
  slack:
    heartbeat:
      showOk: true # 모든 Slack 계정
    accounts:
      ops:
        heartbeat:
          showAlerts: false # ops 계정에 대해서만 알림 억제
  telegram:
    heartbeat:
      showOk: true

일반적인 패턴

목표설정
기본 동작 (조용한 OK, 알림 켜짐)(설정 필요 없음)
완전히 조용 (메시지 없음, 인디케이터 없음)channels.defaults.heartbeat: { showOk: false, showAlerts: false, useIndicator: false }
인디케이터만 (메시지 없음)channels.defaults.heartbeat: { showOk: false, showAlerts: false, useIndicator: true }
한 채널에서만 OKchannels.telegram.heartbeat: { showOk: true }

HEARTBEAT.md (선택 사항)

워크스페이스에 HEARTBEAT.md 파일이 존재하면, 기본 프롬프트가 에이전트에게 이를 읽으라고 지시합니다. “하트비트 체크리스트”로 생각하세요: 작고, 안정적이며, 30분마다 포함해도 안전합니다.

HEARTBEAT.md가 존재하지만 실질적으로 비어있는 경우(빈 줄과 # 제목 같은 마크다운 헤더만 있는 경우), OpenClaw는 API 호출을 절약하기 위해 하트비트 실행을 건너뜁니다. 파일이 없으면 하트비트는 여전히 실행되며 모델이 무엇을 할지 결정합니다.

프롬프트 비대를 피하기 위해 작게 유지하세요 (짧은 체크리스트 또는 알림).

HEARTBEAT.md 예시:

# 하트비트 체크리스트

- 빠른 스캔: 받은편지함에 긴급한 것이 있나?
- 낮 시간이면, 다른 대기 사항이 없는 경우 가벼운 안부 확인.
- 작업이 막혀있으면, _무엇이 부족한지_ 적어두고 다음에 Peter에게 물어보기.

에이전트가 HEARTBEAT.md를 업데이트할 수 있나요?

네 — 요청하면 가능합니다.

HEARTBEAT.md는 에이전트 워크스페이스의 일반 파일이므로, 에이전트에게 (일반 채팅에서) 다음과 같이 말할 수 있습니다:

  • HEARTBEAT.md를 업데이트해서 일일 캘린더 확인을 추가해줘.”
  • HEARTBEAT.md를 더 짧고 받은편지함 후속 작업에 집중하도록 다시 작성해줘.”

이것이 자발적으로 발생하길 원하면, 하트비트 프롬프트에 다음과 같은 명시적 줄을 포함할 수도 있습니다: “체크리스트가 오래되면, 더 나은 것으로 HEARTBEAT.md를 업데이트해.”

안전 참고: HEARTBEAT.md에 시크릿(API 키, 전화번호, 비공개 토큰)을 넣지 마세요 — 프롬프트 컨텍스트의 일부가 됩니다.

수동 웨이크 (온디맨드)

시스템 이벤트를 큐에 추가하고 즉시 하트비트를 트리거할 수 있습니다:

openclaw system event --text "Check for urgent follow-ups" --mode now

여러 에이전트에 heartbeat가 설정된 경우, 수동 웨이크는 해당 에이전트 하트비트를 각각 즉시 실행합니다.

다음 예정된 틱을 기다리려면 --mode next-heartbeat를 사용합니다.

추론 전달 (선택 사항)

기본적으로 하트비트는 최종 “답변” 페이로드만 전달합니다.

투명성이 필요하면 다음을 활성화합니다:

  • agents.defaults.heartbeat.includeReasoning: true

활성화되면, 하트비트는 Reasoning: 접두사가 붙은 별도 메시지도 전달합니다 (/reasoning on과 동일한 형태). 에이전트가 여러 세션/코덱스를 관리하고 왜 핑을 보내기로 결정했는지 보고 싶을 때 유용하지만, 원하는 것보다 더 많은 내부 세부 사항을 노출할 수도 있습니다. 그룹 채팅에서는 비활성화를 권장합니다.

비용 인식

하트비트는 전체 에이전트 턴을 실행합니다. 짧은 간격은 더 많은 토큰을 소비합니다. HEARTBEAT.md를 작게 유지하고, 내부 상태 업데이트만 원하는 경우 더 저렴한 model이나 target: "none"을 고려하세요.