Broadcast
•2 min read
@sizl/broadcast — consumer integration patterns
@sizl/broadcast is the marketing-automation runtime that powers the kill log at directive.run/broadcast. Five consumer surfaces ship the runtime in different shapes — pick the one that matches how your team works.
Surface map
| Surface | When to reach for it | Tier 1 | Tier 2 | Engagement |
|---|---|---|---|---|
| GitHub Action | Repo-driven releases. One workflow line, public, OSS-mirrored. | yes | refused | n/a |
| CLI | Manual posts, backfills, dry-runs, cassette verification. | yes | yes | n/a |
| Cloudflare Worker scaffold | Long-lived listener with the 15-min approval window AND the engagement cron. | yes | yes | yes |
| MCP server | AI assistants drafting on your behalf. Mandatory queue + approve. | n/a | yes | n/a |
| README badge | Adoption signal. Embed <img src="https://directive.run/badge/<project>.svg">. | n/a | n/a | n/a |
All five surfaces share the same @sizl/broadcast core: identical sanitizer, identical Tier 2 workflow, identical Pluck cassette envelope. The differences are runtime-shape — what state the surface owns, what work it can host, what credentials it can hold.
Why so many surfaces
A GitHub Action's runner is ephemeral, so it can run a one-shot Tier 1 dispatch but cannot host a 15-minute Tier 2 approval window — the runner exits long before the operator clicks APPROVE. A Cloudflare Worker is long-lived but has no filesystem, so the dev-key signer that the CLI uses needs a Web-Crypto variant in the Worker template. An MCP server is the AI assistant's only path to the runtime, so it must default-deny every surface (empty allowlist, no raw post tool, mandatory operator label) because the failure mode is the AI broadcasting under your voice without you in the loop.
Each consumer doc spells out the constraint that surface lives under, the trade-off it accepts, and how it stays compatible with the others through the shared StateStore / CounterStore / EngagementStore interfaces.
The flow at a glance
- Event arrives. GitHub release webhook, CLI
broadcast post, MCPbroadcast.queue, or scheduled task. - Sanitize. The shared
sanitizeDraft()blocks internal-voice leaks; the MCP server adds a credential-shape scan. - Tier assignment. Template-driven announcement → Tier 1 (inline). Anything LLM-drafted or with auto-escalation reasons → Tier 2 (queued).
- Cost-breaker. Per-event, per-day, per-month, per-USD caps via the shared
CounterStore. - Dispatch. The platform adapter posts; the response stamps a Pluck cassette.
- Receipt. The cassette envelope (id, platform, postedAt, cassetteHash, rekorUrl) goes to the kill-log. The badge generator updates the project's count.
Read How broadcast routes a release for the visible end of that flow: every dispatched post lands in the public kill log with a verifiable receipt.

