Skip to content

Notifications

cliq can notify external systems when pipeline events occur. Notifications are event-driven and fire-and-forget — failures are logged to orchestrator.log but never block the pipeline. Use them to keep your team informed and to keep Jira tickets in sync with pipeline status.

Two channels are supported out of the box: Slack (via Incoming Webhooks) and Jira (comments and ticket transitions). An automatic A2A event bridge also streams events to calling agents when pipelines are initiated via the A2A protocol.


cliq fires eight notification events across the pipeline lifecycle:

EventWhen it firesContext available
on_startPipeline begins executioninstance_id, req_key
on_phase_startA phase begins executioninstance_id, req_key, phase, phase_type
on_phase_completeA phase finishesinstance_id, req_key, phase, phase_type, outcome, iteration
on_completeAll phases finish successfullyinstance_id, req_key
on_escalatePipeline halts — human intervention requiredinstance_id, req_key, phase, reason
on_cancelPipeline cancelled by user (Ctrl-C, SIGTERM, SIGHUP)instance_id, req_key, reason
on_pullExternal content is pulled into the workspace (before the phase activates)instance_id, req_key, pull_name, pull_url, pull_source_type, pull_size_bytes, pull_file_count, status
on_pushA file is pushed to an external destination (after phase completion)instance_id, req_key, phase, push_file, push_destination, push_mode, push_external_url, status, error_message

Every notification handler receives a NotificationContext object:

{
"instance_id": "cliq-a1b2c3",
"req_key": "PROJ-123",
"phase": "reviewer",
"phase_type": "gate",
"outcome": "done",
"iteration": 2,
"reason": "Gate 'reviewer' exhausted its iteration budget (3 iterations)",
"project_dir": "/path/to/project"
}

Not all fields are present for every event. phase, phase_type, outcome, and iteration are populated for phase-level events. reason is populated for on_escalate and on_cancel.


ChannelWhat it does
slackPosts a formatted message via Incoming Webhook
jiraAdds a comment to the originating Jira ticket. On escalation, transitions the ticket to a configurable status

Configure notifications in settings.json (global or project). Each event lists which channels to notify. Set up Slack and Jira credentials first — see Integrations.

{
"notifications": {
"on_start": { "channels": ["slack"] },
"on_phase_start": { "channels": ["slack"] },
"on_phase_complete": { "channels": ["slack", "jira"] },
"on_complete": { "channels": ["slack", "jira"] },
"on_escalate": { "channels": ["slack", "jira"] },
"on_cancel": { "channels": ["slack"] }
}
}

Leave channels as an empty array [] — or omit the event entirely — to disable notifications for that event.

You can override channel-specific settings for individual events. This is useful for routing escalations to a different Slack channel or changing the Jira transition:

{
"notifications": {
"on_start": { "channels": ["slack"] },
"on_complete": { "channels": ["slack", "jira"] },
"on_escalate": {
"channels": ["slack", "jira"],
"slack": { "webhook_url": "https://hooks.slack.com/services/DIFFERENT/HOOK/for-incidents" },
"jira": { "transition_to": "Blocked" }
}
}
}

The slack.webhook_url override only applies to on_escalate in this example. All other events use the default webhook from integrations.slack.

OverrideTypeDescription
slack.webhook_urlstringSend this event to a different Slack webhook
jira.transition_tostringJira transition name to apply for this event (only used by on_escalate)

Webhook calls (both Slack and Jira) retry up to 3 times with exponential backoff (1 s, 3 s delays) on transient failures:

  • HTTP 429 (Too Many Requests)
  • HTTP 5xx (Server errors)
  • Network errors (ECONNRESET, ECONNREFUSED, etc.)

Permanent failures (4xx other than 429) are not retried.


When a pipeline is initiated via the A2A protocol, notification events are automatically written to .cliq/signals/_a2a_events as JSON Lines. The server process polls this file and relays events to the calling agent over the A2A stream as TaskStatusUpdateEvent messages with structured DataPart payloads.

This is not a user-configurable channel — it activates automatically for A2A-initiated pipelines whenever the .cliq/signals/_a2a_task marker file exists. No changes to notifications settings are needed.

Each line in the events file is a JSON object:

{
"event": "on_phase_complete",
"instance_id": "cliq-a1b2c3",
"req_key": "PROJ-123",
"phase": "developer",
"phase_type": "standard",
"outcome": "done",
"iteration": 1,
"ts": "2026-03-26T14:30:00.000Z"
}

All six events (on_start, on_phase_start, on_phase_complete, on_complete, on_escalate, on_cancel) are written to the bridge regardless of which channels are configured in notifications. See A2A — Real-time Visibility for details on what the calling agent receives.


Set up the Slack webhook in Integrations — Slack. Once configured, add "slack" to the channels array for each event you want.

on_start:

:rocket: cliq pipeline started (cliq-a1b2c3) Req: PROJ-123

on_phase_start:

:arrow_forward: Phase started: developer (standard) (cliq-a1b2c3) Req: PROJ-123

on_phase_complete:

:checkered_flag: Phase completed: developer — done (cliq-a1b2c3) Req: PROJ-123

on_complete:

:white_check_mark: cliq pipeline completed (cliq-a1b2c3) Req: PROJ-123

on_escalate:

:rotating_light: cliq escalation (cliq-a1b2c3)

Pipeline halted — human intervention required

Req: PROJ-123 Phase: reviewer Reason: Gate ‘reviewer’ exhausted its iteration budget (3 iterations)…

Run cliq run after fixing the issue.

on_cancel:

:stop_sign: cliq pipeline cancelled (cliq-a1b2c3) Req: PROJ-123 Reason: Pipeline cancelled by user (SIGINT)

on_pull (success):

:inbox_tray: Pull completed: research-docs from url (4096 bytes, 3 files) — (cliq-a1b2c3) Req: PROJ-123

on_pull (failure):

:x: Pull failed: research-docs from url (cliq-a1b2c3) Req: PROJ-123 Error: HTTP 403 Forbidden

on_push (success):

:outbox_tray: Push completed: report.md → gdoc://abc123 (mode: replace) — (cliq-a1b2c3) Req: PROJ-123 URL: https://docs.google.com/document/d/abc123

on_push (failure):

:x: Push failed: report.md → gdoc://abc123 (cliq-a1b2c3) Req: PROJ-123 Error: Content scanner blocked: API key detected


Set up Jira credentials in Integrations — Jira. Once configured, add "jira" to the channels array. Jira notifications only fire when the req source is a Jira ticket (e.g., cliq req -s jira:PROJ-123). Note: on_start is a no-op for Jira — the handler skips it since there’s nothing useful to post before work begins.

on_start — Skipped (no-op).

on_phase_start — Adds a comment:

cliq phase started: developer (standard) (cliq-a1b2c3).

on_phase_complete — Adds a comment:

cliq phase completed: developer — done (cliq-a1b2c3).

on_complete — Adds a comment:

cliq pipeline completed (cliq-a1b2c3).

All phases finished successfully.

on_escalate — Adds a comment with the failure reason, then transitions the ticket:

cliq escalation (cliq-a1b2c3)

Pipeline halted at phase ‘reviewer’. Human intervention required.

Reason: Gate ‘reviewer’ exhausted its iteration budget (3 iterations)…

Then transitions the ticket to the configured status (default: "Blocked").

on_cancel — Adds a comment:

cliq pipeline cancelled (cliq-a1b2c3).

Reason: Pipeline cancelled by user (SIGINT)

(Optional) Change the escalation transition

Section titled “(Optional) Change the escalation transition”

By default, escalation moves the ticket to “Blocked”. To change it:

{
"on_escalate": {
"channels": ["jira"],
"jira": { "transition_to": "Needs Review" }
}
}

The value must match an available transition name on your Jira board. If the transition doesn’t exist, the comment is still posted and a warning is logged listing the available transitions.


{
"integrations": {
"slack": {
"webhook_url": "https://hooks.slack.com/services/T.../B.../..."
}
},
"notifications": {
"on_start": { "channels": ["slack"] },
"on_phase_start": { "channels": ["slack"] },
"on_phase_complete": { "channels": ["slack"] },
"on_complete": { "channels": ["slack"] },
"on_escalate": { "channels": ["slack"] },
"on_cancel": { "channels": ["slack"] },
"on_pull": { "channels": ["slack"] },
"on_push": { "channels": ["slack"] }
}
}
{
"integrations": {
"jira": {
"base_url": "https://your-org.atlassian.net",
"email": "[email protected]",
"api_token": "your-api-token"
}
},
"notifications": {
"on_complete": { "channels": ["jira"] },
"on_escalate": { "channels": ["jira"] }
}
}

Combined — Slack for everything, Jira for key events

Section titled “Combined — Slack for everything, Jira for key events”
{
"integrations": {
"slack": {
"webhook_url": "https://hooks.slack.com/services/T.../B.../..."
},
"jira": {
"base_url": "https://your-org.atlassian.net",
"email": "[email protected]",
"api_token": "your-api-token"
}
},
"notifications": {
"on_start": { "channels": ["slack"] },
"on_phase_start": { "channels": ["slack"] },
"on_phase_complete": { "channels": ["slack", "jira"] },
"on_complete": { "channels": ["slack", "jira"] },
"on_escalate": {
"channels": ["slack", "jira"],
"slack": { "webhook_url": "https://hooks.slack.com/services/INCIDENT/HOOK" },
"jira": { "transition_to": "Blocked" }
},
"on_cancel": { "channels": ["slack"] }
}
}

Per-phase notifications — track phase progress

Section titled “Per-phase notifications — track phase progress”

If your workflow has many phases and you want granular Slack updates as each phase starts and finishes:

{
"notifications": {
"on_start": { "channels": ["slack"] },
"on_phase_start": { "channels": ["slack"] },
"on_phase_complete": { "channels": ["slack"] },
"on_complete": { "channels": ["slack", "jira"] },
"on_escalate": { "channels": ["slack", "jira"] },
"on_cancel": { "channels": ["slack"] }
}
}

This gives you a real-time Slack thread showing each phase entering and leaving execution — helpful for longer pipelines where you want to see progress without opening the dashboard.


Test your notification integrations before running a pipeline:

Terminal window
cliq doctor test slack # sends a test message to your webhook
cliq doctor test jira # verifies Jira authentication
cliq doctor test jira --ticket PROJ-123 # also verifies access to a specific ticket

IssueFix
”Notification (slack): failed — HTTP 403”The webhook URL is invalid or the Slack app was deleted. Regenerate the webhook in Slack. Run cliq doctor test slack to verify.
”Notification (jira): failed — HTTP 401”Jira credentials are wrong. Verify base_url, email, and api_token in integrations.jira. Run cliq doctor test jira to verify.
”Notification (jira): failed to fetch transitions”The Jira credentials are wrong, or the ticket doesn’t exist. Verify your credentials and run cliq doctor test jira to confirm.
”Notification (jira): transition ‘Blocked’ not available”The “Blocked” status doesn’t exist on your Jira board. Check which transitions are available and set transition_to accordingly. The log message lists the available transitions.
No notifications firing at allCheck that channels arrays are not empty and that integration credentials are set. Notifications read from .cliq/resolved_settings.json — if cliq run hasn’t been executed yet, this file won’t exist. Run cliq doctor test all to verify all integrations.
Phase events not appearingMake sure on_phase_start and/or on_phase_complete are configured in notifications. These events are opt-in — they don’t fire unless you add channels for them.
Jira comments not appearing for on_startThis is expected. The Jira handler skips on_start since there’s nothing to report before work begins. Use Slack for start notifications.