Cron Tool

Schedule assistant tasks to run at specific times or intervals.

Each cron job now answers three separate questions:

  1. What prompt should run?
  2. What should happen to the result?
  3. Should the result be persisted?

The result handling modes are:

  • store_only - run the task and keep the result internal
  • deliver - run the task and deliver the final assistant result to channels
  • handoff_main - run the task, then pass the result into the main agent flow

Actions

status

Get cron service status.

{
  "action": "status"
}

list

List all jobs with full details.

{
  "action": "list"
}

add

Create a new scheduled assistant task.

{
  "action": "add",
  "name": "morning-briefing",
  "description": "Daily morning briefing",
  "scheduleType": "cron",
  "cronExpr": "0 8 * * *",
  "timezone": "America/New_York",
  "prompt": "Give me a morning briefing: weather, calendar, news",
  "resultMode": "deliver"
}
ParameterRequiredDescription
nameYesJob identifier
descriptionNoHuman-readable description
scheduleTypeYesat, every, or cron
promptYesAssistant task prompt to execute
resultModeYesstore_only, deliver, or handoff_main
persistNoPersist result override. Omit to use smart defaults
channelNoOptional future delivery hint for deliver mode
toNoOptional future delivery target hint for deliver mode
bestEffortNoOptional future delivery hint for deliver mode
timeoutSecondsNoOptional per-job timeout override
enabledNoEnable job (default: true)

update

Modify an existing job.

{
  "action": "update",
  "id": "abc123",
  "enabled": false
}

remove

Delete a job.

{
  "action": "remove",
  "id": "abc123"
}

run

Execute a job immediately.

{
  "action": "run",
  "id": "abc123"
}

runs

View job execution history.

{
  "action": "runs",
  "id": "abc123"
}

kill

Clear stuck running state.

{
  "action": "kill",
  "id": "abc123"
}

wake

Send a wake event to inject text or trigger heartbeat.

{
  "action": "wake",
  "text": "Check for new emails",
  "mode": "now"
}
ParameterDescription
textText to inject
modenow or next-heartbeat

Schedule Types

at — One-shot

Run once at a specific time.

{
  "scheduleType": "at",
  "at": "+5m"
}

Formats:

  • Unix milliseconds: 1703275200000
  • ISO 8601: 2024-12-22T15:00:00Z
  • Relative: +5m, +2h, +1d

every — Interval

Run repeatedly at intervals.

{
  "scheduleType": "every",
  "every": "30m"
}

Formats: 30s, 5m, 2h, 1d

cron — Cron expression

Standard 5-field cron expression.

{
  "scheduleType": "cron",
  "cronExpr": "0 9 * * 1-5",
  "timezone": "America/New_York"
}

Format: minute hour day month weekday

Examples:

  • 0 9 * * * — 9 AM daily
  • 0 9 * * 1-5 — 9 AM weekdays
  • */15 * * * * — Every 15 minutes
  • 0 0 1 * * — First of month at midnight

Result Modes

ModeDescription
store_onlyRun the task and do not deliver the final result
deliverRun the task and deliver the final assistant result to channels
handoff_mainRun the task first, then pass its result into the main agent flow

All cron tasks run as scheduled assistant tasks. The runtime handles isolation and follow-up behavior based on the result mode rather than a persisted sessionTarget field.

Persistence

By default:

  • store_only persists the result
  • deliver persists the result
  • handoff_main persists the result

Set "persist": false to suppress persistence for noisy jobs such as threshold checks that usually produce nothing interesting.

Legacy Migration

Older cron files that still use the legacy payload / sessionTarget schema are migrated automatically on load.

  • A backup is written to jobs.json.bak
  • The file is rewritten in native format
  • Legacy systemEvent jobs are converted to handoff_main
  • Malformed legacy jobs fail load loudly instead of being silently skipped

Configuration

{
  "cron": {
    "enabled": true,
    "jobTimeoutMinutes": 30,
    "heartbeat": {
      "enabled": true,
      "interval": "30m",
      "prompt": "Check HEARTBEAT.md for tasks"
    }
  }
}
OptionDefaultDescription
enabledtrueEnable cron scheduler
jobTimeoutMinutes30Job execution timeout (0 = none)
heartbeat.enabledtrueEnable heartbeat polling
heartbeat.interval30mHeartbeat check interval
heartbeat.prompt-Custom heartbeat prompt

Examples

Remind me in 20 minutes:

{
  "action": "add",
  "name": "reminder",
  "scheduleType": "at",
  "at": "+20m",
  "prompt": "Reminder: Take a break!",
  "resultMode": "deliver"
}

Check emails every hour:

{
  "action": "add",
  "name": "email-check",
  "scheduleType": "every",
  "every": "1h",
  "prompt": "Check for important emails",
  "resultMode": "store_only",
  "persist": false
}

Daily standup summary:

{
  "action": "add",
  "name": "standup",
  "scheduleType": "cron",
  "cronExpr": "0 9 * * 1-5",
  "timezone": "America/New_York",
  "prompt": "Summarize today's calendar and pending tasks",
  "resultMode": "handoff_main"
}

See Also