Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
d867993
feat(notifications): add triageable notification inbox
hmans Aug 10, 2026
df6a3c1
fix(notifications): simplify inbox triage controls
hmans Aug 10, 2026
7d13664
test(notifications): align triage e2e expectations
hmans Aug 10, 2026
04c393c
refactor(notifications): isolate occurrence planning events
hmans Aug 11, 2026
0833a4d
docs(agent): restrict new EVT event types
hmans Aug 11, 2026
51ecc34
Merge remote-tracking branch 'origin/main' into hmans/notifications-2…
hmans Aug 11, 2026
666fbe1
fix(notifications): move materialization work out of EVT
hmans Aug 11, 2026
4a4d473
refactor(notifications): reduce v2 API surface
hmans Aug 11, 2026
b28c838
Merge remote-tracking branch 'origin/main' into hmans/notifications-2…
hmans Aug 11, 2026
de10eae
fix(notifications): harden durable materialization
hmans Aug 11, 2026
2d01838
Merge remote-tracking branch 'origin/main' into hmans/notifications-2…
hmans Aug 11, 2026
a09235f
feat(notifications)!: replace notifications 1.0
hmans Aug 11, 2026
1a3a37c
Merge remote-tracking branch 'origin/main' into hmans/notifications-2…
hmans Aug 11, 2026
9bac961
fix(notifications): harden v2 triage and delivery
hmans Aug 11, 2026
a8a0ab6
Merge remote-tracking branch 'origin/main' into hmans/notifications-2…
hmans Aug 11, 2026
5493722
fix(notifications): close final review gaps
hmans Aug 11, 2026
0fcdb2d
Merge remote-tracking branch 'origin/main' into hmans/notifications-2…
hmans Aug 11, 2026
870a062
fix(notifications): fence target visibility checks
hmans Aug 11, 2026
ddcf62a
fix(notifications): bound visibility validation
hmans Aug 11, 2026
da9a0e5
fix(notifications): fence exhaustive inbox summaries
hmans Aug 11, 2026
00b71e8
fix(notifications): fence replica indexes
hmans Aug 11, 2026
fe2a33d
fix(notifications): reconcile implicit visibility loss
hmans Aug 11, 2026
ff39601
fix(notifications): reconcile visibility at event boundary
hmans Aug 11, 2026
c0b4a2f
fix(notifications): checkpoint visibility boundaries
hmans Aug 11, 2026
bf3e2ef
fix(notifications): retain recoverable visibility boundaries
hmans Aug 11, 2026
50cdcc0
fix(auth): fence configured owner materialization
hmans Aug 11, 2026
857c753
fix(notifications): preserve safe visibility snapshots
hmans Aug 11, 2026
4ae1d9f
fix(notifications): align snapshot publication floor
hmans Aug 11, 2026
2cee3f4
fix(notifications): reconstruct safe restart floor
hmans Aug 11, 2026
b4b4ac1
fix(notifications): isolate worker tail reads
hmans Aug 11, 2026
f5c9e73
chore: merge origin/main into notifications 2.0
hmans Aug 11, 2026
3b58f44
Merge remote-tracking branch 'origin/main' into hmans/notifications-2…
hmans Aug 11, 2026
acfe40c
fix(notifications): address inbox review findings
hmans Aug 11, 2026
9b3e951
Merge remote-tracking branch 'origin/main' into hmans/notifications-2…
hmans Aug 11, 2026
4e33789
fix(notifications): fence policy and triage mutations
hmans Aug 11, 2026
d4e83f6
fix(frontend): streamline notification interactions
hmans Aug 11, 2026
c86cf13
fix(notifications): simplify notification attention state
hmans Aug 11, 2026
598e39c
feat(notifications): improve list triage
hmans Aug 11, 2026
c79e267
test(frontend): update notification E2E summaries
hmans Aug 11, 2026
0eba6ae
Merge remote-tracking branch 'origin/main' into hmans/notifications-2…
hmans Aug 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 23 additions & 9 deletions .agents/skills/chatto-event-sourcing/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ Authoritative code anchors:
## Core Rules

- Durable domain facts go into `EVT`. Do not add durable mirrors in KV or object metadata unless the architecture explicitly calls the state runtime, ephemeral, secret, binary, or cache data.
- Treat every new `EVT` event type as a last resort. It must record an
authoritative fact that changes durable domain state, not implementation
bookkeeping, an invalidation, a work item, or an outbox/recovery trigger.
First exhaust existing domain facts, projections, `RUNTIME_STATE`, transient
live sync, reconciliation, and an explicitly acceptable best-effort effect.
If a new event is still necessary, document why those alternatives cannot
preserve the required domain behavior.
- Domain state interactions should go through a Service for that domain. Avoid direct JetStream, KV, object-store, or projection manipulation from unrelated code.
- `ChattoCore` is a facade and wiring point. Prefer moving domain-specific write/readiness logic into a focused Service.
- Projections are process-local read models rebuilt from `EVT`. They are not locks, coordination points, or sources of durable truth.
Expand Down Expand Up @@ -61,15 +68,17 @@ For a hot, high-fanout `RUNTIME_STATE` or `MEMORY_CACHE` read path:
Answer these questions before editing:

1. Is this a durable domain fact, runtime state, transient live sync, binary/object data, a secret, or a cache?
2. Which Service owns the domain? If none exists, should this change introduce one?
3. Which aggregate owns the event subject?
4. What invariant does the OCC filter protect?
5. Which projections must consume the event?
6. Which projections must be current before the mutation returns?
7. Does the write need to publish transient `LiveEvent`s, or will `EVT` republish through `live.evt.>` be enough?
8. What happens with multiple replicas racing the same write?
9. What happens on forward deploy, mixed-version rolling deploy, and rollback?
10. Which focused tests lock down the subject, replay, OCC, projection, and delivery behavior?
2. If this proposes a new `EVT` event, what durable domain state changes, and
why can no existing fact or non-EVT mechanism represent the requirement?
3. Which Service owns the domain? If none exists, should this change introduce one?
4. Which aggregate owns the event subject?
5. What invariant does the OCC filter protect?
6. Which projections must consume the event?
7. Which projections must be current before the mutation returns?
8. Does the write need to publish transient `LiveEvent`s, or will `EVT` republish through `live.evt.>` be enough?
9. What happens with multiple replicas racing the same write?
10. What happens on forward deploy, mixed-version rolling deploy, and rollback?
11. Which focused tests lock down the subject, replay, OCC, projection, and delivery behavior?

## Choosing An Aggregate Subject

Expand Down Expand Up @@ -188,6 +197,11 @@ Check:
Treat the interval between an EVT commit and completion of any KMS, LiveKit,
object-store, webhook, or other external side effect as a crash boundary.

- Recovery requirements alone do not justify a new event type. Recover work
from the existing domain-changing fact whenever possible. If no such fact
exists, decide explicitly whether the effect belongs in `RUNTIME_STATE`, can
be reconciled from current authority, or may remain best-effort before
proposing another `EVT` fact.
- External side effects required by a committed fact must be retryable from
durable state after process restart and lease-holder turnover.
- A process-local retry queue may reduce recovery latency, but must not be the
Expand Down
1 change: 0 additions & 1 deletion apps/docs-website/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,6 @@ export default defineConfig({
"reference/connectrpc-api/messages",
"reference/connectrpc-api/message-search",
"reference/connectrpc-api/account",
"reference/connectrpc-api/notification-preferences",
"reference/connectrpc-api/notifications",
"reference/connectrpc-api/push-notifications",
"reference/connectrpc-api/roles",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,33 @@ Chatto creates persistent notifications for attention-worthy events:
| Role, `@all`, and `@here` mentions | Notify matching recipients, with confirmation for broad sends. |
| Replies to your message | Notify you. |
| Followed thread replies | Notify followers. |
| Rooms set to all messages | Notify for every root message in that room. |
| Followed room activity | Notify according to the followed-room policy. |
| Reactions to your messages | Add a non-interruptive notification by default. |

Notifications are stored for the user, survive browser restarts, sync across tabs and devices, and expire after 90 days. Dismissing a notification clears it everywhere for that user.
Notifications are stored for the user, survive browser restarts, sync across tabs and devices, and expire after 90 days. Read and Delete changes synchronize everywhere for that user.

## Notification Levels
## Notification Centre

Members can choose notification levels per room:
The notification centre shows one chronological list:

| Level | Effect |
| ----- | ------ |
| Default | Inherit the parent/default behavior. |
| Muted | Suppress notifications and unread sidebar state for that room. |
| Normal | Notify for mentions, DMs, and thread replies. |
| All messages | Notify for mentions, DMs, thread replies, and every root message. |
- Unread and read notifications use the normal treatment until you mark or delete them.
- Read notifications stay in the same chronological list without unread emphasis. The trash action permanently dismisses a notification without requiring you to open it.
- Delete permanently removes a notification from the list.

Muted rooms suppress mentions too. Treat mute as "leave this room out of my attention surface."
Related activity is grouped by DM, room, thread, or reacted-to message. Opening a group goes to its newest unread event, or its newest event when everything in the group is read. Reading a room or thread marks covered notifications read. All notifications expire 90 days after their source activity.

## Notification Policy

Members control each notification cause independently at server level and, where useful, per room:

| Intensity | Effect |
| --------- | ------ |
| Inherit | Use the next broader server or product default. |
| Off | Do not create a notification for this cause. |
| Badge | Add it to the notification list and badge counts without sound or Web Push. |
| Alert | Add it to the notification list and allow sound and Web Push. |

Direct messages, direct mentions, replies, role mentions, `@here`, and `@all` alert by default. Followed threads and reactions use Badge by default; followed rooms are Off until enabled. A message that matches several causes creates one notification using the strongest effective intensity. Notification policy affects future activity and does not hide ordinary unread room state.

## Do Not Disturb

Expand Down Expand Up @@ -85,11 +96,11 @@ Use a `mailto:` or HTTPS contact URI for `vapid_subject`. Keep the private key s

## Device Behavior

Each browser or installed PWA creates its own subscription. A user can have multiple subscribed devices, and each device receives the same push notification.
Each browser or installed PWA creates its own subscription. Chatto attempts every current device for each push. Once any device accepts a notification, Chatto does not retry the complete device set merely because another endpoint failed; this avoids repeatedly alerting healthy devices.

When a user reopens Chatto, the app refreshes the server's stored subscription for that browser. Expired subscriptions are cleaned up automatically when push providers report them as gone.

Chatto sends regular notifications in a declarative-compatible Web Push format, with browser-managed display and app-badge updates where supported. User-visible pushes request high-urgency delivery so mobile push services can wake sleeping devices promptly; silent cross-device dismissal updates remain normal urgency. Its service worker preserves notification display and click compatibility and updates a closed app's badge after cross-device dismissals. Operators do not need to change VAPID keys or push configuration for this behavior.
Chatto sends regular notifications in a declarative-compatible Web Push format, with browser-managed display and app-badge updates where supported. User-visible pushes request high-urgency delivery so mobile push services can wake sleeping devices promptly. Its service worker preserves notification display and click compatibility for browsers that do not handle the declarative payload directly. Read and delete actions synchronize inside Chatto; they do not attempt to retract an OS notification that a browser already displayed. Operators do not need to change VAPID keys or push configuration for this behavior.

On iOS and iPadOS, Web Push works only for supported Home Screen web apps. Safari tabs that are not installed as an app may not receive native push.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,7 @@ Use the service pages below for request and response fields. Shared messages and
- [MessageService](/reference/connectrpc-api/messages/) - Message creation, editing, deletion, composer link-preview, reaction, and attachment RPCs.
- [MessageSearchService](/reference/connectrpc-api/message-search/) - Authorized full-text message search and provider availability RPCs.
- [MyAccountService](/reference/connectrpc-api/account/) - Self-service account, profile, avatar, presence, status, external identity, and settings RPCs for the authenticated user.
- [NotificationPreferencesService](/reference/connectrpc-api/notification-preferences/) - Server and room notification preference RPCs.
- [NotificationService](/reference/connectrpc-api/notifications/) - Notification listing, counts, checks, and dismissal RPCs.
- [NotificationService](/reference/connectrpc-api/notifications/) - Grouped notification listing, read, deletion, and per-cause policy RPCs.
- [PushNotificationService](/reference/connectrpc-api/push-notifications/) - Web Push subscription RPCs.
- [RoleService](/reference/connectrpc-api/roles/) - Authenticated role catalog read RPCs.
- [RoomDirectoryService](/reference/connectrpc-api/room-directory/) - Room navigation, room group, and room viewer-state RPCs.
Expand Down

This file was deleted.

Loading
Loading