Engineering report - AO notifications - issue 1579

AO Notifications System - Implementation Report

How AO notifications moved from simple provider messages to semantic events routed across dashboard, desktop, Slack, Discord, Composio, Gmail, webhooks, and OpenClaw.

Date: 2026-05-14 Reading time: 12 min Branch: feat/issue-1579 Scope: notification delivery system

Executive Summary

AO already had lifecycle events, but the notification layer was still too manual and too provider-specific. This branch turns notifications into a real platform: structured payloads, setup commands, routing policy, test tooling, dashboard history, desktop-native delivery, and rich provider rendering.

The core shift is simple: AO no longer just sends a string. It emits a semantic event. Every notifier can then render that event in a way that makes sense for its destination.

Payload model
v3
Structured subject, CI, review, merge, reaction, and escalation data.
Setup surface
9+
Dashboard, desktop, webhook, Slack, Discord, Composio, Gmail, OpenClaw.
Dashboard retention
50
Default latest-notification window, configurable up to 500.
Delivery policy
3
Routing presets: urgent-only, urgent-action, and all.

The Problem

Notifications were useful, but not yet reliable as a system. Setup required too much YAML editing. Testing real providers was awkward. Slack, Discord, email, desktop, and local dashboard surfaces all needed different formats, but they were not sharing one consistent event model.

The result was predictable: every provider could drift, every setup path could fail differently, and users had no single way to verify whether AO would alert them at the right place.

Area Before Now
Payloads Mostly flat event data and provider-side interpretation. Notification data schema v3 with semantic fields.
Setup Manual YAML and provider-specific knowledge. Interactive setup commands with validation, status, refresh, and routing.
Testing Hard to test without triggering real lifecycle work. ao notify test sends deterministic demo notifications.
Dashboard No first-class notification center. Bell UI with retained notifications, unread state, and links.
Desktop Basic OS notifications and platform gaps. AO Notifier app, fallback backends, grouping, badge support, and actions.

Architecture

The architecture centers on one normalized notification object. AO lifecycle code builds semantic data once. The routing layer chooses destinations by priority. Each notifier renders the same event according to its destination.

1

Lifecycle event

AO detects a session, PR, CI, review, merge, reaction, or escalation transition.

2

Semantic payload

Core builds notification data v3 with stable, nested fields.

3

Routing policy

Priority maps to configured notifiers or explicit routing presets.

4

Provider render

Slack, Discord, Gmail, desktop, dashboard, and others format the same event.

5

User action

The notification links back to sessions, PRs, reviews, dashboards, or actions.

Core Notification Data

The v3 payload gives every provider the same vocabulary. Instead of guessing from strings, a notifier can inspect subject.pr, ci.status, review.decision, merge.ready, transition, and escalation.

{
  "schemaVersion": 3,
  "semanticType": "merge.ready",
  "subject": {
    "session": { "id": "demo-agent-29", "projectId": "demo" },
    "pr": { "number": 1579, "url": "...", "branch": "feat/issue-1579" }
  },
  "transition": { "kind": "session_status", "from": "approved", "to": "mergeable" },
  "ci": { "status": "passing" },
  "review": { "decision": "approved" },
  "merge": { "ready": true, "conflicts": false, "isBehind": false }
}

This makes the providers cleaner. It also makes the notification payload easier to test because the event shape is explicit and versioned.

Setup And Testing

A

Interactive setup commands

Setup now exists for dashboard, desktop, webhook, Slack, Discord, Composio, Composio Slack, Composio Discord webhook, Composio Discord bot, Composio Gmail, and OpenClaw.

These flows ask for the right inputs, explain where to get provider credentials, support refresh/status modes, and write the final YAML only after the flow has enough information.

B

Routing presets

Notifier routing moved from ad hoc list editing to explicit presets: urgent-only, urgent-action, and all.

That makes notification policy readable. Users can decide which destinations get high-signal alerts and which destinations receive the full stream.

C

Manual smoke tests

ao notify test can send a real demo notification without spawning an agent. It supports templates, target selection, routes, actions, JSON output, dry runs, and a local sink.

This became the fast path for validating every notifier one by one.

Dashboard Notifications

The dashboard is now a notification destination, not just a place to inspect sessions. AO can write dashboard notifications to a config-scoped JSONL store. The web mux server reads that store and streams snapshots and appends to the browser over the existing WebSocket path.

Storage
Config-scoped dashboard-notifications.jsonl under the AO observability directory.
Retention
Default latest 50 records, configurable and clamped to a safe maximum.
Streaming
Mux notification subscription sends an immediate snapshot, then appends new records.
UI
Bell button, unread count, All/Unread tabs, mark read/unread, and links to session, PR, review, and non-redundant actions.

Desktop Notifications

The desktop path now has a native macOS helper app plus fallbacks. The AO Notifier app can request permission, send native notifications, group delivered notifications, maintain a badge count, expose delivered state, and handle URL or callback actions.

When the app is not installed, the plugin can fall back to terminal-notifier, then osascript on macOS. Linux still uses notify-send.

External Integrations

Slack rich blocks

Native Slack now sends professional Block Kit messages with semantic colors, fields, status context, PR/review links, and action buttons.

Discord embeds

Native Discord now sends embeds with provider-safe formatting, colors by priority, PR/CI/review/merge fields, retry behavior, and no broad mentions.

Composio multi-app

Composio now supports Slack, Discord webhook, Discord bot, and Gmail modes through setup flows and app-specific execution arguments.

Gmail HTML mail

Email notifications now render as HTML messages instead of raw HTML text, with clear headings, details, status blocks, and action links.

OpenClaw local gateway

OpenClaw gets structured AO briefs, config-token discovery, retries, status probes, and health summaries without mutating the OpenClaw side.

Webhook generic sink

The generic webhook notifier remains the plain integration point, now supported by setup, validation, headers, retries, and the test sink.

What Is Right Now

The branch is pushed and clean except for local untracked experiment files. The current implementation covers the full notifier system surface: payload creation, provider rendering, setup, manual tests, dashboard delivery, and desktop delivery.

The practical status is: the feature is built and provider smoke tests have been exercised manually, but the branch should still be rebased or merged with the current main branch before final CI.

Track Status Notes
Feature branch Implemented feat/issue-1579 contains the notification system work.
Dashboard Implemented JSONL retention, mux streaming, bell UI, unread state, and semantic links.
Desktop Implemented AO Notifier app, fallback backends, badge grouping, icon update, and richer messages.
Provider rendering Implemented Slack, Discord, Composio, Gmail, OpenClaw, webhook, and desktop updated.
Final CI Pending Needs latest main integrated and stale integration expectations refreshed.

Risks And Caveats

Detailed Changelog

Core notification model
  • Added notification data schema v3.
  • Added builders for session transitions, PR state transitions, CI failures, reaction events, and escalations.
  • Lifecycle manager now emits semantic notification data.
  • Notifier interface supports action-capable delivery through notifyWithActions.
CLI setup and testing
  • Added ao notify test with templates for basic, agent stuck, needs input, CI failing, review changes requested, approved and green, merge ready, all complete, and PR closed.
  • Added interactive setup flows for desktop, dashboard, webhook, Slack, Discord, Composio variants, Gmail, and OpenClaw.
  • Added routing presets and status/refresh paths where needed.
  • Extended doctor checks to resolve notifier plugins and optionally send test notifications.
Dashboard notification center
  • Added dashboard notifier plugin.
  • Added config-scoped JSONL notification retention.
  • Added mux notification subscription for snapshots and appends.
  • Added bell UI with unread badge, All/Unread tabs, mark read/unread, mark all, and session/PR/review links.
  • Filtered redundant dashboard and duplicate PR/review action links from cards.
Provider rendering
  • Slack now renders Block Kit style messages with status fields and action buttons.
  • Discord now renders embeds with semantic colors, fields, links, and retry handling.
  • Composio supports Slack, Discord webhook, Discord bot, and Gmail modes.
  • Gmail sends HTML notifications.
  • OpenClaw sends structured AO briefs and records delivery health.
  • Webhook remains the generic JSON destination with setup and retry support.
Desktop notifier
  • Added native AO Notifier macOS helper app.
  • Added permission checks, notification grouping, badge count, delivered-state commands, URL actions, and callback actions.
  • Improved desktop message titles, subtitles, body structure, and action formatting.
  • Added app icon generation from the new AO icon asset.
  • Kept fallback behavior for terminal-notifier, osascript, and Linux notify-send.

Actual Things We Did

  • Added semantic notification payloads v3.
  • Added notification payload builders in core.
  • Updated lifecycle notifications to emit structured data.
  • Added the dashboard notifier plugin.
  • Added dashboard notification JSONL retention.
  • Added notification streaming over the mux WebSocket.
  • Added the dashboard notification bell.
  • Added unread count, All/Unread tabs, and read/unread controls.
  • Added links from notifications to sessions, PRs, and reviews.
  • Removed redundant dashboard and PR action buttons from dashboard cards.
  • Added ao notify test.
  • Added demo templates for common notification types.
  • Added local sink support for testing webhook payloads.
  • Added notifier routing presets.
  • Added ao setup dashboard.
  • Added ao setup desktop.
  • Added ao setup webhook.
  • Added ao setup slack.
  • Added ao setup discord.
  • Added the interactive Composio setup hub.
  • Added dedicated Composio Slack setup.
  • Added Composio Discord webhook setup.
  • Added Composio Discord bot setup.
  • Added Composio Gmail setup.
  • Added OpenClaw setup and status behavior.
  • Updated native Slack messages to rich blocks.
  • Updated native Discord messages to rich embeds.
  • Updated Composio Slack formatting.
  • Updated Composio Discord webhook and bot formatting.
  • Updated Composio Gmail to send HTML email.
  • Updated OpenClaw messages to structured AO briefs.
  • Added OpenClaw delivery health summary.
  • Added the native macOS AO Notifier app.
  • Added desktop notification grouping and badge behavior.
  • Added desktop notification action handling.
  • Added a custom AO Notifier app icon.
  • Updated tests for core, CLI, dashboard, web mux, and notifier plugins.
  • Updated notifier documentation.
  • Manually smoke-tested notifications across configured providers.