Cron 작업 (Gateway 스케줄러)

Cron vs Heartbeat? 각각을 언제 사용해야 하는지 안내는 Cron vs Heartbeat를 참조하세요.

Cron은 Gateway의 내장 스케줄러입니다. 작업을 유지하고, 적절한 시간에 agent를 깨우며, 선택적으로 출력을 채팅으로 다시 전달할 수 있습니다.

"매일 아침 실행" 또는 *"20분 후에 agent를 호출"*과 같은 작업이 필요하다면, cron이 적합한 메커니즘입니다.

요약

  • Cron은 Gateway 내부에서 실행됩니다 (모델 내부가 아님).
  • 작업은 ~/.openclaw/cron/ 아래에 저장되므로 재시작 시에도 일정이 유지됩니다.
  • 두 가지 실행 스타일:
    • Main session: 시스템 이벤트를 대기열에 추가한 다음 다음 heartbeat에서 실행.
    • Isolated: cron:<jobId>에서 전용 agent 턴을 실행하며, 선택적으로 출력 전달.
  • 웨이크업은 일급 기능: 작업은 "지금 깨우기" vs "다음 heartbeat"를 요청할 수 있습니다.

초보자 친화적 개요

Cron 작업을 언제 실행할지 + 무엇을 할지로 생각하세요.

  1. 일정 선택

    • 일회성 알림 → schedule.kind = "at" (CLI: --at)
    • 반복 작업 → schedule.kind = "every" 또는 schedule.kind = "cron"
    • ISO 타임스탬프에 시간대가 생략되면 UTC로 처리됩니다.
  2. 실행 위치 선택

    • sessionTarget: "main" → main 컨텍스트와 함께 다음 heartbeat에서 실행.
    • sessionTarget: "isolated"cron:<jobId>에서 전용 agent 턴 실행.
  3. 페이로드 선택

    • Main session → payload.kind = "systemEvent"
    • Isolated session → payload.kind = "agentTurn"

선택 사항: deleteAfterRun: true는 성공한 일회성 작업을 저장소에서 제거합니다.

개념

작업 (Jobs)

Cron 작업은 다음을 포함하는 저장된 레코드입니다:

  • schedule (언제 실행할지),
  • payload (무엇을 할지),
  • 선택적 delivery (출력을 어디로 보낼지).
  • 선택적 agent 바인딩 (agentId): 특정 agent에서 작업을 실행; 누락되었거나 알 수 없는 경우 gateway는 기본 agent로 대체합니다.

작업은 안정적인 jobId로 식별됩니다 (CLI/Gateway API에서 사용). Agent 도구 호출에서 jobId가 표준이며, 레거시 id는 호환성을 위해 허용됩니다. 작업은 deleteAfterRun: true를 통해 성공한 일회성 실행 후 자동 삭제될 수 있습니다.

일정 (Schedules)

Cron은 세 가지 일정 종류를 지원합니다:

  • at: 일회성 타임스탬프 (epoch 이후 ms). Gateway는 ISO 8601을 허용하고 UTC로 변환합니다.
  • every: 고정 간격 (ms).
  • cron: 선택적 IANA 시간대가 있는 5필드 cron 표현식.

Cron 표현식은 croner를 사용합니다. 시간대가 생략되면 Gateway 호스트의 로컬 시간대가 사용됩니다.

Main vs isolated 실행

Main session 작업 (시스템 이벤트)

Main 작업은 시스템 이벤트를 대기열에 추가하고 선택적으로 heartbeat 러너를 깨웁니다. payload.kind = "systemEvent"를 사용해야 합니다.

  • wakeMode: "next-heartbeat" (기본값): 이벤트가 다음 예약된 heartbeat를 기다립니다.
  • wakeMode: "now": 이벤트가 즉시 heartbeat 실행을 트리거합니다.

이것은 일반적인 heartbeat 프롬프트 + main session 컨텍스트를 원할 때 가장 적합합니다. Heartbeat를 참조하세요.

Isolated 작업 (전용 cron 세션)

Isolated 작업은 세션 cron:<jobId>에서 전용 agent 턴을 실행합니다.

주요 동작:

  • 프롬프트 앞에 추적 가능성을 위해 [cron:<jobId> <job name>]이 붙습니다.
  • 각 실행은 새로운 세션 id로 시작합니다 (이전 대화 이어받기 없음).
  • 요약이 main session에 게시됩니다 (접두사 Cron, 설정 가능).
  • wakeMode: "now"는 요약 게시 후 즉시 heartbeat를 트리거합니다.
  • payload.deliver: true인 경우 출력이 채널로 전달되며, 그렇지 않으면 내부에 유지됩니다.

main 채팅 기록을 스팸하지 않아야 하는 시끄럽거나 빈번하거나 "백그라운드 작업"에 isolated 작업을 사용하세요.

페이로드 형태 (무엇을 실행할지)

두 가지 페이로드 종류가 지원됩니다:

  • systemEvent: main session 전용, heartbeat 프롬프트를 통해 라우팅.
  • agentTurn: isolated session 전용, 전용 agent 턴 실행.

일반적인 agentTurn 필드:

  • message: 필수 텍스트 프롬프트.
  • model / thinking: 선택적 오버라이드 (아래 참조).
  • timeoutSeconds: 선택적 타임아웃 오버라이드.
  • deliver: true로 설정하여 출력을 채널 대상으로 전송.
  • channel: last 또는 특정 채널.
  • to: 채널별 대상 (전화/채팅/채널 id).
  • bestEffortDeliver: 전달 실패 시 작업이 실패하지 않도록 함.

Isolation 옵션 (session=isolated에만 해당):

  • postToMainPrefix (CLI: --post-prefix): main의 시스템 이벤트 접두사.
  • postToMainMode: summary (기본값) 또는 full.
  • postToMainMaxChars: postToMainMode=full일 때 최대 문자 수 (기본값 8000).

모델 및 thinking 오버라이드

Isolated 작업 (agentTurn)은 모델 및 thinking 레벨을 오버라이드할 수 있습니다:

  • model: Provider/모델 문자열 (예: anthropic/claude-sonnet-4-20250514) 또는 별칭 (예: opus)
  • thinking: Thinking 레벨 (off, minimal, low, medium, high, xhigh; GPT-5.2 + Codex 모델만)

참고: Main session 작업에도 model을 설정할 수 있지만, 공유 main session 모델이 변경됩니다. 예상치 못한 컨텍스트 변경을 피하기 위해 isolated 작업에만 모델 오버라이드를 권장합니다.

해결 우선순위:

  1. 작업 페이로드 오버라이드 (최고)
  2. Hook별 기본값 (예: hooks.gmail.model)
  3. Agent 구성 기본값

전달 (채널 + 대상)

Isolated 작업은 출력을 채널로 전달할 수 있습니다. 작업 페이로드는 다음을 지정할 수 있습니다:

  • channel: whatsapp / telegram / discord / slack / mattermost (plugin) / signal / imessage / last
  • to: 채널별 수신자 대상

channel 또는 to가 생략되면, cron은 main session의 "last route" (agent가 마지막으로 응답한 위치)로 대체될 수 있습니다.

전달 참고사항:

  • to가 설정되면, deliver가 생략되어도 cron은 agent의 최종 출력을 자동 전달합니다.
  • 명시적인 to 없이 last route 전달을 원할 때는 deliver: true를 사용하세요.
  • to가 있어도 출력을 내부에 유지하려면 deliver: false를 사용하세요.

대상 형식 참고:

  • Slack/Discord/Mattermost (plugin) 대상은 모호함을 피하기 위해 명시적 접두사를 사용해야 합니다 (예: channel:<id>, user:<id>).
  • Telegram 토픽은 :topic: 형식을 사용해야 합니다 (아래 참조).

Telegram 전달 대상 (토픽 / 포럼 스레드)

Telegram은 message_thread_id를 통해 포럼 토픽을 지원합니다. Cron 전달의 경우 to 필드에 토픽/스레드를 인코딩할 수 있습니다:

  • -1001234567890 (채팅 id만)
  • -1001234567890:topic:123 (권장: 명시적 토픽 마커)
  • -1001234567890:123 (단축형: 숫자 접미사)

telegram:... / telegram:group:...와 같은 접두사 대상도 허용됩니다:

  • telegram:group:-1001234567890:topic:123

저장소 및 기록

  • 작업 저장소: ~/.openclaw/cron/jobs.json (Gateway 관리 JSON).
  • 실행 기록: ~/.openclaw/cron/runs/<jobId>.jsonl (JSONL, 자동 정리).
  • 저장소 경로 오버라이드: 구성에서 cron.store.

구성

{
  cron: {
    enabled: true, // 기본값 true
    store: "~/.openclaw/cron/jobs.json",
    maxConcurrentRuns: 1 // 기본값 1
  }
}

Cron 완전히 비활성화:

  • cron.enabled: false (구성)
  • OPENCLAW_SKIP_CRON=1 (환경 변수)

CLI 빠른 시작

일회성 알림 (UTC ISO, 성공 후 자동 삭제):

openclaw cron add \
  --name "Send reminder" \
  --at "2026-01-12T18:00:00Z" \
  --session main \
  --system-event "Reminder: submit expense report." \
  --wake now \
  --delete-after-run

일회성 알림 (main session, 즉시 깨우기):

openclaw cron add \
  --name "Calendar check" \
  --at "20m" \
  --session main \
  --system-event "Next heartbeat: check calendar." \
  --wake now

반복 isolated 작업 (WhatsApp으로 전달):

openclaw cron add \
  --name "Morning status" \
  --cron "0 7 * * *" \
  --tz "America/Los_Angeles" \
  --session isolated \
  --message "Summarize inbox + calendar for today." \
  --deliver \
  --channel whatsapp \
  --to "+15551234567"

반복 isolated 작업 (Telegram 토픽으로 전달):

openclaw cron add \
  --name "Nightly summary (topic)" \
  --cron "0 22 * * *" \
  --tz "America/Los_Angeles" \
  --session isolated \
  --message "Summarize today; send to the nightly topic." \
  --deliver \
  --channel telegram \
  --to "-1001234567890:topic:123"

모델 및 thinking 오버라이드가 있는 isolated 작업:

openclaw cron add \
  --name "Deep analysis" \
  --cron "0 6 * * 1" \
  --tz "America/Los_Angeles" \
  --session isolated \
  --message "Weekly deep analysis of project progress." \
  --model "opus" \
  --thinking high \
  --deliver \
  --channel whatsapp \
  --to "+15551234567"

Agent 선택 (다중 agent 설정):
```bash
# 작업을 agent "ops"에 고정 (해당 agent가 없으면 기본값으로 대체)
openclaw cron add --name "Ops sweep" --cron "0 6 * * *" --session isolated --message "Check ops queue" --agent ops

# 기존 작업의 agent 전환 또는 지우기
openclaw cron edit <jobId> --agent ops
openclaw cron edit <jobId> --clear-agent

수동 실행 (디버그):
```bash
openclaw cron run <jobId> --force

기존 작업 편집 (필드 패치):

openclaw cron edit <jobId> \
  --message "Updated prompt" \
  --model "opus" \
  --thinking low

실행 기록:

openclaw cron runs --id <jobId> --limit 50

작업 생성 없이 즉시 시스템 이벤트:

openclaw system event --mode now --text "Next heartbeat: check battery."

Gateway API 표면

  • cron.list, cron.status, cron.add, cron.update, cron.remove
  • cron.run (강제 또는 예정), cron.runs 작업 없이 즉시 시스템 이벤트를 사용하려면 openclaw system event를 사용하세요.

문제 해결

"아무것도 실행되지 않음"

  • Cron이 활성화되어 있는지 확인: cron.enabledOPENCLAW_SKIP_CRON.
  • Gateway가 지속적으로 실행되고 있는지 확인 (cron은 Gateway 프로세스 내부에서 실행됨).
  • cron 일정의 경우: 시간대 (--tz) vs 호스트 시간대를 확인.

Telegram이 잘못된 위치로 전달됨

  • 포럼 토픽의 경우 -100…:topic:<id>를 사용하여 명시적이고 모호하지 않게 하세요.
  • 로그 또는 저장된 "last route" 대상에서 telegram:... 접두사가 보이면 정상입니다; cron 전달은 이를 허용하며 여전히 토픽 ID를 올바르게 파싱합니다.