Files
buzz/docs/guides/workflows.md
npub1pejagjwzjh7y36gq97hxf62ry75u3s6c6grr0rumx2p4c5qsms9s7jdtgl 23f75dac90 docs: write full documentation content (Phase 2)
Fill all 31 stub pages scaffolded in Phase 1 with content migrated and
verified from the root docs, crate READMEs, and source code:

- getting-started/ (3): installation, quickstart, local relay (TESTING.md)
- architecture/ (8): ARCHITECTURE.md §1–§8, one page per section
- guides/ (9): development, testing, agents, workflows, self-hosting,
  nostr-clients (operational half of NOSTR.md), adding-event-kinds,
  adding-api-endpoints, releasing
- reference/ (5): CLI reference verified against buzz --help and
  crates/buzz-cli/src (18 groups / 87 subcommands; README drift noted),
  configuration, known-limitations (ARCHITECTURE §9 + conformance
  LIMITS.md + doc-debt list), NIPs index (13, NIP-CW canonical),
  design-docs index
- vision/ (6): VISION.md + 5 VISION_*.md migrated with aspirational
  banners and rewritten links

Root originals (ARCHITECTURE, NOSTR, TESTING, RELEASING, VISION*) get
pointer notes marking docs/ as canonical; deletion is a follow-up.
All relative links in the new tree verified to resolve.

Known limitations are documented honestly, never papered over:
rate limiting unenforced, WF-07/WF-08 workflow stubs, buzz-cli README
drift, one-line GOVERNANCE.md.

Note: pre-commit sadscan findings reviewed as false positives (dev-default
postgres URI and NIP-OA test vectors, both already on origin/main).

Co-authored-by: npub1pejagjwzjh7y36gq97hxf62ry75u3s6c6grr0rumx2p4c5qsms9s7jdtgl <0e65d449c295fc48e9002fae64e94327a9c8c358d206378f9b32835c5010dc0b@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: npub1pejagjwzjh7y36gq97hxf62ry75u3s6c6grr0rumx2p4c5qsms9s7jdtgl <0e65d449c295fc48e9002fae64e94327a9c8c358d206378f9b32835c5010dc0b@sprout-oss.stage.blox.sqprod.co>
2026-07-07 12:14:33 -07:00

4.2 KiB
Raw Blame History

Workflows

YAML-as-code automation, scoped to a channel. A workflow is a trigger plus a list of steps; every run is recorded as workflow execution events (kinds 46001–46012) with a full trace. Engine: crates/buzz-workflow.

Workflow model

name: "Incident Triage"
trigger:
  on: message_posted
  filter: "str_contains(trigger_text, 'P1')"
steps:
  - id: notify
    action: send_message
    text: "P1 incident detected: {{trigger.text}}"
  - id: page
    if: "str_contains(trigger_text, 'production')"
    action: request_approval
    from: "{{trigger.author}}"
    message: "Page on-call?"

Triggers are internally tagged on on:; actions on action:. Each step has a unique id (alphanumeric + underscore, ≤64 chars — step IDs become evalexpr variable names), an optional if: condition (step is skipped, not failed, when false), and an optional timeout_secs.

Manage workflows with the CLI: buzz workflows create / list / get / update / delete / trigger / runs / approve.

Triggers (5)

Trigger Fires when Options
message_posted Any message posted in the workflow's channel filter: evalexpr expression
reaction_added An emoji reaction is added emoji: limit to one emoji
diff_posted A diff message (kind:40008) is posted filter: as above
schedule Cron expression or simple interval (UTC) cron: or interval: (e.g. "1h") — exactly one
webhook HTTP POST arrives at /hooks/{id} secret-authenticated

(Source: TriggerDef in crates/buzz-workflow/src/schema.rs.)

The cron scheduler ticks every 60 seconds and evaluates expressions with window-based matching.

Actions (7)

Action Description Status
send_message Post to the workflow's channel (or channel: override) ✅
send_dm Direct message a user (to: pubkey hex or {{trigger.author}}) ❌ returns NotImplemented (WF-07)
set_channel_topic Update channel topic ❌ returns NotImplemented (WF-07)
add_reaction React to the trigger message ✅
call_webhook HTTP POST to an external URL — SSRF-protected, redirects disabled, 1 MiB response cap ✅
request_approval Suspend and wait for approval (from:, message:, timeout: default 24h) ⚠️ not wired end-to-end (WF-08)
delay Pause execution (duration:, max 300 seconds) ✅

Templates and variables

  • {{trigger.text}}, {{trigger.author}}, {{steps.ID.output.FIELD}}
  • Single-pass resolution — templates are not recursive; unknown variables are left as literal text.

filter: / if: conditions use evalexpr with dot-notation converted to underscores (trigger.text → trigger_text). Registered helper functions: str_contains, str_starts_with, str_ends_with, str_len. Evaluation has a 100 ms timeout.

Approval gates

request_approval is designed to suspend a run and resume it after a signed-off approval (buzz workflows approve --token <uuid>), with approval tokens stored as SHA-256 hashes and single-use enforcement.

⚠️ Current status (WF-08): the executor returns Suspended and the relay has grant/deny endpoints with DB CRUD, but the engine does not yet persist the token or resume execution — runs that hit an approval gate are marked as failed. Track this in Known Limitations.

Concurrency and loop prevention

  • 100 concurrent runs (semaphore); at capacity a new trigger returns CapacityExceeded immediately rather than queuing.
  • Workflow execution kinds (46001–46012), relay-signed messages tagged buzz:workflow, and gift wraps never trigger workflows — no self-loops.

Known limitations

See Known Limitations — in short: send_dm / set_channel_topic are schema-only stubs (WF-07), and approval gates fail rather than suspend (WF-08).

Note: ARCHITECTURE.md §buzz-workflow says "4 trigger types"; the code has 5 (diff_posted was added, and schedule gained interval:). This page follows the code.