하트비트 (Gateway)
하트비트와 Cron 중 무엇을 써야 하나요? 언제 무엇을 사용할지에 대한 안내는 Automation & Tasks를 참고하세요.하트비트는 주기적인 에이전트 턴을 메인 세션에서 실행하여, 모델이 사용자에게 과도한 메시지를 보내지 않으면서 주의가 필요한 사항을 알려줄 수 있게 합니다. 하트비트는 예약된 메인 세션 턴이며, background task 레코드를 생성하지 않습니다. 작업 레코드는 분리된 작업(ACP 실행, 서브에이전트, 격리된 cron 작업)을 위한 것입니다. 문제 해결: Scheduled Tasks
빠른 시작 (초보자)
- 하트비트를 활성화된 상태로 둡니다(기본값은
30m, Anthropic OAuth/token 인증(Claude CLI 재사용 포함)일 때는1h) 또는 원하는 주기를 설정합니다. - 에이전트 워크스페이스에 작은
HEARTBEAT.md체크리스트 또는tasks:블록을 만듭니다(선택 사항이지만 권장). - 하트비트 메시지를 어디로 보낼지 결정합니다(
target: "none"이 기본값이며, 마지막 연락처로 라우팅하려면target: "last"로 설정). - 선택 사항: 투명성을 위해 하트비트 reasoning 전달을 활성화합니다.
- 선택 사항: 하트비트 실행에
HEARTBEAT.md만 필요하다면 가벼운 bootstrap 컨텍스트를 사용합니다. - 선택 사항: 매 하트비트마다 전체 대화 기록을 보내지 않도록 격리 세션을 활성화합니다.
- 선택 사항: 하트비트를 활성 시간대로 제한합니다(로컬 시간).
기본값
- 간격:
30m(또는 감지된 인증 모드가 Anthropic OAuth/token 인증인 경우1h, Claude CLI 재사용 포함).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” 섹션이 포함됩니다.
0m으로 하트비트를 비활성화하면 일반 실행도 bootstrap 컨텍스트에서HEARTBEAT.md를 제외하므로 모델이 하트비트 전용 지침을 보지 않습니다.- 활성 시간(
heartbeat.activeHours)은 구성된 시간대에서 검사됩니다. 시간대 밖에서는 다음 유효 시간대의 틱까지 하트비트를 건너뜁니다.
하트비트 프롬프트의 목적
기본 프롬프트는 의도적으로 폭넓게 설계되어 있습니다:- 백그라운드 작업: “Consider outstanding tasks”는 에이전트가 후속 작업(받은편지함, 캘린더, 리마인더, 대기 중인 작업)을 검토하고 긴급한 사항을 알리도록 유도합니다.
- 사람 확인: “Checkup sometimes on your human during day time”는 가벼운 “필요한 것 있나요?” 메시지를 가끔 보내도록 유도하지만, 설정된 로컬 시간대를 사용해 야간 스팸은 피합니다(/concepts/timezone 참고).
agents.defaults.heartbeat.prompt(또는
agents.list[].heartbeat.prompt)를 사용자 정의 본문으로 설정하세요(그대로 전송됨).
응답 계약
- 주의가 필요한 것이 없으면 **
HEARTBEAT_OK**로 응답합니다. - 하트비트 실행 중 OpenClaw는 응답의 시작 또는 끝에
HEARTBEAT_OK가 있으면 이를 ack로 처리합니다. 이 토큰은 제거되며, 남은 내용이ackMaxChars이하(기본값: 300)면 응답은 폐기됩니다. HEARTBEAT_OK가 응답의 중간에 있으면 특별하게 처리되지 않습니다.- 경고의 경우
HEARTBEAT_OK를 포함하지 말고 경고 텍스트만 반환하세요.
HEARTBEAT_OK가 제거되고
로그에 기록됩니다. 메시지가 HEARTBEAT_OK만으로 이루어져 있으면 폐기됩니다.
구성
범위 및 우선순위
agents.defaults.heartbeat는 전역 하트비트 동작을 설정합니다.agents.list[].heartbeat는 그 위에 병합되며, 어떤 에이전트든heartbeat블록이 있으면 그 에이전트들만 하트비트를 실행합니다.channels.defaults.heartbeat는 모든 채널의 가시성 기본값을 설정합니다.channels.<channel>.heartbeat는 채널 기본값을 override합니다.channels.<channel>.accounts.<id>.heartbeat(멀티 계정 채널)는 채널별 설정을 override합니다.
에이전트별 하트비트
어떤agents.list[] 항목이든 heartbeat 블록을 포함하면 그 에이전트들만
하트비트를 실행합니다. 에이전트별 블록은 agents.defaults.heartbeat
위에 병합되므로 공통 기본값을 한 번만 설정하고 에이전트별로 override할 수 있습니다.
예시: 에이전트가 두 개이고, 두 번째 에이전트만 하트비트를 실행합니다.
활성 시간 예시
특정 시간대의 업무 시간으로 하트비트를 제한합니다:24/7 설정
하트비트를 하루 종일 실행하려면 다음 패턴 중 하나를 사용하세요:activeHours를 아예 생략합니다(시간대 제한 없음, 기본 동작).- 하루 전체 창을 설정합니다:
activeHours: { start: "00:00", end: "24:00" }.
start와 end 시간을 설정하지 마세요(예: 08:00에서 08:00).
이 경우 너비가 0인 창으로 처리되어 하트비트가 항상 건너뛰어집니다.
멀티 계정 예시
Telegram과 같은 멀티 계정 채널에서 특정 계정을 대상으로 하려면accountId를 사용합니다:
필드 참고
every: 하트비트 간격(duration 문자열, 기본 단위 = 분).model: 하트비트 실행용 선택적 모델 override (provider/model).includeReasoning: 활성화하면 가능할 때 별도의Reasoning:메시지도 전달합니다(/reasoning on과 동일한 형태).lightContext: true이면 하트비트 실행은 가벼운 bootstrap 컨텍스트를 사용하고 워크스페이스 bootstrap 파일에서HEARTBEAT.md만 유지합니다.isolatedSession: true이면 각 하트비트는 이전 대화 기록이 없는 새 세션에서 실행됩니다. cron의sessionTarget: "isolated"와 동일한 격리 패턴을 사용합니다. 하트비트당 토큰 비용을 크게 줄여줍니다. 최대 절감을 위해lightContext: true와 함께 사용하세요. 전달 라우팅은 여전히 메인 세션 컨텍스트를 사용합니다.session: 하트비트 실행용 선택적 세션 키.main(기본값): 에이전트 메인 세션.- 명시적 세션 키(
openclaw sessions --json또는 sessions CLI에서 복사). - 세션 키 형식은 Sessions 및 Groups를 참고하세요.
target:last: 마지막으로 사용한 외부 채널로 전달.- 명시적 채널: 구성된 모든 채널 또는 plugin id(예:
discord,matrix,telegram,whatsapp). none(기본값): 하트비트를 실행하지만 외부로는 전달하지 않음.
directPolicy: direct/DM 전달 동작을 제어합니다:allow(기본값): direct/DM 하트비트 전달 허용.block: direct/DM 전달 억제(reason=dm-blocked).
to: 선택적 수신자 override(채널별 id, 예: WhatsApp의 E.164 또는 Telegram chat id). Telegram topic/thread에는<chatId>:topic:<messageThreadId>를 사용하세요.accountId: 멀티 계정 채널용 선택적 계정 id.target: "last"일 때, 마지막으로 확인된 채널이 계정을 지원하면 그 채널에 적용되고, 그렇지 않으면 무시됩니다. 계정 id가 확인된 채널에 구성된 계정과 일치하지 않으면 전달은 건너뜁니다.prompt: 기본 프롬프트 본문을 override합니다(병합되지 않음).ackMaxChars:HEARTBEAT_OK뒤에 허용되는 최대 문자 수.suppressToolErrorWarnings: true이면 하트비트 실행 중 도구 오류 경고 payload를 억제합니다.activeHours: 하트비트 실행을 특정 시간 창으로 제한합니다.start(HH:MM, 포함, 하루 시작은00:00사용),end(HH:MM, 제외, 하루 끝은24:00허용), 선택적timezone이 있는 객체입니다.- 생략 또는
"user":agents.defaults.userTimezone이 설정되어 있으면 그것을 사용하고, 아니면 호스트 시스템 시간대로 대체합니다. "local": 항상 호스트 시스템 시간대를 사용합니다.- 모든 IANA 식별자(예:
America/New_York): 직접 사용하며, 유효하지 않으면 위"user"동작으로 대체됩니다. - 활성 창에서는
start와end가 같아서는 안 됩니다. 같으면 너비가 0인 창(항상 창 밖)으로 처리됩니다. - 활성 시간 창 밖에서는 창 안의 다음 틱까지 하트비트를 건너뜁니다.
- 생략 또는
전달 동작
- 하트비트는 기본적으로 에이전트의 메인 세션(
agent:<id>:<mainKey>)에서 실행되며,session.scope = "global"일 때는global에서 실행됩니다. 특정 채널 세션(Discord/WhatsApp 등)으로 override하려면session을 설정하세요. session은 실행 컨텍스트에만 영향을 주며, 전달은target과to로 제어됩니다.- 특정 채널/수신자에게 전달하려면
target+to를 설정하세요.target: "last"를 사용하면 전달은 해당 세션의 마지막 외부 채널을 사용합니다. - 하트비트 전달은 기본적으로 direct/DM 대상을 허용합니다. direct 대상 전송은 억제하면서 하트비트 턴은 계속 실행하려면
directPolicy: "block"을 설정하세요. - 메인 큐가 바쁘면 하트비트는 건너뛰고 나중에 다시 시도합니다.
target이 외부 대상이 없는 것으로 확인되면 실행은 계속되지만 발신 메시지는 전송되지 않습니다.showOk,showAlerts,useIndicator가 모두 비활성화되면 실행은 사전에reason=alerts-disabled로 건너뜁니다.- 경고 전달만 비활성화된 경우에도 OpenClaw는 하트비트를 실행하고, 기한이 된 작업 타임스탬프를 갱신하고, 세션 idle 타임스탬프를 복원하고, 외부 경고 payload는 억제할 수 있습니다.
- 하트비트 전용 응답은 세션을 활성 상태로 유지하지 않습니다. 마지막
updatedAt값이 복원되므로 idle 만료는 정상적으로 동작합니다. - 분리된 background tasks는 시스템 이벤트를 큐에 넣고 메인 세션이 무언가를 빨리 인지해야 할 때 하트비트를 깨울 수 있습니다. 이 깨우기 동작이 하트비트 실행을 background task로 만들지는 않습니다.
가시성 제어
기본적으로HEARTBEAT_OK 확인 응답은 숨겨지고 경고 콘텐츠는
전달됩니다. 채널별 또는 계정별로 이를 조정할 수 있습니다:
각 플래그의 역할
showOk: 모델이 OK 전용 응답을 반환할 때HEARTBEAT_OK확인 응답을 전송합니다.showAlerts: 모델이 OK가 아닌 응답을 반환할 때 경고 콘텐츠를 전송합니다.useIndicator: UI 상태 화면용 인디케이터 이벤트를 내보냅니다.
채널별 vs 계정별 예시
일반적인 패턴
| 목표 | 구성 |
|---|---|
| 기본 동작 (OK는 숨김, 경고는 표시) | (구성 불필요) |
| 완전히 무음 (메시지 없음, 인디케이터 없음) | channels.defaults.heartbeat: { showOk: false, showAlerts: false, useIndicator: false } |
| 인디케이터만 사용 (메시지 없음) | channels.defaults.heartbeat: { showOk: false, showAlerts: false, useIndicator: true } |
| 한 채널에서만 OK 표시 | channels.telegram.heartbeat: { showOk: true } |
HEARTBEAT.md (선택 사항)
워크스페이스에HEARTBEAT.md 파일이 있으면 기본 프롬프트는
에이전트가 이를 읽도록 지시합니다. 이를 “하트비트 체크리스트”라고 생각하면 됩니다: 작고, 안정적이며,
30분마다 포함해도 안전한 내용입니다.
일반 실행에서는 기본 에이전트에 대해 하트비트 지침이
활성화된 경우에만 HEARTBEAT.md가 주입됩니다. 0m으로 하트비트 주기를 비활성화하거나
includeSystemPromptSection: false를 설정하면 일반 bootstrap
컨텍스트에서 제외됩니다.
HEARTBEAT.md가 존재하지만 사실상 비어 있는 경우(빈 줄과 # Heading 같은 markdown
헤더만 있는 경우), OpenClaw는 API 호출을 절약하기 위해 하트비트 실행을 건너뜁니다.
이 건너뜀은 reason=empty-heartbeat-file로 보고됩니다.
파일이 없으면 하트비트는 계속 실행되며 모델이 무엇을 할지 결정합니다.
프롬프트 팽창을 피하려면 작게 유지하세요(짧은 체크리스트 또는 리마인더).
예시 HEARTBEAT.md:
tasks: 블록
HEARTBEAT.md는 하트비트 내부에서 간격 기반 점검을 수행하기 위한 작은 구조화된 tasks: 블록도 지원합니다.
예시:
- OpenClaw는
tasks:블록을 파싱하고 각 작업을 자체interval에 따라 검사합니다. - 해당 틱에서 기한이 된 작업만 하트비트 프롬프트에 포함됩니다.
- 기한이 된 작업이 없으면 하트비트는 낭비되는 모델 호출을 피하기 위해 완전히 건너뜁니다(
reason=no-tasks-due). HEARTBEAT.md의 작업 외 콘텐츠는 유지되며 기한이 된 작업 목록 뒤에 추가 컨텍스트로 덧붙여집니다.- 작업 마지막 실행 타임스탬프는 세션 상태(
heartbeatTaskState)에 저장되므로 일반적인 재시작 후에도 간격이 유지됩니다. - 작업 타임스탬프는 하트비트 실행이 정상 응답 경로를 완료한 뒤에만 갱신됩니다. 건너뛴
empty-heartbeat-file/no-tasks-due실행은 작업을 완료된 것으로 표시하지 않습니다.
에이전트가 HEARTBEAT.md를 업데이트할 수 있나요?
네 — 그렇게 하라고 요청하면 가능합니다.HEARTBEAT.md는 에이전트 워크스페이스에 있는 일반 파일일 뿐이므로,
일반 채팅에서 에이전트에게 다음과 같이 말할 수 있습니다:
- “매일 캘린더 확인을 추가하도록
HEARTBEAT.md를 업데이트해.” - “더 짧고 받은편지함 후속 작업에 집중되도록
HEARTBEAT.md를 다시 작성해.”
HEARTBEAT.md에는 비밀 정보(API 키, 전화번호, 개인 토큰)를 넣지 마세요.
이 파일은 프롬프트 컨텍스트의 일부가 됩니다.
수동 깨우기 (온디맨드)
다음 명령으로 시스템 이벤트를 큐에 넣고 즉시 하트비트를 트리거할 수 있습니다:heartbeat가 구성되어 있으면 수동 깨우기는 그 에이전트들의
하트비트를 즉시 각각 실행합니다.
다음 예약 틱까지 기다리려면 --mode next-heartbeat를 사용하세요.
reasoning 전달 (선택 사항)
기본적으로 하트비트는 최종 “응답” payload만 전달합니다. 투명성을 원한다면 다음을 활성화하세요:agents.defaults.heartbeat.includeReasoning: true
Reasoning: 접두사가 붙은 별도 메시지도 전달합니다
(reasoning on과 동일한 형태). 이는 에이전트가 여러 세션/codex를 관리하고 있을 때
왜 사용자에게 알림을 보내기로 결정했는지 보고 싶을 때 유용할 수 있습니다.
하지만 원하지 않는 더 많은 내부 세부 정보가 드러날 수도 있습니다. 그룹 채팅에서는
끄는 편이 좋습니다.
비용 고려
하트비트는 전체 에이전트 턴을 실행합니다. 간격이 짧을수록 토큰을 더 많이 사용합니다. 비용을 줄이려면:- 전체 대화 기록 전송을 피하기 위해
isolatedSession: true를 사용하세요(실행당 약 100K 토큰에서 약 2~5K로 감소). - bootstrap 파일을
HEARTBEAT.md로만 제한하려면lightContext: true를 사용하세요. - 더 저렴한
model을 설정하세요(예:ollama/llama3.2:1b). HEARTBEAT.md를 작게 유지하세요.- 내부 상태 업데이트만 원한다면
target: "none"을 사용하세요.
관련 항목
- Automation & Tasks — 모든 자동화 메커니즘 한눈에 보기
- Background Tasks — 분리된 작업이 추적되는 방식
- Timezone — 시간대가 하트비트 예약에 미치는 영향
- Troubleshooting — 자동화 문제 디버깅