Task scheduling — the guide
The task-scheduling card in your instructions carries the rules (when a
task is right, scope, notification mode, timing, timezone). This guide is
the reference behind them.
Task completion notifications (notification_mode)
Every task requires a notification_mode — pick one when calling
create_scheduled_task or create_one_time_task. The system enforces this:
there is no default. The chosen mode controls both the system's behaviour AND
the task agent's behaviour, so they can never disagree.
| Mode |
What the user gets on success |
What the user gets on failure |
When to pick |
auto |
Generic "Task Complete: <name>" (severity from notify_severity) |
"Task Failed: <name>" (warning) |
Status tasks where the user only cares that it finished — deploys, "wake me when X is done", sync confirmations. |
manual |
A custom notification fired by the task agent itself, with actual results |
"Task Failed: <name>" (system safety net — crashed agents can't notify themselves) |
Notification content matters — daily PR review (with findings), draft Reddit comments (with the drafts), email triage (with summary). Most user-facing tasks fall here. |
none |
Nothing |
Nothing (user explicitly opted out) |
High-frequency ops tasks where notifications would be spam — cache refresh, log rotation, vector store rebuild. User checks the task runs page for status. |
You do not need to write notification instructions in the task prompt. The
system auto-injects the right behaviour for the chosen mode into the task
agent's system prompt:
- Don't write: "When done, send a notification to the user with create_notification." —
manual mode injects this for you.
- Don't write: "A notification will be sent automatically — do not notify yourself." —
auto mode injects this for you.
- Just pick
notification_mode and write the task prompt about what the agent should DO.
notify_severity controls the generic notification's severity in auto
mode (info / success / warning) and is ignored in manual and none.
Scheduled self-continuations (schedule_continuation)
schedule_continuation wakes THIS session at a future time: the prompt you
give it is delivered into this very conversation as a new turn, with full
context (the session resumes automatically if it went idle). It works from
any session — chats and task runs alike.
- Watchdog wake: after delegating lanes,
schedule_continuation(prompt="Check on the delegated lanes — peek any that have not reported back.", in_seconds=3600). Cancel-on-arrival: if the thing you were watching for already happened (the callbacks arrived), delete_task the pending wake — don't let a stale watchdog fire.
- Deferred round:
schedule_continuation(prompt="Start phase 2 now if phase 1 finished.", at="2026-07-08T15:00:00").
Guardrails (enforced):
- Recurring continuations are always bounded —
max_runs (default 5) or until. A chat must never wake itself forever. For indefinite monitoring, create a recurring task instead (create_scheduled_task) — each run gets a fresh context instead of accreting into this chat.
- Wakes coalesce: a new wake is skipped while a previous one is still unprocessed in this chat.
- Continuations auto-cancel when this chat is deleted, appear in
list_tasks, and are cancelled with delete_task.
Cron schedules
create_scheduled_task accepts standard 5-field POSIX cron — minute hour day month weekday. Sub-daily intervals are fully supported:
*/10 * * * * — every 10 minutes
0 */3 * * * — every 3 hours (top of the hour)
*/15 9-17 * * 1-5 — every 15 minutes, 9am-5pm, weekdays
0 9 * * 1-5 — weekdays at 9am
0 0 * * 0 — every Sunday at midnight
Pick the coarsest interval that meets the user's intent — don't schedule
* * * * * (every minute) unless they explicitly need that. For cadences
that don't divide 24 evenly (every 17 hours, every 5h30m, every 3 days), use
interval_seconds instead of cron.
Managing existing tasks
list_tasks — shows all tasks for this agent with their current status (active or paused), schedule, next run time, and ID. Always call this first to find the task ID before pausing/resuming/deleting.
- Cross-agent reads:
list_tasks, get_task_history, and get_task_result take an optional agent argument — another agent's slug, or "all" for every agent your user can access. You see exactly what your user would see on that agent's pages (their role travels with you); sessions without a user see only this agent plus its wired delegation targets (their agent-scope tasks and runs — the scheduled-briefing pattern: read what your delegation targets did, then summarize). Reading is where it ends: to CHANGE another agent's schedule, ask that agent via delegation — mutations never cross agents.
pause_task(task_id) — stops a task from firing on its schedule without deleting it. The task can be resumed later. Use when the user says "pause", "stop for now", "disable temporarily".
resume_task(task_id) — re-enables a paused task. For one-time tasks whose run_at has already passed, resume keeps the row active but does NOT auto-fire — the user can run it manually from the dashboard if they want.
edit_task(task_id, ...) — change the schedule, run time, name, prompt, timeout, notification settings, or the model / execution layer of an existing task without deleting and recreating it. Pass only the fields you want to change. schedule and run_at are mutually exclusive — setting one switches the task between recurring and one-time mode and clears the other. Use this whenever the user says "change the time of X", "update the X reminder to Y", "make this run every 3 hours instead", "edit the prompt of X". Always prefer this over delete+recreate — it preserves the task ID, history references, and any in-flight context.
delete_task(task_id) — permanently removes a task (or a pending continuation). Use when the user says "delete", "remove", "cancel for good". Static tasks (defined in tasks.json) cannot be deleted via this tool.
run_task(task_id) — fires an existing task immediately, regardless of schedule. Use for "run X now" or to manually fire a paused/expired task.
One-time tasks auto-clean up after they fire successfully — the row is
removed and won't appear in list_tasks. Recurring tasks persist and keep
firing until paused or deleted.
Choosing a model for a task
Every task runs on your agent's default model and execution layer unless
it says otherwise. That default is the right answer almost always — leave
model and layer out.
The exception is a task whose cost profile genuinely differs from your
everyday work: a heavy daily briefing that has to reason over a lot of
material, or conversely a trivial hourly sync that would be wasteful on a big
model. create_scheduled_task, create_one_time_task, and edit_task all
take an optional model (and layer) that pins that one task's runs,
leaving the agent's default untouched for everything else. It is a real cost
lever: a cheap default with one task pinned up, or an expensive default with
the noisy tasks pinned down.
- Ask the user before pinning a model, unless they already asked for it. Which model a schedule burns is their spend, not your call. "Should I run that daily report on and keep everything else on the default?" is the shape of the question.
- Valid values come from your own
layers: line — it lists your enabled execution layers and the model ids on each, with your current default marked [default]. Look for it under Scheduled-task Execution in your prompt; if you also have the delegation tools it lives on your own row in Available Agents instead, and the Scheduled-task Execution block points you there. A model that isn't on that line is rejected with a 400; do not guess ids.
- Retuning is cheap.
edit_task(task_id, model="...") re-pins a live schedule from its next run on, with no change to when it fires. edit_task(task_id, model="") clears the pin and returns the task to your default.
- Read it back, never assume.
list_tasks shows every task's effective model and layer — runs on: <model> [pinned] for a task-level pin, runs on: <model> [agent default] when it follows the agent's current setting. When asked "what model does this task run on?", answer from list_tasks, not from memory or the default. The dashboard's Scheduled Tasks tab shows the same.
Trigger-only tasks (task_type='trigger')
A task can also be paired with a webhook trigger instead of a schedule.
Use create_one_time_task(name=..., prompt=..., task_type='trigger') — the
task is stored without run_at or delay_seconds, and only runs when an
external system calls the trigger's webhook URL. This pattern is for personal
automations and business event handlers:
- "Run my code-review task whenever GitHub fires the PR-opened webhook"
- "Run the deploy-checker agent task whenever the CI webhook fires"
The task prompt can use {{placeholder}} tokens that get substituted from
the webhook body at fire time. Wire it up afterwards with
create_trigger(task_id=...) from the triggers-mcp. Cross-scope linkage
is enforced — a user-scoped trigger can only run a user-scoped task;
agent-scoped triggers only agent-scoped tasks.
Timezone semantics
The [Current time: ...] line at the start of each user message shows the
user's local timezone with the IANA name and explicit UTC offset (e.g.
Europe/Athens (UTC+03:00), America/New_York (UTC-04:00)). The time is
rendered in 24-hour form first, then in parentheses again as 12-hour with
AM/PM (e.g. 04:02 (4:02 AM), 17:00 (5:00 PM)) — always trust the AM/PM
gloss; never guess the half-of-day from the 24-hour number alone. This is
detected from the user's browser, so it follows them when they travel.
When you compute future times for run_at (or schedule_continuation's at):
- Prefer naive ISO (no offset, e.g.
'2026-04-29T10:00:00'). The proxy interprets it in the user's local timezone — same one you see in [Current time: ...]. This matches how users speak ("remind me at 10am") and travels with them.
- Don't append
Z or +00:00 unless you genuinely mean UTC. UTC-tagged times are stored at the literal absolute moment, which is rarely what the user meant when they said a wall-clock time.
- Recurring
schedule (cron) is also evaluated in the user's local timezone, snapshotted on the row at creation. To change the timezone of a recurring task (e.g. user moved permanently), use edit_task(task_id, ...) — the proxy resnapshots when you pass a new schedule.
1---2name: task-scheduling-guide3description: Parameter shapes and worked detail for the schedules-mcp tools — notification modes, cron and interval schedules, self-continuations, editing and reading back tasks, model pinning, trigger-only tasks, timezone rules. Load before creating or editing a scheduled task.4---56# Task scheduling — the guide78The `task-scheduling` card in your instructions carries the rules (when a9task is right, scope, notification mode, timing, timezone). This guide is10the reference behind them.1112## Task completion notifications (`notification_mode`)1314Every task requires a `notification_mode` — pick one when calling15`create_scheduled_task` or `create_one_time_task`. The system enforces this:16there is no default. The chosen mode controls both the system's behaviour AND17the task agent's behaviour, so they can never disagree.1819| Mode | What the user gets on success | What the user gets on failure | When to pick |20|---|---|---|---|21| `auto` | Generic `"Task Complete: <name>"` (severity from `notify_severity`) | `"Task Failed: <name>"` (warning) | Status tasks where the user only cares that it finished — deploys, "wake me when X is done", sync confirmations. |22| `manual` | A custom notification fired by the task agent itself, with actual results | `"Task Failed: <name>"` (system safety net — crashed agents can't notify themselves) | Notification content matters — daily PR review (with findings), draft Reddit comments (with the drafts), email triage (with summary). Most user-facing tasks fall here. |23| `none` | Nothing | Nothing (user explicitly opted out) | High-frequency ops tasks where notifications would be spam — cache refresh, log rotation, vector store rebuild. User checks the task runs page for status. |2425You do not need to write notification instructions in the task prompt. The26system auto-injects the right behaviour for the chosen mode into the task27agent's system prompt:2829- Don't write: *"When done, send a notification to the user with create_notification."* — `manual` mode injects this for you.30- Don't write: *"A notification will be sent automatically — do not notify yourself."* — `auto` mode injects this for you.31- Just pick `notification_mode` and write the task prompt about what the agent should DO.3233`notify_severity` controls the generic notification's severity in `auto`34mode (`info` / `success` / `warning`) and is ignored in `manual` and `none`.3536## Scheduled self-continuations (`schedule_continuation`)3738`schedule_continuation` wakes THIS session at a future time: the prompt you39give it is delivered into this very conversation as a new turn, with full40context (the session resumes automatically if it went idle). It works from41any session — chats and task runs alike.4243- **Watchdog wake**: after delegating lanes, `schedule_continuation(prompt="Check on the delegated lanes — peek any that have not reported back.", in_seconds=3600)`. Cancel-on-arrival: if the thing you were watching for already happened (the callbacks arrived), `delete_task` the pending wake — don't let a stale watchdog fire.44- **Deferred round**: `schedule_continuation(prompt="Start phase 2 now if phase 1 finished.", at="2026-07-08T15:00:00")`.4546Guardrails (enforced):4748- Recurring continuations are always bounded — `max_runs` (default 5) or `until`. A chat must never wake itself forever. For indefinite monitoring, create a recurring **task** instead (`create_scheduled_task`) — each run gets a fresh context instead of accreting into this chat.49- Wakes **coalesce**: a new wake is skipped while a previous one is still unprocessed in this chat.50- Continuations auto-cancel when this chat is deleted, appear in `list_tasks`, and are cancelled with `delete_task`.5152## Cron schedules5354`create_scheduled_task` accepts standard 5-field POSIX cron — `minute hour day month weekday`. Sub-daily intervals are fully supported:5556- `*/10 * * * *` — every 10 minutes57- `0 */3 * * *` — every 3 hours (top of the hour)58- `*/15 9-17 * * 1-5` — every 15 minutes, 9am-5pm, weekdays59- `0 9 * * 1-5` — weekdays at 9am60- `0 0 * * 0` — every Sunday at midnight6162Pick the coarsest interval that meets the user's intent — don't schedule63`* * * * *` (every minute) unless they explicitly need that. For cadences64that don't divide 24 evenly (every 17 hours, every 5h30m, every 3 days), use65`interval_seconds` instead of cron.6667## Managing existing tasks6869- **`list_tasks`** — shows all tasks for this agent with their current status (`active` or `paused`), schedule, next run time, and ID. Always call this first to find the task ID before pausing/resuming/deleting.70- **Cross-agent reads**: `list_tasks`, `get_task_history`, and `get_task_result` take an optional `agent` argument — another agent's slug, or `"all"` for every agent your user can access. You see exactly what your user would see on that agent's pages (their role travels with you); sessions without a user see only this agent plus its wired delegation targets (their agent-scope tasks and runs — the scheduled-briefing pattern: read what your delegation targets did, then summarize). Reading is where it ends: to CHANGE another agent's schedule, ask that agent via delegation — mutations never cross agents.71- **`pause_task(task_id)`** — stops a task from firing on its schedule without deleting it. The task can be resumed later. Use when the user says "pause", "stop for now", "disable temporarily".72- **`resume_task(task_id)`** — re-enables a paused task. For one-time tasks whose `run_at` has already passed, resume keeps the row active but does NOT auto-fire — the user can run it manually from the dashboard if they want.73- **`edit_task(task_id, ...)`** — change the schedule, run time, name, prompt, timeout, notification settings, or the model / execution layer of an existing task **without deleting and recreating it**. Pass only the fields you want to change. `schedule` and `run_at` are mutually exclusive — setting one switches the task between recurring and one-time mode and clears the other. Use this whenever the user says "change the time of X", "update the X reminder to Y", "make this run every 3 hours instead", "edit the prompt of X". Always prefer this over delete+recreate — it preserves the task ID, history references, and any in-flight context.74- **`delete_task(task_id)`** — permanently removes a task (or a pending continuation). Use when the user says "delete", "remove", "cancel for good". Static tasks (defined in `tasks.json`) cannot be deleted via this tool.75- **`run_task(task_id)`** — fires an existing task immediately, regardless of schedule. Use for "run X now" or to manually fire a paused/expired task.7677One-time tasks auto-clean up after they fire successfully — the row is78removed and won't appear in `list_tasks`. Recurring tasks persist and keep79firing until paused or deleted.8081## Choosing a model for a task8283Every task runs on **your agent's default model and execution layer** unless84it says otherwise. That default is the right answer almost always — leave85`model` and `layer` out.8687The exception is a task whose cost profile genuinely differs from your88everyday work: a heavy daily briefing that has to reason over a lot of89material, or conversely a trivial hourly sync that would be wasteful on a big90model. `create_scheduled_task`, `create_one_time_task`, and `edit_task` all91take an optional `model` (and `layer`) that pins **that one task's runs**,92leaving the agent's default untouched for everything else. It is a real cost93lever: a cheap default with one task pinned up, or an expensive default with94the noisy tasks pinned down.9596- **Ask the user before pinning a model, unless they already asked for it.** Which model a schedule burns is their spend, not your call. "Should I run that daily report on <stronger model> and keep everything else on the default?" is the shape of the question.97- **Valid values come from your own `layers:` line** — it lists your enabled execution layers and the model ids on each, with your current default marked `[default]`. Look for it under **Scheduled-task Execution** in your prompt; if you also have the delegation tools it lives on your own row in **Available Agents** instead, and the Scheduled-task Execution block points you there. A model that isn't on that line is rejected with a 400; do not guess ids.98- **Retuning is cheap.** `edit_task(task_id, model="...")` re-pins a live schedule from its next run on, with no change to when it fires. `edit_task(task_id, model="")` clears the pin and returns the task to your default.99- **Read it back, never assume.** `list_tasks` shows every task's effective model and layer — `runs on: <model> [pinned]` for a task-level pin, `runs on: <model> [agent default]` when it follows the agent's current setting. When asked "what model does this task run on?", answer from `list_tasks`, not from memory or the default. The dashboard's Scheduled Tasks tab shows the same.100101## Trigger-only tasks (`task_type='trigger'`)102103A task can also be paired with a **webhook trigger** instead of a schedule.104Use `create_one_time_task(name=..., prompt=..., task_type='trigger')` — the105task is stored without `run_at` or `delay_seconds`, and only runs when an106external system calls the trigger's webhook URL. This pattern is for personal107automations and business event handlers:108109- "Run my code-review task whenever GitHub fires the PR-opened webhook"110- "Run the deploy-checker agent task whenever the CI webhook fires"111112The task prompt can use `{{placeholder}}` tokens that get substituted from113the webhook body at fire time. Wire it up afterwards with114`create_trigger(task_id=...)` from the **triggers-mcp**. Cross-scope linkage115is enforced — a user-scoped trigger can only run a user-scoped task;116agent-scoped triggers only agent-scoped tasks.117118## Timezone semantics119120The `[Current time: ...]` line at the start of each user message shows the121user's **local** timezone with the IANA name and explicit UTC offset (e.g.122`Europe/Athens (UTC+03:00)`, `America/New_York (UTC-04:00)`). The time is123rendered in 24-hour form first, then in parentheses again as 12-hour with124AM/PM (e.g. `04:02 (4:02 AM)`, `17:00 (5:00 PM)`) — always trust the AM/PM125gloss; never guess the half-of-day from the 24-hour number alone. This is126detected from the user's browser, so it follows them when they travel.127128When you compute future times for `run_at` (or `schedule_continuation`'s `at`):129130- **Prefer naive ISO** (no offset, e.g. `'2026-04-29T10:00:00'`). The proxy interprets it in the user's local timezone — same one you see in `[Current time: ...]`. This matches how users speak ("remind me at 10am") and travels with them.131- **Don't append `Z` or `+00:00`** unless you genuinely mean UTC. UTC-tagged times are stored at the literal absolute moment, which is rarely what the user meant when they said a wall-clock time.132- **Recurring `schedule` (cron)** is also evaluated in the user's local timezone, snapshotted on the row at creation. To change the timezone of a recurring task (e.g. user moved permanently), use `edit_task(task_id, ...)` — the proxy resnapshots when you pass a new schedule.