Cron Management
Critical Rules
- •
sessionTarget/payload pairing is mandatory:
- •
sessionTarget: "main"requirespayload.kind: "systemEvent" - •
sessionTarget: "isolated"requirespayload.kind: "agentTurn" - •Mismatches cause silent failures
- •
- •
Always verify after creating: After
cron add, immediately runcron listto confirm the job exists, is enabled, andnextRunAtMsis 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
tzfor 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,nextRunAtMsis correct - •For recurring jobs, consider
cron run <jobId>withmode: "force"to test immediately - •After test run, check
cron runsforstatus: "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
// List all (including disabled)
{ "action": "list", "includeDisabled": true }
// Update schedule
{ "action": "update", "jobId": "<id>", "patch": { "schedule": { "kind": "every", "everyMs": 7200000 } } }
// Disable/enable
{ "action": "update", "jobId": "<id>", "patch": { "enabled": false } }
// Force run for testing
{ "action": "run", "jobId": "<id>" }
// Check run history
{ "action": "runs", "jobId": "<id>" }
// Delete
{ "action": "remove", "jobId": "<id>" }