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.

Three channels are supported out of the box: Slack (via Incoming Webhooks), Email (via SMTP), 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 six 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

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.


All channel references use the format <type> or <type>:<name>. A bare <type> (e.g., "slack", "email") is syntactic sugar for <type>:default.

ChannelWhat it does
slack or slack:<name>Posts a formatted message via Incoming Webhook to the named channel
email or email:<name>Sends an HTML + plain text email to the named channel’s recipient list
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, Email, and Jira credentials first — see each agent’s setup guide.

{
"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.

Route different events to different destinations using named channels. Define channels in agents.slack.channels and agents.email.channels, then reference them with <type>:<name> syntax:

{
"notifications": {
"on_start": { "channels": ["slack"] },
"on_complete": { "channels": ["slack", "email", "jira"] },
"on_escalate": {
"channels": ["slack:incidents", "email:ops", "jira"]
}
}
}

In this example, escalation goes to the incidents Slack channel and ops email list, while other events use the default channels.


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 Slack Agent. 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)


Set up SMTP credentials in Email Agent. Once configured, add "email" (or "email:<name>") to the channels array.

Email notifications include both HTML and plain text. The HTML version uses inline styles for broad client compatibility (Gmail, Outlook, Apple Mail). Each event type has a colored header bar (blue for start, green for complete, red for escalation/failure, gray for cancel) and a key-value metadata table.

EventSubject
on_start[cliq] Pipeline started — {team}
on_phase_start[cliq] Phase started: {phase} — {team}
on_phase_complete[cliq] Phase completed: {phase} — {team}
on_complete[cliq] Pipeline completed — {team}
on_escalate[cliq] Escalation — {team}
on_cancel[cliq] Pipeline cancelled — {team}

Email delivery retries up to 3 times with exponential backoff (1 s, 3 s, 9 s) on transient SMTP errors (connection timeouts, 4xx responses). Permanent failures (SMTP 5xx, authentication errors) are not retried.


Set up Jira credentials in Jira Agent. Once configured, add "jira" to the channels array. Jira notifications only fire when the req source is a Jira ticket (e.g., cliq req --input ticket=PROJ-123 with a Jira agent phase). 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)


{
"agents": {
"slack": {
"channels": {
"default": { "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"] }
}
}
{
"agents": {
"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"] }
}
}
{
"agents": {
"slack": {
"channels": {
"default": { "webhook_url": "https://hooks.slack.com/services/T.../B.../..." },
"incidents": { "webhook_url": "https://hooks.slack.com/services/INCIDENT/HOOK" }
}
},
"email": {
"smtp_host": "smtp.example.com",
"from_address": "[email protected]",
"channels": {
"default": ["[email protected]"],
}
},
"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", "email", "jira"] },
"on_escalate": {
"channels": ["slack:incidents", "email:ops", "jira"]
},
"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 agent slack # sends a test message to your webhook
cliq doctor agent email # verifies SMTP connection and auth
cliq doctor agent email --send-to [email protected] # also sends a test email
cliq doctor agent jira # verifies Jira authentication
cliq doctor agent 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 agent slack to verify.
”Notification (jira): failed — HTTP 401”Jira credentials are wrong. Verify base_url, email, and api_token in agents.jira. Run cliq doctor agent 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 agent 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.
”Notification (email): agents.email.smtp_host not configured — skipped.”SMTP settings are missing. Set agents.email.smtp_host and related fields in your global settings.
”Notification (email): failed — …”SMTP delivery failed. Check credentials, hostname, port, and TLS settings. Common causes: wrong port (use 587 for STARTTLS, 465 for implicit TLS), incorrect username/password, or firewall blocking outbound SMTP.
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 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.