| name | cron-management |
| description | Create, verify, and manage OpenClaw cron jobs reliably. Use when the user asks to schedule tasks, set reminders, create recurring jobs, or manage existing cron jobs. Triggers on: "remind me", "schedule", "cron", "every morning", "in 20 minutes", "recurring task", "set a timer", "lembrete", "agendar", "todo dia", "daqui a". Ensures correct sessionTarget/payload pairing, verifies jobs after creation, and handles delivery, isolation, and model overrides properly.
|
Cron Management
Critical Rules
-
sessionTarget/payload pairing is mandatory:
sessionTarget: "main" requires payload.kind: "systemEvent"
sessionTarget: "isolated" requires payload.kind: "agentTurn"
- Mismatches cause silent failures
-
Always verify after creating: After cron add, immediately run cron list to confirm the job exists, is enabled, and nextRunAtMs is in the future.
-
Always use wakeMode: "now" for time-sensitive jobs. Default "next-heartbeat" waits for the next heartbeat cycle which may be minutes away.
-
Timezone matters: Always set tz for cron expressions. Without it, the Gateway host's local timezone is used (likely UTC on servers).
Decision Tree: Which Job Type?
User wants scheduled task
├── Simple reminder/nudge to self (main agent context needed)?
│ → sessionTarget: "main", payload: systemEvent
│ → The text becomes a system event processed during heartbeat
│ → Agent sees it with full main conversation context
│
└── Task requiring agent work (generate, analyze, fetch, summarize)?
→ sessionTarget: "isolated", payload: agentTurn
→ Runs in dedicated session cron:<jobId>
→ Summary posted back to main session
→ Can deliver output to WhatsApp/Telegram/Slack/Discord
Schedule Types
| Need | Kind | Example |
|---|
| Run once at specific time | at | { "kind": "at", "atMs": <epoch-ms> } |
| Run once in X minutes | at | { "kind": "at", "at": "20m" } — normalizer accepts duration strings |
| Run every N hours | every | { "kind": "every", "everyMs": 3600000 } |
| Run on cron schedule | cron | { "kind": "cron", "expr": "0 7 * * *", "tz": "America/Sao_Paulo" } |
One-shot jobs (at): After successful run, they auto-disable. Use deleteAfterRun: true to auto-delete instead.
Creating Jobs via the cron Tool
Use action: "add" with a job object. See references/tool-schemas.md for complete schemas and examples.
Minimal one-shot reminder (main session)
{
"action": "add",
"job": {
"name": "Reminder: <descriptive name>",
"schedule": { "kind": "at", "at": "20m" },
"sessionTarget": "main",
"wakeMode": "now",
"payload": { "kind": "systemEvent", "text": "Reminder: <what to do>" },
"deleteAfterRun": true
}
}
Recurring isolated job with delivery
{
"action": "add",
"job": {
"name": "Morning brief",
"schedule": { "kind": "cron", "expr": "0 10 * * *", "tz": "America/Sao_Paulo" },
"sessionTarget": "isolated",
"wakeMode": "now",
"payload": {
"kind": "agentTurn",
"message": "<clear, self-contained prompt>",
"deliver": true,
"channel": "whatsapp",
"to": "+5531XXXXXXXXX",
"bestEffortDeliver": true
},
"isolation": { "postToMainMode": "summary" }
}
}
Writing Effective Cron Prompts
The cron prompt runs in an isolated session with no prior conversation context. Write prompts that are:
- Self-contained: Include all context needed. The isolated agent has no memory of previous conversations.
- Specific about output: State exactly what format/length you want. Without guidance, responses can be long and get truncated during delivery.
- Aware of available tools: The isolated agent has access to all configured tools (web search, file read/write, workspace files, messaging, etc.). Reference them if the task requires them.
- Concise about delivery: If delivering to chat, mention "keep response under N words" or "respond in 2-3 short paragraphs" — long messages get truncated by channel limits (WhatsApp ~4096 chars, Telegram ~4096 chars).
Good prompt examples
"Leia o arquivo ~/workspace/tarefas.md, resuma as tarefas pendentes em no máximo 3 linhas, e envie."
"Check the calendar for today's meetings. List them as bullet points. Keep under 500 chars."
Bad prompt examples
"Summarize updates."
(No context about what updates, where to find them, or output format)
"Do the weekly report and send it to everyone."
(No specifics about report content, data sources, recipients, or format constraints)
Using contextMessages for Reminders
When creating reminders from a conversation, use contextMessages: 3-5 to attach recent conversation context to the job's text. This way, when the reminder fires, it carries enough context about what was being discussed.
{
"action": "add",
"contextMessages": 5,
"job": {
"name": "Follow up on discussion",
"schedule": { "kind": "at", "at": "2h" },
"sessionTarget": "main",
"wakeMode": "now",
"payload": { "kind": "systemEvent", "text": "Follow up: revisit the API design discussion" },
"deleteAfterRun": true
}
}
Post-Creation Verification Checklist
After every cron add, verify:
cron list — job appears, enabled: true, nextRunAtMs is correct
- For recurring jobs, consider
cron run <jobId> with mode: "force" to test immediately
- After test run, check
cron runs for status: "ok" and verify the summary/output
- If delivering to a channel, confirm the message arrived at the target
Common Pitfalls
| Pitfall | Fix |
|---|
| Job created but never runs | Check wakeMode: "now" is set; check Gateway is running |
| Isolated job output is empty/truncated | Make prompt self-contained; add output length constraints |
| Delivery fails silently | Use bestEffortDeliver: true to avoid job failure; check to format |
| Wrong timezone | Always set tz explicitly for cron expressions |
"main" job with "agentTurn" payload | Fatal mismatch — use "systemEvent" for main |
| One-shot job stays in list after running | Normal — it disables. Use deleteAfterRun: true to auto-clean |
| Agent can't find files/context in isolated job | Isolated session is fresh — specify full paths, include needed context in prompt |
contextMessages not working | Only works with systemEvent payload kind |
Managing Existing Jobs
{ "action": "list", "includeDisabled": true }
{ "action": "update", "jobId": "<id>", "patch": { "schedule": { "kind": "every", "everyMs": 7200000 } } }
{ "action": "update", "jobId": "<id>", "patch": { "enabled": false } }
{ "action": "run", "jobId": "<id>" }
{ "action": "runs", "jobId": "<id>" }
{ "action": "remove", "jobId": "<id>" }