| Type | Runs when |
|---|---|
schedule | A cron expression matches. |
heartbeat | An interval passes, optionally within a daily window. |
event | An event with a matching source is emitted. |
watch | A plugin watcher writes a line of output. |
folder | Files change in a folder. |
manual | The owner or an employee runs it. |
call | A phone line rings. Only in phone call trees. |
schedule
{ "type": "schedule", "cron": "0 8 * * 1-5", "schedule": "Weekdays at 8:00" } cron is a five-field cron expression: minute, hour, day of month, month, day of week. schedule is an optional description for people. Schedules run in the bot's local time
zone. Nebo checks schedules every five seconds. A fire missed while the bot was off is caught up once
if it is less than an hour late. A fire is skipped while the previous run is still going.
heartbeat
{ "type": "heartbeat", "interval": "30m", "window": "08:00-18:00" } interval is a span such as 30m, 1h or 2h30m. window, HH:MM-HH:MM, keeps fires inside working hours. The next fire is the
last fire plus the interval, moved into the window; the first is one interval after the workflow
loads. Timers survive restarts. A fire is skipped while the previous run is still going, and an
invalid interval never fires.
event
{ "type": "event", "sources": ["support-coordinator.summary.ready", "assignment.*"] } sources lists event names to match exactly, or with a trailing .* wildcard.
An empty list is an error that rejects the whole agent.json. The run receives _event_source, _event_payload and _event_origin. See Events for how names are formed.
watch
{ "type": "watch", "plugin": "mail", "event": "email.new" } A watch keeps a plugin process running and starts a run for each line it writes. Each line arrives
as _watch_payload. Identical lines within ten minutes are dropped.
| Field | Default | Meaning |
|---|---|---|
plugin | required | A capability, such as mail, or a plugin slug. Name a capability whenever one fits. |
event | none | An event from the plugin’s events list. Nebo uses that event’s command and also emits each line as <plugin>.<event>. |
command | none | Arguments that start the watcher. Used when set; otherwise taken from event. |
restart_delay_secs | 5 | Wait before restarting a watcher that exits. |
A capability resolves to the installed plugin that provides it, preferring one this employee has an account on. With no such plugin, the workflow is marked degraded and the owner is told what to connect. A watcher that keeps crashing restarts with a delay that doubles up to 300 seconds and resets after 30 seconds of uptime.
{ "type": "watch", "plugin": "notes-sync", "command": "watch --notebook {{notebook}} --format ndjson" } {{key}} in command is filled from the owner's answers to the
employee's inputs. If a placeholder has no answer, the watch does not start.
folder
{ "type": "folder", "path": "{{inbox_folder}}", "extensions": ["pdf"], "recursive": false } | Field | Default | Meaning |
|---|---|---|
path | required | Absolute folder path. {{key}} is filled from inputs. |
extensions | all files | File extensions to match, without the dot. |
recursive | true | Include subfolders. |
debounce_secs | 2 | Changes within this window become one run. |
The run receives the changed paths in _watch_payload.files.
manual
{ "type": "manual" } A manual workflow runs only when the owner runs it or an employee calls run_workflow.
Every workflow, whatever its trigger, can also be run this way.
call
{"type": "call", "line": "..."} is valid only in a workflow of "type": "call_tree", which configures how an employee answers a phone line. An empty line applies to every line the employee answers that has no more specific tree. A call
tree must have exactly one greeting and at least one named intent.
Webhooks
The owner can also create a webhook for an employee. A webhook tied to a workflow runs that workflow; one without a workflow delivers its payload to the employee's chat.