Skip to content

Hooks & notifications

Hooks run your code when the loop does something; notification channels tell you about it. Both are configured globally and per-project.

Two hook types:

  • command: run a shell command. The event payload is JSON on stdin; the hook runs via sh -c with a 10-second default timeout.
  • webhook: HTTP POST the same JSON payload to a URL.
Terminal window
# a global command hook on specific events
openloop config add-hook \
--type command \
--events promotion-auto-merge-queued \
--command 'node scripts/review-gate.mjs'
# a project-level webhook
openloop config project-add-hook api \
--type webhook \
--events 'task-complete,task-failed' \
--url https://example.com/hooks/openloop
# manage
openloop config list-hooks
openloop config remove-hook 0

Options: --type command|webhook (required), --events (comma-separated or * for all, default *), --command or --url (required per type), --timeout-seconds (default 10).

Event Fired when
task-complete / task-failed a scheduled run finishes
validation-failed post-run validations fail
task-awaiting-approval a task enters awaiting-approval
promotion-auto-merge-queued an auto-merge is about to be applied
promotion-review-queued a promotion waits for human review
promotion-blocked policy blocks a promotion
promotion-ci-failed PR checks fail
all-tasks-done a project’s queue drains
budget-blocked daily spend hits the ceiling
daily-digest the daily digest fires
review-backpressure a project is skipped for pending reviews
{
"event": "promotion-auto-merge-queued",
"project": "api",
"taskId": "add-rate-limit-headers"
}

Command hooks also get OPENLOOP_EVENT, OPENLOOP_PROJECT, and OPENLOOP_TASK_ID in the environment.

A command hook may respond (stdout, JSON) with:

{ "note": "touched auth middleware", "requireManualReview": true }

requireManualReview: true downgrades the promotion to manual review and the note is attached to the artifact. This is the extension point for custom gates, extra checks, approval systems, deploy freezes.

Higher-level than hooks: formatted notifications on channels.

Terminal window
# any HTTP endpoint (Slack/Discord webhooks, etc.)
openloop config add-channel --type webhook --url https://hooks.slack.com/… \
--events 'task-complete,budget-blocked'
# desktop notifications (notify-send on Linux, osascript on macOS)
openloop config add-channel --type desktop
openloop config list-channels
openloop config remove-channel 0

notifications.onTaskComplete & co. (global config) run a shell command for a single event, superseded by hooks and channels, kept for compatibility.