Skip to content

Hooks and Webhooks

Rocky fires lifecycle events at key points during pipeline execution. You can attach shell scripts or HTTP webhooks to any event for notifications, gating, auditing, or custom integrations.

Events are organized into five phases:

EventWhenUse case
pipeline_startPipeline beginsSlack notification, deploy freeze gate
discover_completeSource discovery finishesLog connector/table counts
compile_completeCompilation finishesValidate types before execution
pipeline_completePipeline succeedsSuccess notification, metrics push
pipeline_errorPipeline failsPagerDuty alert, incident creation
EventWhenUse case
before_materializeBefore table copyAudit logging
after_materializeAfter table copyPublish to data catalog
materialize_errorTable copy failsPer-table alerting
EventWhenUse case
before_model_runBefore compiled model runsFeature flag checks
after_model_runAfter compiled model runsLineage metadata push
model_errorModel execution failsDebug notification
EventWhenUse case
before_checksQuality checks beginMute downstream alerts during expected check windows
check_resultA quality check completesPer-check threshold alerting
after_checksAll checks finishAggregate summary to dashboards, gating on total pass rate
drift_detectedSchema drift foundSchema change notification
anomaly_detectedRow count anomalyData quality alert
EventWhenUse case
state_syncedState store syncedBackup confirmation
EventWhenUse case
budget_breachObserved run cost or duration exceeds a limit declared in [budget]Page oncall on overspend; gate downstream runs on on_breach = "error"
EventWhenUse case
circuit_breaker_trippedAdapter circuit breaker moves Closed → Open after consecutive transient failuresMute retries; notify oncall that a warehouse endpoint is unhealthy
circuit_breaker_recoveredHalf-open trial request succeeds and the breaker closesClear the alert; record recovery latency

Circuit-breaker behaviour is configured per-adapter via [adapter.NAME.retry]circuit_breaker_threshold sets the failure count that trips it, and circuit_breaker_recovery_timeout_secs enables timed auto-recovery through the half-open state.

Shell hooks execute a command and pipe the event context as JSON to stdin:

[[hook.pipeline_complete]]
command = "bash scripts/slack-notify.sh"
timeout_ms = 5000
on_failure = "warn"

The script receives JSON like:

{
"event": "pipeline_complete",
"run_id": "run_20260402",
"timestamp": "2026-04-02T14:30:00Z",
"duration_ms": 45200,
"metadata": {
"tables_copied": "20",
"tables_failed": "0"
}
}
ModeBehavior
abortStop the pipeline if the hook fails
warnLog a warning and continue (default)
ignoreSilently continue

Use abort for gating hooks (deploy freeze, approval gates). Use warn or ignore for notifications.

The command string is passed to sh -c verbatim. The event context is delivered to the script as JSON on stdin — it is not interpolated into the command line — so the runtime values Rocky exposes (run_id, event, etc.) cannot inject shell metacharacters into your command.

That said, never build a hook command by string-formatting untrusted input (a webhook payload, a Fivetran response, a value pulled from a row, anything you don’t fully control). Use only static commands or commands templated from values you control yourself. If you need to react to dynamic input, hand it off through the JSON context to a script you wrote, and let that script decide what to do with quoting / validation.

Webhooks send HTTP requests instead of running shell commands:

[hook.webhooks.pipeline_error]
url = "https://hooks.slack.com/services/T.../B.../xxx"
preset = "slack"
secret = "${WEBHOOK_SECRET}"
PresetServiceBody format
slackSlack Incoming WebhookSlack Block Kit JSON
pagerdutyPagerDuty Events API v2PD event payload
datadogDatadog Events APIDD event JSON
teamsMicrosoft Teams WebhookAdaptive Card JSON

Presets provide default body templates and headers. Override any field in your config.

When secret is set, Rocky signs the request body with HMAC-SHA256:

X-Rocky-Signature: sha256=<hex-encoded digest>

The receiving service can verify the signature to ensure the request came from Rocky.

Custom body templates use Mustache-style syntax:

body_template = """
{
"text": "Pipeline {{event}}: {{metadata.tables_copied}} tables copied in {{duration_ms}}ms"
}
"""

Supported: {{field}}, {{metadata.key}}, {{#if field}}...{{/if}}.

Validate your hook configuration without running a real pipeline:

Terminal window
# List all configured hooks
rocky hooks list
# Fire a test event
rocky hooks test pipeline_start

The test command sends a synthetic event context to verify scripts execute correctly.