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.
Events
Section titled “Events”cliq fires six notification events across the pipeline lifecycle:
| Event | When it fires | Context available |
|---|---|---|
on_start | Pipeline begins execution | instance_id, req_key |
on_phase_start | A phase begins execution | instance_id, req_key, phase, phase_type |
on_phase_complete | A phase finishes | instance_id, req_key, phase, phase_type, outcome, iteration |
on_complete | All phases finish successfully | instance_id, req_key |
on_escalate | Pipeline halts — human intervention required | instance_id, req_key, phase, reason |
on_cancel | Pipeline cancelled by user (Ctrl-C, SIGTERM, SIGHUP) | instance_id, req_key, reason |
Event context
Section titled “Event context”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.
Channels
Section titled “Channels”All channel references use the format <type> or <type>:<name>. A bare <type> (e.g., "slack", "email") is syntactic sugar for <type>:default.
| Channel | What 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 |
jira | Adds a comment to the originating Jira ticket. On escalation, transitions the ticket to a configurable status |
Configuration
Section titled “Configuration”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.
Named channels
Section titled “Named channels”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.
Retry behavior
Section titled “Retry behavior”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.
A2A event bridge
Section titled “A2A event bridge”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.
Slack message examples
Section titled “Slack message examples”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 runafter 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.
Email subject lines
Section titled “Email subject lines”| Event | Subject |
|---|---|
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} |
Retry behavior
Section titled “Retry behavior”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.
Jira behavior per event
Section titled “Jira behavior per event”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)
Configuration examples
Section titled “Configuration examples”Slack-only — all events
Section titled “Slack-only — all events”{ "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"] } }}Jira-only — completion and escalation
Section titled “Jira-only — completion and escalation”{ "agents": { "jira": { "base_url": "https://your-org.atlassian.net", "api_token": "your-api-token" } }, "notifications": { "on_complete": { "channels": ["jira"] }, "on_escalate": { "channels": ["jira"] } }}Combined — Slack + Email + Jira
Section titled “Combined — Slack + Email + 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", "channels": { } }, "jira": { "base_url": "https://your-org.atlassian.net", "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.
Verification
Section titled “Verification”Test your notification integrations before running a pipeline:
cliq doctor agent slack # sends a test message to your webhookcliq doctor agent email # verifies SMTP connection and authcliq doctor agent jira # verifies Jira authenticationcliq doctor agent jira --ticket PROJ-123 # also verifies access to a specific ticketTroubleshooting
Section titled “Troubleshooting”| Issue | Fix |
|---|---|
| ”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 all | Check 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 appearing | Make 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_start | This is expected. The Jira handler skips on_start since there’s nothing to report before work begins. Use Slack for start notifications. |