Time-Based Actions

Productivity

Unified routing guide for reminders, schedules, notifications, and tasks. Prevents common misrouting.

Install
assistant skills install time-based-actions

compatibility:Designed for Vellum personal assistants

Quick-reference decision guide for choosing the right tool when users ask about time-triggered actions, recurring automation, notifications, or task tracking.

Decision Tree

  1. Does the request have a specific future time AND should fire only once?

    • YES -> reminder_create
    • Examples: "remind me at 3pm", "remind me in 5 minutes", "alert me tomorrow at 9am"
  2. Does the request have a recurring pattern?

    • YES -> schedule_create with mode: "notify" (for recurring reminders/alerts) or mode: "execute" (if the assistant should act autonomously each recurrence)
    • Default to mode: "notify" for recurring reminder-style requests. Use mode: "execute" only when each recurrence should trigger the assistant to perform a task (e.g. "every morning, check my email and summarize it").
    • Examples: "every day at 9am", "weekly on Mondays", "every 2 hours"
  3. Does the request need an alert RIGHT NOW (no delay)?

    • YES -> assistant notifications send via bash
    • Examples: "send me a notification", "alert me now", "ping me"
  4. Is the request about tracking work with no time trigger?

    • YES -> task_list_add
    • Examples: "add to my tasks", "remind me to do X" (no time), "put this on my list"

Critical Warning: assistant notifications send is IMMEDIATE-ONLY

assistant notifications send fires instantly when called. It has NO delay, scheduling, or future-time capability. NEVER use it for:

  • "Remind me in 5 minutes" -> use reminder_create
  • "Alert me at 3pm" -> use reminder_create
  • "Notify me tomorrow" -> use reminder_create

If you use assistant notifications send for any of these, the notification fires immediately and the user misses their intended reminder.

Critical Warning: task_list_add has NO time trigger

task_list_add creates a work queue item. It does NOT fire at a specific time. NEVER use it as a workaround for delayed notifications. If the user wants a timed alert, use reminder_create.

Time Grounding Source

Use the current_time: field from the injected <turn_context> block as the authoritative clock source. The format is:

current_time: 2026-04-02 (Wednesday) 14:30:00 -05:00 (America/Chicago)

It contains the date, weekday name, local time (HH:MM:SS), UTC offset, and IANA timezone name in parentheses.

Timezone confidence check: The timezone shown may be the assistant host's timezone rather than the user's actual timezone (this happens when the user hasn't configured Settings → Appearance → User timezone). If you have no prior confirmation of the user's timezone (from conversation history or memory) and the request is locale-specific (e.g. "at 3pm", "tomorrow morning", "tonight"), confirm the timezone once before scheduling. If the user confirms, suggest saving it in Settings → Appearance → User timezone so future requests resolve correctly without re-asking.

Relative Time Parsing

When the user says "in X minutes/hours", compute the ISO 8601 timestamp yourself:

  • Take the time and offset from the current_time: field (e.g. 23:26:00 -05:00)
  • Add the requested offset
  • Format as ISO 8601 with timezone: 2025-03-15T09:05:00-05:00
  • Pass to reminder_create as fire_at

Anchored & Ambiguous Relative Time

Phrases like "at the 45 minute mark", "at the top of the hour", "on the half-hour", "at noon", "20 minutes in", or "when I hit an hour" are clock-position or anchored relative time expressions. Do NOT treat them as offsets from now.

Resolution rules (in priority order):

  1. Conversation-anchored expressions - if the user mentioned a start time earlier in conversation ("I got here at 9", "meeting started at 2:10"), interpret offset-style phrases ("the 45 minute mark", "20 minutes in", "when I hit an hour") as start_time + offset. This takes precedence because the conversational anchor overrides any wall-clock interpretation.

  2. Clock-position expressions - when no start time is in context, map directly to a wall-clock time:

    • "top of the hour" / "on the hour" → next :00 (e.g. 10:00 AM)
    • "the X minute mark" / "at :XX" → current hour's :XX; if already past, advance one hour
    • "the half-hour mark" / "half past" → nearest upcoming :30
    • "noon" / "midnight" → 12:00 PM or 12:00 AM today; if past, tomorrow
    • "quarter past" / "quarter to" → :15 or :45 of current or next hour
  3. Ask only if truly ambiguous - if neither rule 1 nor rule 2 resolves, ask: "Do you mean [clock time] or [X minutes from now]?" Never silently default to "from now."

Examples:

  • "meeting started at 2:10, remind me at the 45 minute mark" → 2:55 PM (start + 45 min)
  • "20 minutes in, I started at 2pm" → 2:20 PM (start + 20 min)
  • "at the 45 min mark" (no start time, now: 9:39) → 9:45 AM (wall-clock)
  • "at the 45 min mark" (no start time, now: 9:50) → 10:45 AM (wall-clock, next hour)
  • "top of the hour" (now: 9:39) → 10:00 AM
  • "at noon" → 12:00 PM today
  • "at the hour mark" with no start time → ask for clarification

"Remind me to X" Disambiguation

The word "remind" is ambiguous. Route based on whether a time is specified:

User saysTime present?Tool
"Remind me to buy milk"Notask_list_add
"Remind me to buy milk at 5pm"Yesreminder_create
"Remind me in 10 minutes to check the oven"Yes (relative)reminder_create
"Remind me every morning to take vitamins"Yes (recurring)schedule_create

Reminder Modes

reminder_create supports two modes:

  • notify (default) - shows a notification to the user when the reminder fires
  • execute - sends the reminder message to a background assistant conversation for autonomous handling

Use notify for simple alerts. Use execute when the reminder should trigger the assistant to do something (e.g., "in 30 minutes, check if the build passed").

Reminder Routing

reminder_create supports a routing_intent parameter that controls how the reminder is delivered at trigger time:

  • single_channel - deliver to one best channel
  • multi_channel - deliver to a subset of channels
  • all_channels (default) - deliver to every available channel

You can also pass routing_hints (a JSON object) to influence routing decisions (e.g. preferred channels, exclusions).

Routing Defaults

Use the following heuristics to pick routing_intent:

  • Default to all_channels for most reminders. Users setting reminders usually want to be notified wherever they are, and redundant notifications are less harmful than missed ones.

  • Use single_channel only when the user explicitly specifies a single channel (e.g. "remind me on Telegram") or the reminder is low-stakes and noise reduction matters.

  • Determine the originating channel for routing hints using this priority:

    1. source_channel from <turn_context> — use directly if present. This is the authoritative channel name.
    2. interface fallback — if source_channel is absent (common for guardian/direct users), map the interface value to a channel name:
      interface valueChannel name
      macos, iosvellum
      telegramtelegram
      slackslack
      cli(omit — no routable channel)
    3. If neither field is present or the interface is cli, omit preferred_channels.

    When a channel is determined, include it as a routing hint:

    routing_hints: { preferred_channels: ["<resolved channel>"] }
    routing_intent: "all_channels"
    
  • Never use single_channel as a passive default. If you haven't thought about which channel to use, use all_channels.

Examples

Scenariorouting_intentrouting_hints
source_channel: telegram in turn_contextall_channels{ preferred_channels: ["telegram"] }
No source_channel, interface: macosall_channels{ preferred_channels: ["vellum"] }
No source_channel, interface: iosall_channels{ preferred_channels: ["vellum"] }
User says "remind me on Telegram"single_channel{ preferred_channels: ["telegram"] }
No source_channel, interface: cliall_channels{}
No channel info availableall_channels{}

Tool Summary

ToolTimingRecurrencePurpose
reminder_createFuture time (one-shot)NoTimed notification or timed autonomous action
schedule_createRecurring patternYes (cron/RRULE)Recurring automated jobs
assistant notifications sendImmediate onlyNoAlert the user right now
task_list_addNo time triggerNoTrack work in the task queue
CreatorVellum
LicenseMIT
Updated1 month ago
SecurityVerified
View on GitHub

The Personal AI you were promised

GET STARTED