agent-swarm.devagent-swarm.dev
Concepts

Scheduled Tasks

Schedule recurring or one-time AI agent tasks with cron expressions and delayed execution — automate daily reports, polling, and time-driven workflows across the swarm.

Agent Swarm supports both recurring and one-time schedules to automate work. A schedule can create an agent task (targetType: "agent-task"), trigger a workflow directly, or run a saved catalog script without an agent session in the loop.

Creating a Recurring Schedule

create-schedule(
  name: "daily-standup",
  taskTemplate: "Generate a daily standup report summarizing yesterday's completed tasks",
  cronExpression: "0 9 * * *",
  timezone: "America/New_York",
  targetType: "agent-task"
)

Or use interval-based scheduling:

create-schedule(
  name: "health-check",
  scriptName: "service-health-check",
  scriptArgs: { channel: "ops" },
  targetType: "script",
  intervalMs: 3600000
)

Creating a One-Time Schedule

One-time schedules run once and then auto-disable. Use delayMs for a relative delay or runAt for an absolute time:

create-schedule(
  name: "deploy-reminder",
  scheduleType: "one_time",
  taskTemplate: "Remind the team about the deployment at 3 PM",
  delayMs: 1800000
)
create-schedule(
  name: "scheduled-report",
  scheduleType: "one_time",
  taskTemplate: "Generate the quarterly report",
  runAt: "2026-03-15T09:00:00Z"
)

Deferring until another task finishes

Use defer-task when your current task needs to resume after other work finishes:

{
  "taskId": "<current-task-id>",
  "delayMs": 1800000,
  "wakeOn": { "event": "settled", "taskId": "<build-task-id>" },
  "summary": "Submitted the build; validation is pending.",
  "note": "Read the build result, then verify the deployment."
}

The call completes the current task and schedules one continuation for the same agent. settled wakes on completion, failure, or cancellation; use task.completed or task.failed to watch only that outcome. Cancellation does not match either named event. The required delay or runAt is the latest scheduled wake-up time if the event does not arrive.

To wait for several tasks, replace taskId inside wakeOn with taskIds:

"wakeOn": {
  "event": "settled",
  "taskIds": ["<build-task-id>", "<test-task-id>"],
  "mode": "all"
}

mode defaults to all: every member must match the requested event. Set mode: "any" to wake on the first matching member. For example, all with settled accepts a mix of successes, failures, and cancellations; all with task.completed cannot wake early if one member fails or is cancelled. The single deadline bounds the whole set.

A worker task normally creates a lead follow-up when it finishes. When its settlement is the one that wakes the wait, and the wake-up task goes to the agent the follow-up would target, the engine skips that follow-up: the wake-up task reviews the result. The task log of the settled task records a task_follow_up_suppressed event naming the woken waiter. The follow-up is kept when no wait is woken, including an all wait whose other members are still pending, a wait already woken or cancelled, or a wait owned by a different agent. It is also kept when the task's followUpConfig sets onCompleted or onFailed for that outcome, because the wake-up task does not carry those instructions.

Provide exactly one of taskId or a nonempty, unique taskIds array. Every watched task must exist, be nonterminal, and differ from the current task. If any member is already terminal, the whole request is rejected before completing the current task or creating a schedule. Read those results and submit only unfinished IDs; terminal IDs are never silently counted as satisfied.

When a member defers, its completion does not count as a match. That member follows its resume task across further deferrals without changing the set's deadline. Disabling or deleting its successor schedule before it runs makes the parent's completion eligible on reconciliation.

When a member is superseded, the wait follows its resume child without waking or changing the deadline. This works whether the child is created before or after supersession, including across API restarts. If no resume child exists, the wait holds to its original deadline. Supersession itself never matches an event.

The event and deadline compete for the same durable wait. Only one creates the continuation, including after an API restart. Tasks with an outputSchema must also supply schema-valid JSON in output; summary and deferral details are stored separately in the task log.

Schedule Properties

PropertyDescription
nameUnique name for the schedule
targetTypeagent-task (default), workflow, or script
taskTemplateTask description created each time. Required for agent-task schedules
workflowIdWorkflow to trigger when targetType: "workflow"
scriptNameGlobal catalog script name to run when targetType: "script"
scriptArgsJSON arguments passed to the script target
scheduleTyperecurring (default) or one_time
cronExpressionCron expression for recurring schedules (e.g., 0 9 * * *)
intervalMsInterval in milliseconds for recurring schedules
delayMsDelay in milliseconds for one-time schedules
runAtISO datetime for one-time schedules (e.g., 2026-03-15T09:00:00Z)
timezoneTimezone for cron schedules (default: UTC)
targetAgentIdAgent to assign tasks to (omit for task pool)
priorityTask priority 0-100 (default: 50)
tagsTags applied to created tasks
taskTypeType classification for created tasks
modelConcrete model override for created agent tasks
modelTierPortable model intent for created agent tasks: smol, regular, smart, or ultra
enabledWhether the schedule is active (default: true)

Automation setup checks

Bundled schedules can declare requiredParams and requires metadata. requiredParams names values that must be present in the schedule's params object. requires names integrations, such as Slack or GitHub, that must be configured before the automation can run.

The scheduler checks these requirements immediately before dispatch. An incomplete automation reports needs_setup with its missing parameters, missing integrations, and a dashboard fix URL; it does not create a task, start a workflow, or run a script. The schedules dashboard exposes the same status and lets operators supply the missing values, so the UI and dispatcher use one preflight result.

When Slack is available and SLACK_ALERTS_CHANNEL is configured, a newly recorded setup refusal sends an alert naming the automation, missing values, and dashboard fix URL. Repeated identical schedule refusals are suppressed within a UTC day; a changed failure can alert again. Workflow refusals alert at most once per workflow per UTC day. The blocked fire is skipped without being retried or queued; fixing setup allows later fires to proceed. Without Slack alerts, the refusal remains visible in the dashboard and logs.

Choosing targetType

Pick the schedule target that matches the work you actually want to fire:

  • Use agent-task when a reasoning agent needs to read the prompt, use tools, and make judgment calls before doing the work.
  • Use workflow when the schedule's only job is to start an existing workflow DAG. Pass workflowId and skip agent-task fields that only apply to delegated tasks.
  • Use script when the schedule should run a saved catalog script directly with scriptName and optional scriptArgs, without opening an interactive agent session.

This avoids a common anti-pattern: creating an agent-task schedule whose task body only says "trigger workflow X" or "run script Y". If the work is already captured as a workflow or script, schedule that target directly.

Managing Schedules

List Schedules

list-schedules()
list-schedules(enabled: true)
list-schedules(name: "daily")
list-schedules(scheduleType: "one_time")

By default, completed one-time schedules are hidden. Pass hideCompleted: false to include them.

Update a Schedule

update-schedule(name: "daily-standup", cronExpression: "0 10 * * *")
update-schedule(name: "daily-standup", enabled: false)
update-schedule(name: "health-check", targetType: "workflow", workflowId: "<workflow-uuid>")

Delete a Schedule

delete-schedule(name: "daily-standup")

Run Immediately

Trigger a scheduled task now without waiting for the next interval:

run-schedule-now(name: "daily-standup")

This creates a task immediately but does not affect the regular schedule timing.

Cron Expression Examples

ExpressionDescription
0 9 * * *Every day at 9:00 AM
0 9 * * 1-5Weekdays at 9:00 AM
*/30 * * * *Every 30 minutes
0 0 * * 0Every Sunday at midnight
0 9,17 * * *At 9 AM and 5 PM daily

How Scheduling Works

The MCP server runs a scheduler that polls for due schedules at a configurable interval (default: 10 seconds, set via SCHEDULER_INTERVAL_MS).

When a schedule fires, execution depends on targetType:

  • agent-task — creates a task from taskTemplate (the original behavior)
  • workflow — runs the referenced workflow directly and returns workflowRunIds
  • script — launches the named global script directly and returns scriptRunIds

For agent-task schedules:

  1. A new task is created with the schedule's taskTemplate
  2. The task is linked back to its schedule via scheduleId
  3. If targetAgentId is set, the task is assigned to that agent; otherwise it goes into the unassigned pool
  4. If model or modelTier is set, the task inherits that runtime selection
  5. The schedule's lastRunAt is updated
  6. One-time schedules are automatically disabled after execution

A defer-task wake-up schedule (deferred-*) is deleted 30 days after it fires, whether the deadline or a watched task woke it. The wake-up task keeps its scheduleId. A deferral schedule that never fired is kept.

Direct Workflow and Script Targets

Native targetType replaces the old "workflow trigger references a schedule" indirection for many cases:

{
  "name": "nightly-pipeline",
  "targetType": "workflow",
  "workflowId": "<workflow-uuid>"
}

Use targetType: "script" plus scriptName / scriptArgs when the scheduled work is a reusable script and does not need an interactive agent task. Each fire records a completed or failed run under Script Runs. To keep that table small, the run stores a pointer to the script version instead of a copy of the source.

Any registered agent can update or delete schedules.

On this page