Skip to content

Hooks & Automation

Hooks are the unified automation system. They react to events (messages, agent completions, webhooks) or run on cron schedules. A “scheduled task” is simply a hook with a schedule trigger.

A hook has three parts:

  1. Trigger — what event fires the hook
  2. Conditions (optional) — filter rules that must match
  3. Action — what to do when triggered
TriggerFires WhenConfig Fields
message_receivedNew message on any channelchannelTypes[], messagePatterns[] (regex)
agent_startedAgent begins worksessionFilter.topics[], sessionFilter.userIds[]
agent_completedAgent finishes successfullySame as above
agent_failedAgent errors outSame as above
tool_executedA tool runstoolIds[], toolNames[]
permission_requestedTool needs user approval
scheduleCron timer or specific datetimecronExpression, timezone, scheduledAt
webhookInbound HTTP POST to /api/hooks/incoming/:hookIdwebhookSecret, messageTemplate
ActionWhat It DoesConfig Fields
notifySend message to channelsnotifyOwner, notifyChannels[], notifyMessage, channelType, channelId
spawn_agentStart an AI agentagentPrompt, agentTopic, agentModel, orchestrated, notifyOwner
webhookSend outgoing HTTP requestwebhookUrl, webhookMethod, webhookHeaders, webhookBody
n8n_workflowTrigger N8N workflowworkflowId, workflowData
execute_toolRun a registered tooltoolId, toolAction, toolParams

When notifyOwner: true is set on a spawn_agent action, the agent’s output is automatically sent to all the user’s verified channels (Telegram, Slack, etc.) when the agent completes. No need for the agent to handle messaging itself.

notifyChannels uses the format type:channelId:

telegram:123456789 # Telegram chat ID
slack:C0123ABCDEF # Slack channel ID
webchat:session-uuid # WebChat session ID
teams:channel-id # Microsoft Teams channel

Use {{path.to.value}} in notifyMessage, agentPrompt, and webhookBody:

VariableAvailable In
message.contentmessage_received
agent.id, agent.topic, agent.statusagent_* triggers
tool.name, tool.toolIdtool_executed
webhook.path, webhook.body.*webhook
schedule.cronExpressionschedule

Optional array of rules that ALL must match:

{
"conditions": [
{ "field": "message.content", "operator": "contains", "value": "deploy" },
{ "field": "message.channelType", "operator": "equals", "value": "telegram" }
]
}

Operators: equals, contains, matches (regex), gt, lt, in.

FieldPurpose
isEnabledToggle hook on/off
priorityHigher priority hooks run first (default: 0)
maxExecutionsStop after N runs (null = unlimited)
cooldownMsMinimum ms between executions

Set trigger: "schedule" with a cron expression:

* * * * *
│ │ │ │ └── Day of week
│ │ │ └──── Month
│ │ └────── Day of month
│ └──────── Hour
└────────── Minute

Common patterns: */5 * * * * (every 5 min), 0 9 * * * (daily 9 AM), 0 9 * * 1-5 (weekdays 9 AM).

Set triggerConfig.scheduledAt to an ISO 8601 datetime for a one-time task:

{
"trigger": "schedule",
"triggerConfig": { "scheduledAt": "2026-04-15T14:30:00Z" }
}

The task auto-disables after execution (isEnabled set to false, nextRunAt cleared).

The Hooks & Tasks UI includes a Calendar tab showing a weekly grid of all scheduled tasks — recurring cron tasks on their next run day, datetime tasks on their exact day. Navigate weeks and see server timezone for reference.

GitHub push handler via inbound webhook:

{
"name": "GitHub Push Handler",
"trigger": "webhook",
"triggerConfig": {
"webhookSecret": "my-secret-123",
"messageTemplate": "New push to {{body.repository.name}} by {{body.pusher.name}}: {{body.head_commit.message}}"
},
"action": "notify",
"actionConfig": {
"channelType": "telegram",
"channelId": "123456789"
}
}

Scheduled daily email check:

{
"name": "Morning email check",
"trigger": "schedule",
"triggerConfig": { "cronExpression": "0 9 * * *", "timezone": "Europe/Berlin" },
"action": "spawn_agent",
"actionConfig": {
"agentPrompt": "Check Gmail for unread emails and summarize.",
"orchestrated": true
}
}

Notify on agent failure:

{
"name": "Error alert",
"trigger": "agent_failed",
"triggerConfig": {},
"action": "notify",
"actionConfig": {
"notifyOwner": true,
"notifyMessage": "Agent failed on topic '{{agent.topic}}'"
}
}

External services can trigger hooks by POSTing to /api/hooks/incoming/:hookId. This enables GitHub, Stripe, smart home sensors, n8n, and any HTTP-capable service to drive agent actions.

Setup:

  1. Create a hook with trigger: "webhook" via the API or UI
  2. Set triggerConfig.webhookSecret for authentication
  3. Optionally set triggerConfig.messageTemplate for Mustache-style payload transformation
  4. Configure the external service to POST to https://your-host/api/hooks/incoming/<hook-uuid>

Authentication: Every request must include the secret via Authorization: Bearer <secret> or X-Webhook-Secret: <secret> header.

Templating: Use &#123;&#123;body.field.path&#125;&#125; to extract values from the incoming JSON payload.

MethodPathDescription
GET/api/hooksList user’s hooks
POST/api/hooksCreate hook
PATCH/api/hooks/:idUpdate hook
DELETE/api/hooks/:idDelete hook
POST/api/hooks/:id/toggleEnable/disable
POST/api/hooks/:id/testTrigger manually
GET/api/hooks/:id/executionsExecution history
GET/api/hooks/executions/allAll user executions
POST/api/hooks/incoming/:hookIdReceive inbound webhook (public, auth via secret)
GET/api/hooks/suggestionsSuggested hooks
POST/api/hooks/suggestions/:id/applyApply suggestion
  1. Go to Hooks page and click the history icon on the hook row
  2. Or switch to Execution Log tab for all executions
  3. Expand an entry to see full result/error and trigger context
  4. If no executions appear, verify:
    • Hook is enabled
    • Trigger config matches (channel types, patterns, webhook path)
    • Conditions aren’t filtering everything out
    • Cooldown hasn’t blocked it
    • Max executions hasn’t been reached