# Buzz Workflow Engine Trigger Types: Complete Guide to Event-Driven Automation

> Explore Buzz workflow engine trigger types: message_posted, reaction_added, diff_posted, schedule, and webhook. Automate tasks with event-driven workflows.

- Repository: [Block Open Source/buzz](https://github.com/block/buzz)
- Tags: deep-dive
- Published: 2026-08-27

---

**The Buzz workflow engine supports five distinct trigger types defined in the `TriggerDef` enum: `message_posted`, `reaction_added`, `diff_posted`, `schedule`, and `webhook`.** Each trigger type determines when a workflow executes—ranging from chat events and reactions to timed schedules and external HTTP requests—with optional filtering capabilities via `evalexpr` expressions.

The `buzz-workflow` crate powers event-driven automation in the Buzz platform, implementing the core trigger system in Rust. At the heart of this engine lies the `TriggerDef` enum located in [`crates/buzz-workflow/src/schema.rs`](https://github.com/block/buzz/blob/main/crates/buzz-workflow/src/schema.rs) (lines 38-71), which defines exactly when workflows activate. Every workflow definition must specify exactly one `trigger` field that instructs the engine when to initiate execution.

## Core Trigger Architecture

The trigger system uses **internally-tagged serialization** with the `on` key as the discriminator. The `TriggerDef` enum declaration utilizes `#[serde(tag = "on", rename_all = "snake_case")]` to map YAML/JSON payloads to Rust variants. This design ensures type-safe parsing while maintaining human-readable workflow definitions where the `on` field indicates the trigger variant.

When the workflow engine parses a definition, it validates the trigger configuration through `WorkflowDef::validate` in the same schema file. This validation enforces field requirements, mutual exclusivity constraints, and minimum value thresholds specific to each trigger type.

## Supported Trigger Types

### Message Posted (`message_posted`)

The **`message_posted`** trigger fires whenever any message appears in the workflow's channel. This trigger accepts an optional `filter` field containing an **evalexpr** string that evaluates message content conditionally before workflow execution.

```yaml
name: "Alert on P1"
trigger:
  on: message_posted
  filter: 'str_contains(trigger_text, "P1")'
steps:
  - id: notify
    action: send_message
    text: "P1 alert detected"

```

The `filter` parameter accesses message context variables to determine whether the workflow should run, enabling fine-grained control without modifying the core workflow logic.

### Reaction Added (`reaction_added`)

The **`reaction_added`** trigger activates when a user adds an emoji reaction to a message. This variant supports two optional fields: `emoji` to match specific Unicode reactions, and `filter` for complex conditional logic over the reaction context.

```yaml
name: "Triage via Reaction"
trigger:
  on: reaction_added
  emoji: clipboard
steps:
  - id: ack
    action: add_reaction
    emoji: eyes

```

When the `emoji` field is specified, the workflow triggers only for that specific reaction. When omitted, the workflow responds to any reaction added to messages in the channel.

### Diff Posted (`diff_posted`)

Specific to Nostr protocol integration, the **`diff_posted`** trigger responds to `kind:40008` diff events posted in the channel. This trigger type uses the same filtering variables as `message_posted` through its optional `filter` field.

```yaml
name: "Diff Monitor"
trigger:
  on: diff_posted
steps:
  - id: log
    action: send_message
    text: "New diff posted: {{trigger.diff_id}}"

```

This trigger enables automated code review and change management workflows within the Buzz platform's Nostr integration layer.

### Schedule (`schedule`)

The **`schedule`** trigger provides time-based execution supporting either **cron expressions** (UTC timezone) or **interval durations**. These fields are mutually exclusive—the implementation in `WorkflowDef::validate` ensures exactly one is present, with `interval` values requiring a minimum of 60 seconds to align with the engine's minute-level cron loop.

**Cron expression example:**

```yaml
name: "Daily Standup"
trigger:
  on: schedule
  cron: "0 9 * * 1-5"   # 09:00 UTC Monday-Friday

steps:
  - id: ping
    action: send_message
    text: "Standup time!"

```

**Interval example:**

```yaml
name: "Heartbeat"
trigger:
  on: schedule
  interval: "30m"
steps:
  - id: heartbeat
    action: send_message
    text: "I'm alive"

```

The `cron` field accepts standard cron syntax, while `interval` accepts duration strings such as `"1h"` or `"30m"`.

### Webhook (`webhook`)

The **`webhook`** trigger enables external systems to initiate workflows via HTTP POST requests. When this trigger is present, the engine automatically exposes an endpoint at `/hooks/{id}` where `{id}` corresponds to the workflow identifier. No additional configuration fields are required.

```yaml
name: "External Alert"
trigger:
  on: webhook
steps:
  - id: notify
    action: send_message
    text: "Webhook received from {{trigger.source}}"

```

The trigger payload includes metadata about the HTTP request source, accessible through the `trigger` context variable within workflow steps.

## Validation and Implementation Details

The `WorkflowDef::validate` method in [`crates/buzz-workflow/src/schema.rs`](https://github.com/block/buzz/blob/main/crates/buzz-workflow/src/schema.rs) enforces trigger-specific constraints before workflow registration. For `schedule` triggers, the validator confirms that either `cron` or `interval` is specified, but never both. Additionally, interval durations must meet the 60-second minimum threshold because the background scheduler ticks at one-minute intervals.

Runtime execution of triggers occurs in [`crates/buzz-workflow/src/executor.rs`](https://github.com/block/buzz/blob/main/crates/buzz-workflow/src/executor.rs), which handles the event routing and context building for each trigger type. The public API for parsing and validating workflow definitions resides in [`crates/buzz-workflow/src/lib.rs`](https://github.com/block/buzz/blob/main/crates/buzz-workflow/src/lib.rs), exposing functions like `parse_yaml` that consume these trigger definitions.

## Summary

- **Five trigger types** are available: `message_posted`, `reaction_added`, `diff_posted`, `schedule`, and `webhook`.
- **Event triggers** (`message_posted`, `reaction_added`, `diff_posted`) support optional `evalexpr` filters for conditional execution.
- **Time triggers** (`schedule`) require either a cron expression or an interval string, but never both, with intervals capped at a 60-second minimum.
- **External triggers** (`webhook`) automatically provision HTTP endpoints at `/hooks/{id}` without additional configuration fields.
- All trigger definitions are parsed and validated through the `buzz-workflow` crate's schema system before runtime execution.

## Frequently Asked Questions

### How many trigger types does the Buzz workflow engine support?

The Buzz workflow engine supports exactly five trigger types defined in the `TriggerDef` enum: `message_posted`, `reaction_added`, `diff_posted`, `schedule`, and `webhook`. Each type corresponds to a specific event source, ranging from internal chat events to external HTTP requests.

### Can a single workflow use multiple trigger types simultaneously?

No, each workflow definition must specify exactly one trigger field. The engine enforces this constraint through the `WorkflowDef` structure in [`crates/buzz-workflow/src/schema.rs`](https://github.com/block/buzz/blob/main/crates/buzz-workflow/src/schema.rs). If you need to respond to multiple event types, you must create separate workflow definitions for each trigger type.

### What is the minimum interval for scheduled workflows?

Scheduled workflows using the `interval` field must specify durations of at least 60 seconds (one minute). This limitation exists because the background scheduling loop ticks at minute intervals. For sub-minute precision, use the `cron` field with specific second-level expressions if supported by the underlying scheduler.

### How does the `filter` field work in message triggers?

The `filter` field accepts an **evalexpr** expression string that evaluates against trigger context variables. For `message_posted` and `diff_posted` triggers, you can reference message content through variables like `trigger_text`. The workflow only executes if the expression evaluates to true, enabling conditional automation without separate filtering steps.