Agents that act on their own schedule. Set up reminders, recurring reports, and automated check-ins — your agent runs in the background and delivers results to Slack, Telegram, WhatsApp, or any connected channel.
What are scheduled tasks?
Agents can schedule work to happen later — a one-time delay, a specific future time, or a recurring cron schedule. When the task fires, the agent runs with its full context (tools, memory, workspace) and can optionally deliver the result to a connected channel.
There are three scheduling tools, each designed for a different pattern:
| Tool | Purpose | Delivers to channel? |
|---|---|---|
schedule_task |
Run a specific tool in the background | No |
schedule_cron_job |
Run a full agent turn with a custom prompt | Yes (optional) |
schedule_heartbeat |
Periodic check-in with smart suppression | Yes (when something needs attention) |
These are agent tools, not REST API endpoints. You trigger them through conversation — ask the agent to schedule something, and it uses the appropriate tool.
schedule_task
Runs a specific tool at a scheduled time. The execution is silent — results are stored but not delivered to the user.
What you'd say to the agent:
"Check the API status endpoint every hour."
What the agent does:
The agent calls schedule_task with the tool name, parameters, and a schedule:
{
"tool_name": "check_api_status",
"tool_parameters": { "endpoint": "/health" },
"schedule_type": "recurring",
"cron_expression": "0 * * * *",
"description": "Hourly API health check"
}
Schedule types
| Type | Field | Example |
|---|---|---|
| Delay (relative) | delay_seconds |
300 → runs in 5 minutes |
| Specific time | execution_time |
"2026-03-15T14:00:00Z" → runs at that moment |
| Recurring | cron_expression |
"0 9 * * 1-5" → weekdays at 9 AM UTC |
When to use
- Automated data syncs that don't need user-facing output
- Periodic background checks
- Deferred tool execution ("run this import tonight")
schedule_cron_job
Runs a full agent turn — the agent processes a custom prompt with its complete tool set, then optionally delivers the response to a channel.
What you'd say to the agent:
"Send me a daily summary of open tickets every morning at 9 AM on Telegram."
What the agent does:
{
"message": "Summarize all open support tickets and highlight any that are overdue.",
"cron_expression": "0 9 * * *",
"description": "Daily ticket summary",
"deliver": true,
"channel": "telegram",
"to": "123456789"
}
When the task fires, the agent:
- Starts an isolated session (separate from your main conversation)
- Processes the prompt with full access to its tools
- Sends the result to the specified channel
- Optionally posts a summary back to your main conversation thread
Parameters
| Parameter | Required | Default | Description |
|---|---|---|---|
message |
yes | — | The prompt the agent processes |
cron_expression |
one of these | — | Recurring schedule (5-field cron) |
delay_seconds |
one of these | — | One-time delay in seconds |
execution_time |
one of these | — | One-time ISO 8601 timestamp |
deliver |
no | true |
Send result to a channel |
channel |
no | "last" |
Target: "last", "telegram", "slack", "whatsapp", "discord" |
to |
depends | — | Recipient ID (chat ID, phone number, channel ID). Required when channel is a specific platform |
description |
no | — | Human-readable task name |
model |
no | agent default | Override the LLM model for this job |
post_to_main |
no | true |
Post a summary back to the originating conversation |
Channel targeting
| Value | Behavior |
|---|---|
"last" (default) |
Replies on whatever channel the user last messaged from |
"telegram" |
Sends to a Telegram chat (requires to = chat ID) |
"slack" |
Sends to a Slack channel (requires to = channel ID) |
"whatsapp" |
Sends to WhatsApp (requires to = phone number) |
"discord" |
Sends to a Discord channel (requires to = channel ID) |
Examples
One-time reminder:
"Remind me to review the PR in 30 minutes."
{
"message": "Reminder: review the open pull request.",
"delay_seconds": 1800,
"deliver": true,
"channel": "last"
}
Weekly report:
"Every Monday at 8:30 AM, compile the week's metrics and send them to Slack."
{
"message": "Pull this week's metrics and format them as a summary.",
"cron_expression": "30 8 * * 1",
"deliver": true,
"channel": "slack",
"to": "C01234ABCDE"
}
Silent background job:
"Every 6 hours, check for stale records and clean them up. Don't message me about it."
{
"message": "Query for records older than 30 days and archive them.",
"cron_expression": "0 */6 * * *",
"deliver": false
}
schedule_heartbeat
A specialized recurring check-in. The agent reads a HEARTBEAT.md file from its workspace, runs its instructions, and only sends a message when something needs attention.
What you'd say to the agent:
"Check on my systems every morning at 9 AM. Only message me if something's wrong."
What the agent does:
{
"cron_expression": "0 9 * * *",
"target": "telegram",
"to": "123456789",
"active_hours": {
"start": "09:00",
"end": "17:00",
"timezone": "America/New_York"
}
}
How it works
- You create a
HEARTBEAT.mdworkspace file with check-in instructions - The agent reads it on each heartbeat
- If everything's fine, the agent responds with
HEARTBEAT_OK— and the message is not delivered - If something needs attention, the agent responds with details — and the message is delivered
The HEARTBEAT_OK convention
The agent's HEARTBEAT.md instructions should tell it to respond with HEARTBEAT_OK when nothing needs action:
Check these items:
- Are there any failed jobs in the queue?
- Any error alerts in the last hour?
- Are response times within normal range?
If everything looks good, reply: HEARTBEAT_OK
If anything needs attention, describe what's wrong.
When the agent responds:
"HEARTBEAT_OK"→ delivery suppressed (silent acknowledgment)"HEARTBEAT_OK - all 3 checks passed"→ delivery suppressed (short addendum undermax_ack_chars)"HEARTBEAT_OK - Found 12 failed jobs: ..."(long response) → delivery proceeds
Parameters
| Parameter | Required | Default | Description |
|---|---|---|---|
cron_expression |
yes | — | Recurring schedule (5-field cron) |
target |
no | "last" |
Delivery target: "last", "none", "telegram", "slack", etc. |
to |
depends | — | Recipient ID. Required for specific platforms |
active_hours.start |
no | — | Start of active window ("HH:MM", 24-hour) |
active_hours.end |
no | — | End of active window |
active_hours.timezone |
no | UTC | IANA timezone (e.g., "America/Los_Angeles") |
max_ack_chars |
no | 300 |
Max characters after HEARTBEAT_OK before triggering delivery |
description |
no | — | Human-readable task name |
Active hours
Heartbeats outside the active window are skipped silently. This prevents 3 AM alerts when you've told the agent to only check during business hours.
Managing scheduled tasks
Agents can inspect and cancel their own scheduled tasks during conversation:
List tasks:
"What tasks do I have scheduled?"
The agent calls list_scheduled_tasks and returns a summary with task IDs, descriptions, schedules, and next run times.
Cancel a task:
"Cancel the daily report."
The agent calls cancel_scheduled_task with the task ID.
Get task details:
"Show me the details of task xyz."
The agent calls get_scheduled_task with the task ID.
Cron expression reference
Schedules use standard 5-field cron syntax. Times are in UTC unless a timezone is specified (heartbeat active_hours only).
┌───────────── minute (0-59)
│ ┌───────────── hour (0-23)
│ │ ┌───────────── day of month (1-31)
│ │ │ ┌───────────── month (1-12)
│ │ │ │ ┌───────────── day of week (0-6, Sunday = 0)
* * * * *
| Expression | Meaning |
|---|---|
0 9 * * * |
Every day at 9:00 AM |
0 9 * * 1-5 |
Weekdays at 9:00 AM |
30 8 * * 1 |
Every Monday at 8:30 AM |
0 */6 * * * |
Every 6 hours |
*/30 * * * * |
Every 30 minutes |
0 0 1 * * |
First day of every month at midnight |
0 12 * * * |
Every day at noon |
How channels and scheduled tasks work together
Scheduled tasks can deliver results to any connected channel. The flow:
- User talks to the agent on Telegram and asks for a daily report
- Agent schedules a
schedule_cron_jobwithchannel: "last"(orchannel: "telegram") - Every day at the scheduled time, the agent runs independently
- The result is sent to Telegram as a message from the bot
The agent has its full tool set during scheduled runs — it can query APIs, search knowledge graphs, read memory stores, and compose a real response. It's not just a static reminder; it's a full agent turn.