Notifications
sfdt can push deployment events and org-health snapshots to Slack, Microsoft Teams, Google Chat, email, a generic webhook, or Grafana Loki — with per-channel event filtering and severity routing.
The multi-channel channels[] system is gated by notifications.enabled. The older
single-Slack shape (notifications.slack.webhookUrl) is still honored when
features.notifications: true. See Configuration.
Configuration
{
"features": { "notifications": true },
"notifications": {
"enabled": true,
"summary": { "enabled": false },
"channels": [
{
"type": "slack",
"name": "team-deploys",
"webhookUrlEnv": "SLACK_WEBHOOK_URL",
"severityThreshold": "warn",
"events": ["deploy-failure", "snapshot"]
},
{
"type": "teams",
"name": "ops",
"webhookUrlEnv": "TEAMS_WEBHOOK_URL",
"severityThreshold": "fail",
"events": ["snapshot"]
},
{
"type": "googlechat",
"name": "gchat-ops",
"webhookUrlEnv": "GCHAT_WEBHOOK_URL",
"severityThreshold": "warn",
"events": ["deploy-failure", "snapshot"]
},
{
"type": "email",
"name": "admins",
"from": "ci@example.com",
"to": ["admin@example.com"],
"smtp": { "hostEnv": "SFDT_SMTP_HOST", "portEnv": "SFDT_SMTP_PORT", "userEnv": "SFDT_SMTP_USER", "passwordEnv": "SFDT_SMTP_PASS" },
"severityThreshold": "fail",
"events": ["snapshot"]
},
{
"type": "webhook",
"name": "loki",
"format": "loki",
"url": "https://logs-prod.grafana.net/loki/api/v1/push",
"severityThreshold": "warn",
"events": ["snapshot"]
}
]
}
}Secrets are referenced by env-var name, never inline. Webhook URLs and SMTP credentials are
given as the name of an environment variable (webhookUrlEnv, urlEnv, SMTP *Env) — the
value is read from process.env at send time and is never stored in config. Inline
webhookUrl/url are still supported for back-compat but discouraged.
The same applies to webhook auth headers — use headersEnv, not headers, for anything
secret.
Authenticating a webhook channel
headers takes literal values, so a token placed there is written into .sfdt/config.json. Use
headersEnv instead — it maps a header name to the name of the env var holding its value:
{
"type": "webhook",
"name": "n8n",
"webhookUrlEnv": "HARNESS_WEBHOOK_URL",
"headersEnv": { "X-Auth-Token": "HARNESS_WEBHOOK_TOKEN" }
}headersEnv overrides a literal headers entry of the same name, so an existing config can adopt
it one key at a time. If a named env var is unset or empty, that channel fails with an error
naming the variable — it does not fall back to sending the request unauthenticated. Other channels
are unaffected.
Works with n8n Header Auth, Cloudflare Access service tokens, and any gateway expecting a shared-secret header.
Channel fields
| Field | Applies to | Meaning |
|---|---|---|
type | all | slack | teams | googlechat | email | webhook |
name | all | Friendly label (shown in CLI/GUI results) |
webhookUrl / webhookUrlEnv | slack, teams, googlechat | Incoming-webhook URL (inline or env-var name) |
url / urlEnv | webhook | Endpoint URL (inline or env-var name) |
format | webhook | json (default) or loki (Grafana Loki push) |
headers | webhook | Extra HTTP headers (literal values) |
headersEnv | webhook | Header name → name of the env var holding its value. Use this for auth tokens. |
from, to, smtp | Sender, recipients, and SMTP env-var names | |
severityThreshold | all | Minimum snapshot severity to receive (ok | warn | error | fail) |
events | all | Which events this channel receives (omit = all) |
Email uses nodemailer, an optional dependency that is lazy-loaded only when an email channel
is configured.
Events & severity routing
- Lifecycle events —
deploy-success,deploy-failure,test-failure,release-created,harness-escalation— are sent to any channel whoseeventsfilter allows them. - The
snapshotevent (an audit/monitor run) is routed by severity: a channel receives it only when the snapshot’s worst status is at or above the channel’sseverityThreshold.
Severity rank: ok < warn < error < fail.
AI executive-summary digests
Set notifications.summary.enabled = true to have snapshot notifications carry a 1–2 paragraph AI
executive summary (top issue + next steps) instead of the raw findings list. It requires
features.ai and an available AI provider; the summary is computed once and reused across
channels, and falls back to the normal body when AI is unavailable. The wording is controlled by
the editable monitor-summary prompt (see AI Providers).
Commands
sfdt notify deploy-failure --org prod --message "Release 1.4 failed"
sfdt notify snapshot --type monitor # push the latest monitor snapshot
sfdt notify snapshot --type audit
sfdt monitor all --notify # run + notify in one step
sfdt audit all --notifySee Org Health & Operations for the audit/monitor commands.
Surfaces
- GUI — the Notifications page lists configured channels (secrets redacted), shows whether the AI summary is on, and offers a “send test to all channels” button.
- MCP —
sfdt_notifypushes the latest snapshot. - CI — the generated pipelines run
monitor all --notifyon a schedule (see CI/CD Integration).