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:

  1. Starts an isolated session (separate from your main conversation)
  2. Processes the prompt with full access to its tools
  3. Sends the result to the specified channel
  4. 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

  1. You create a HEARTBEAT.md workspace file with check-in instructions
  2. The agent reads it on each heartbeat
  3. If everything's fine, the agent responds with HEARTBEAT_OK — and the message is not delivered
  4. 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 under max_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:

  1. User talks to the agent on Telegram and asks for a daily report
  2. Agent schedules a schedule_cron_job with channel: "last" (or channel: "telegram")
  3. Every day at the scheduled time, the agent runs independently
  4. 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.