If icon
BlueskyExecution icon
DiscordIncomingWebhook icon
Fail icon
Webhook icon

Publish Incident Status Updates to Bluesky with Human Sign-Off

Publish incident status updates to Bluesky with Kestra. An ops webhook proposes the post, a human sign-off gate approves it, and Discord logs the outcome.

Categories
Business

During an incident, the public status feed is the one channel where automation must not outrun judgment. A wrong or premature post erodes exactly the trust the feed exists to protect. This blueprint automates everything except the decision: incident tooling POSTs a proposed status update to a Kestra webhook, io.kestra.plugin.core.flow.If checks a boolean approval flag, and only an approved draft reaches io.kestra.plugin.bluesky.BlueskyExecution and the public feed. An unapproved draft fails the execution through io.kestra.plugin.core.execution.Fail, loudly and visibly, instead of being quietly dropped.

Bluesky increasingly serves as the community-facing status channel for developer products, where affected users actually follow along, and this flow treats it with the care a public channel deserves: posts are effectively irreversible once seen, so the default answer is always no. Each published skeet also carries its own provenance, opening with the execution state and flow id and closing with a link to the execution, so every update visibly comes from the approved status pipeline rather than a rushed manual post.

How it works

  1. The incident_webhook trigger (io.kestra.plugin.core.trigger.Webhook) receives status_message and approved from the incident tooling, typically wired to a confirm button an incident commander clicks.
  2. signoff_gate (io.kestra.plugin.core.flow.If) evaluates {{ (trigger.body.approved ?? inputs.approved) == true }}. Manual executions use the approved flow input, which defaults to false, the safe state.
  3. On approval, post_status (io.kestra.plugin.bluesky.BlueskyExecution) posts the update with the approved text as customMessage. The plugin always renders its built-in execution template: the post opens with the execution state and flow id, for example RUNNING: company.team/bluesky-incident-status-post, then the approved message, and closes with a link to the execution in the Kestra UI. The 300-grapheme limit applies to that whole rendered post.
  4. log_publication writes the outcome to the Discord incident channel, adding the public post to the incident timeline.
  5. Without approval, refuse_unapproved (io.kestra.plugin.core.execution.Fail) fails the execution with an explicit message, and the errors block posts a Discord alert so the team knows the public feed was not updated.

What you get

  • A public status pipeline where a human decision is structurally required, not procedurally hoped for.
  • Fail-loud semantics, since a refused or failed post raises an alert instead of leaving a stale feed unnoticed.
  • A Discord record of every publication and every refusal, aligned with the incident timeline.
  • One flow serving both tooling-driven and manual publication paths.

Who it's for

  • SRE and incident response teams publishing public status updates during outages.
  • Communication leads who want automation speed without giving up editorial control.
  • Teams whose users follow service status on Bluesky rather than a legacy status page.

Why orchestrate this with Kestra

Approval gates bolted onto chat bots tend to decay into rubber stamps because nothing enforces them. In Kestra the gate is control flow: the posting task is structurally unreachable without the flag, the refusal is a failed execution in the history, and the app password never leaves the secret store. Every status update, posted or refused, is auditable after the retro.

Prerequisites

  • A Bluesky account used as the public status feed and an app password created under Settings, never the account password.
  • Incident tooling able to POST JSON to the webhook URL with an explicit approval flag.
  • A Discord incoming webhook for the incident channel.

Secrets

  • BLUESKY_IDENTIFIER: the Bluesky handle of the status account, for example yourstatus.bsky.social.
  • BLUESKY_APP_PASSWORD: an app password generated in Bluesky settings.
  • DISCORD_WEBHOOK_URL: Discord incoming webhook URL for the incident channel.

Quick start

  1. Add the three secrets to your Kestra namespace.
  2. Execute the flow manually with approved left at false and confirm it fails with the refusal message and a Discord alert.
  3. Execute again with approved set to true and a test status_message, and check the skeet on the status account.
  4. Replace the webhook key with a strong random value and wire your incident tooling's confirm action to the URL.

How to extend

  • Add a resolution template by passing a phase field in the webhook body and branching the wording on it.
  • Mirror approved updates to additional channels by adding tasks after post_status.
  • Announce scheduled maintenance on a cadence instead, as shown in the changelog digest blueprint.
  • Post routine milestones without a gate where stakes are low, as shown in the community milestone blueprint.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.