Nodal-Agents
Guides

Automations

Schedule an agent to run a task on a recurring cron schedule, with optional notifications on the channel of your choice.

An automation is a named cron schedule that fires an agent on a recurring basis. The agent receives a fixed task prompt each time — useful for daily reports, monitoring jobs, regular data pulls, or anything you'd otherwise remember to trigger manually.

Prerequisites

  • At least one agent configured. See Create an agent.
  • If you want notifications: the agent must have at least one channel connected (Telegram, Discord, or Slack), and you must have messaged it there at least once (so the runner has your conversation id).

Create an automation

  1. Open the Run board in the sidebar rail. Its panel has two sections, Cron and Webhooks, each with a + on its title; either one, or the board's own cell, opens the Automations page.
  2. Click + New schedule.
  3. Fill in:
    • Agent — which agent runs this automation.
    • Name — a human label for the schedule (e.g. "Daily standup").
    • Cron expression — standard 5-field cron (minute hour day-of-month month day-of-week). The default is 0 9 * * * (every day at 09:00). A visual cron builder is provided.
    • Task instructions — the exact prompt the agent receives each time the schedule fires. Treat this like a detailed task description.
    • Notify me when it succeeds — when checked, the agent sends a short confirmation after each successful run. Requires the agent to have at least one connected channel.
    • Notify via — appears once Notify is checked, listing every channel this agent is actually connected to. Auto (the default) picks the agent's first active channel; choosing a specific one always sends there instead.
  4. Click Create schedule. The automation starts active immediately.

Common cron expressions

0 9 * * 1-5     Weekdays at 09:00
0 */6 * * *     Every 6 hours
30 8 * * 1      Every Monday at 08:30
0 0 1 * *       First of every month at midnight
*/15 * * * *    Every 15 minutes

Manage an automation

Each schedule row shows the next scheduled run, last run time, and last status (success / failed / no_action / budget_exhausted / notify_unreachable). Available actions:

  • Run now — fires the automation immediately, outside the schedule. Useful for testing.
  • Edit — change the name, agent, cron expression, task, or notification setting.
  • Duplicate — creates a paused copy of the schedule. Enable it when ready.
  • Pause / Enable — toggle the schedule on or off without deleting it.
  • Delete — removes the schedule. Past job runs are kept for audit.

Its own page

Clicking a schedule opens /automations/<id> — one route that serves a schedule and a webhook alike, because both are "an automation" to whoever is looking at one:

  • a header saying which kind it is,
  • a settings card of five rows,
  • its last ten runs, with what they cost over the last thirty days,
  • and what the routine has remembered.

That last block is worth knowing about. A routine keeps state it owns, read and written without a model. Before 0.8.9 a schedule stored "what I last announced" as a memory and searched it back in plain language; a memory that got cleaned up made one routine announce a release twice on a public Discord.

Opening a run from that list gives you the run page. /scheduled now redirects here; /scheduled/<id> still opens the run it always did.

How the runner fires schedules

The runner's cron ticker evaluates due schedules every minute. For each due schedule it:

  1. Atomically claims the row (concurrent ticks cannot double-fire).
  2. Inserts a job with channel = 'cron' and advances next_run using the cron expression.
  3. Executes the job inline.
  4. Updates last_status with the outcome.

A bad cron expression causes the schedule to be marked failed and its next_run is pushed one year out — edit and save to fix it.

Cron fires in your workspace timezone

Cron expressions are evaluated in the workspace timezone, not UTC. Set it in Settings (the timezone is captured from your browser at onboarding and editable there — it also accepts any IANA name like Europe/Paris). So 0 9 * * * means 09:00 in that zone. If automations fire at an unexpected hour, check the workspace timezone first.

Watchers

A schedule is not just for daily reports. Set the cron expression to a short interval (e.g. */5 * * * *) and the task instructions to "check X, and only act if it changed" and the schedule becomes a watcher: a recurring poll that inspects some external state on your behalf instead of running on a fixed daily cadence.

Two guards keep a watcher from running away:

  • Daily budget. Every schedule has a Daily budget ($) field, 5.00 by default. Each fire's cost rolls up against this ceiling for the schedule's own local day (in its cron timezone). Once the day's spend reaches the ceiling, further fires are skipped and lastStatus shows budget_exhausted. You get one notification per exhaustion (not one per skipped tick), and the ceiling lifts automatically at the next local day. Raise or lower it in Edit.
  • No overlap. If the previous run of a schedule is still pending, processing, awaiting_approval, or awaiting_delegation when the next tick comes due, that tick is skipped rather than starting a second, parallel run of the same watcher. The schedule stays due and fires on the first tick after the in-flight run finishes.

A frequent watcher (say, every minute) can still burn its whole daily budget quickly if each check is expensive. Set the budget with that in mind, and prefer a coarser interval when a tighter one is not needed.

Notifications and channel choice

Notification delivery is per-agent: the agent sends through its own channel bindings. A schedule with Notify me enabled but assigned to an agent with no connected channel shows a warning in the form. The notification is sent only on a successful (completed) run, not on failure or when the agent takes no action.

Notify via links the channel to where the confirmation goes: picking a channel resolves your conversation with the agent on THAT channel specifically, instead of whichever connected channel happens to win by default priority (Telegram, then Discord, then Slack). If you pick a channel you've never messaged the agent on yet, the schedule still fires — the run itself is not blocked — but the confirmation has nowhere to go. lastStatus then reads notify_unreachable instead of success, so the miss is visible instead of silent. Message the agent once on that channel and the next fire delivers normally.

WhatsApp is not offered in Notify via yet — the runner has no way to hand a mid-run confirmation to a WhatsApp-bound agent today.

Notes

  • Automations run up to 5 concurrently per tick. If more than 5 are due simultaneously, the remaining ones fire on the next tick.
  • A running automation counts against the same job limits as manual chat jobs.
  • Pausing a schedule does not affect any job already in flight.

On this page