Skip to content

Triggers

Every agent turn in Zooid starts with a message in a room. Usually a person writes it. A trigger is the daemon writing it instead.

That is the whole idea, and it is deliberately not a plugin API. A trigger is a bot user — @cron, @hook — that joins a room and posts text mentioning an agent. Everything after that is the path Zooid already had:

WhatWho handles it
Which agent wakesthe ordinary mention routing
The sessionthe message becomes a thread root, so each firing gets a fresh session
Visibilitythe message is in scrollback, so people can see why an agent woke
Steeringreply in the thread, the same as any other conversation
PermissionsMatrix power levels on the bot user

A daily trigger therefore gets a new thread and a new session every day without any scheduling state of its own, and a webhook that fires at 3am leaves a conversation your team can read at 9.

A trigger asks; the agent does

A trigger runs no commands and computes nothing. It says what it wants, and names who should do it:

triggers:
agent-image-currency:
schedule: "0 6 * * 1"
as: "@cron"
room: "#ops"
mention: architect
text: |
Check whether the pinned agent CLI versions are behind npm `latest`.
If any are, open a bump PR. If none are, say so and stop.

This is the part that most often surprises people coming from CI. There is no step that shells out, captures stdout, and pastes it into the message — because the agent already has a shell, a workspace, credentials and tools. A trigger that pre-computes a result and hands the agent a blob is doing the agent’s job, worse, in a second place. The agent runs the check itself and sees the real output.

Schedule or webhook

Two kinds, and the choice isn’t a preference — it follows from whether the thing you care about announces itself:

  • schedule: — for state that only reveals itself when you look. Nothing emits an event, so going to check is the only option. Is a pinned dependency stale? Did the backup actually run? Is anything sitting in the review queue?
  • webhook: — for events that arrive on their own. Polling for these is strictly worse: later, noisier, and it re-derives what you were already told. A PR merged. An invoice failed. An issue was opened.

The trap is reaching for a schedule because it’s simpler to set up, for something that already tries to tell you. A nightly “check for merged PRs” job is slower than the webhook, runs 364 times for nothing, and still misses the context the event carried.

What it looks like in the room

Every firing is an ordinary message, so a trigger’s history is the room’s history. You can see when the last one ran, what it asked, what the agent did about it, and what a colleague said in reply — without opening a dashboard.

See Setting up triggers for the config, providers, secrets, and filtering.