8000 feat(notifications): per-namespace notifications to Matterbridge and webhooks by adeelahmad · Pull Request #16 · adeelahmad/lense · GitHub
[go: up one dir, main page]

Skip to content

feat(notifications): per-namespace notifications to Matterbridge and webhooks - #16

Merged
adeelahmad merged 4 commits into
mainfrom
claude/notifications-webhooks-tqjjrw
Oct 2, 2026
Merged

adeelahmad merged 4 commits into
mainfrom
claude/notifications-webhooks-tqjjrw

Conversation

@adeelahmad
Copy link
Copy Markdown
Owner

Requested by Adeel · project thread

Description

Before: Lens told nobody when a run finished or failed; you had to look at Activity.

After: a namespace's owners add notification targets on the namespace's page (Notifications). Each target picks its events (a run finished, failed or was cancelled; a batch run finished; something was added), can be sent a test, and lists what it was sent.

Targets:

  • Matterbridge (42wim's chat relay): POST /api/message with gateway, username and optional bearer token, reaching Slack, Discord, Matrix, Telegram, IRC and the rest.
  • Webhook: Lens JSON signed with Standard Webhooks (webhook-id, webhook-timestamp, webhook-signature), with a secret shown once that can be rotated.
  • Slack-style ({"text"}) and Discord ({"content"}) incoming webhooks.

How: nothing in the existing code calls into notifications. A notifier thread (app/domain/notify.py) runs wherever background work runs (inline workers in the API process, lens worker). It reads runs that ended (job.finished_at) and recordings added (recording.created_at) since its last look, with a 60 s lookback. Each event is claimed once across processes through a CREATE notify_event:<hash> that only one process can win. Events are then queued per target in notify_delivery, claimed per send, and retried with backoff: 30 s, then ×4 each time, capped at 6 h, up to notifications.max_attempts. A 4xx response other than 408, 425 or 429 is not retried. A batch run's jobs go out as one batch.finished message, and more than 5 additions in one look go out as one message.

Security: target URLs, secrets and tokens are sealed with the server key, and the API returns only scheme://host. Targets can reach public addresses only, unless an admin lists private networks in notifications.networks. The notifier resolves the host itself, checks every address, connects to the address it checked (with SNI and certificate checks against the hostname), and doesn't follow redirects.

Admin settings (Settings → Notifications): enabled, networks, app_url (for links; defaults to FRONTEND_URL), poll_seconds, max_attempts.

API: GET/POST /api/v1/namespaces/{name}/notifications, PATCH/DELETE …/{tid}, POST …/{tid}/test, POST …/{tid}/secret, GET …/{tid}/deliveries. These are for owners and are audited.

Motivation and Context

Requested in the project thread: Matterbridge and webhook support for notifications.

Screenshots (if appropriate):

Checked in a local run of the app: the namespace's panel listing targets and test results, the New target dialog, the Sent log and the admin settings section all render. A test to a fake Matterbridge answered 200.

Steps to reproduce (if appropriate):

  1. As an admin, allow your Matterbridge's network in Settings → Notifications (for example 172.16.0.0/12 for Docker).
  2. On a namespace's page, open Notifications, click New target, choose Matterbridge, enter http://matterbridge:4242 and gateway lens, then click Test.
  3. Run something in that namespace and watch the message arrive.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • My code follows the code style of this project.
  • My change requires documentation updates.
  • I have updated the documentation accordingly (docs/notifications.md, docs/api.md, docs/configuration.md, CHANGELOG).
  • My change requires dependencies updates.
  • I have updated the dependencies accordingly.

Tests: tests/api/test_notifications.py has 6 tests, all run against local HTTP servers: signing checked against the spec, the private-address refusal, sending once across two "processes", retry and refusal, and grouping. ruff, mypy, tsc, eslint and prettier are clean. In the full backend suite, 1 test fails: test_conversion.py::test_office_and_text_files_become_documents. LibreOffice can't read the .docx in this container, and the test doesn't touch this change.

🤖 Generated with Claude Code

https://claude.ai/code/session_01PqBe9ycLaqFLZvCqL5wprK


Generated by Claude Code

Owners pick targets (Matterbridge API, signed Standard Webhooks JSON, Slack-style
and Discord webhooks) and events (runs finished/failed/cancelled, batch runs
finished, things added). A notifier in every background process reads what
changed, claims each event once, queues it per target and retries with backoff.
Targets reach public addresses unless an admin allows a private network.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PqBe9ycLaqFLZvCqL5wprK
@adeelahmad adeelahmad self-assigned this Oct 2, 2026
claude added 3 commits October 2, 2026 12:45
The first look marks a floor; rows in that same second could predate it (CI saw
the test's seeded recordings sent), so the floor is exclusive.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PqBe9ycLaqFLZvCqL5wprK
…ap a send

- Each source is read from a (time, id) cursor a page at a time; only a caught-up
  look reads the last minute again, so more than a page of events no longer
  freezes the notifier.
- Claiming an event and queueing its deliveries is one transaction; only an
  existing claim counts as someone else's, and the cache learns after the fact.
- A send gets 30 s in all (a trickling answer is cut off), well inside the
  5-minute reclaim; a round stops sending after a minute to look for news.
- A batch run's counts are per namespace.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PqBe9ycLaqFLZvCqL5wprK
Regenerated openapi.json and the API client from the merged backend.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SNbRrpHTCqLewRKdkmd45X
@adeelahmad adeelahmad changed the title Notifications to Matterbridge and webhooks, per namespace feat(notifications): per-namespace notifications to Matterbridge and webhooks Oct 2, 2026
@adeelahmad
adeelahmad marked this pull request as ready for review October 2, 2026 13:27
@adeelahmad
adeelahmad merged commit 81a6cdb into main Oct 2, 2026
1 of 11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

0