Reminders and notifications

{ "uses": ["notifications"] }
await tinylib.reminders.set('evening', {
  title: 'Time to write',
  text: 'How was today?',
  repeat: tinylib.reminders.daily('18:00'),
  address: 'today',
})

reminders.set schedules a notification for the persona on each of their devices that receive notifications. It goes off at its time with the app closed, and a reminder set without a connection still goes off on that device. Each reminder has a name: setting a name again replaces that reminder, so two devices that set 'evening' end up with one. A tap on it opens the app at address, or the start screen for ''.

Once or repeating

await tinylib.reminders.set('dentist', { title: 'Dentist at 3', at: '2026-10-06T14:30' })
await tinylib.reminders.set('tea', { title: 'Tea is ready', at: tinylib.now() + 4 * 60_000 })
await tinylib.reminders.set('standup', { title: 'Standup', repeat: tinylib.reminders.weekly(['mon', 'tue', 'wed', 'thu', 'fri'], '09:30') })

at is a local date and time, or a time on Tinylib's clock. repeat comes from daily, weekly or monthly and starts at the next matching time. A reminder keeps the time zone it was set in, across travel and clock changes; list() gives it as timeZone. On the web, a reminder goes off without a connection only while Tinylib is open.

The notifications switch

offNotice.hidden = tinylib.persona.notificationsOn
turnOn.onclick = () => tinylib.persona.edit('notifications')

try {
  await tinylib.reminders.set('evening', evening)
} catch (error) {
  if (error.code === 'notifications_off') offNotice.hidden = false
  else toast(error.message)
}

Only the person changes the app's notifications switch. The app reads notificationsOn, and persona.edit('notifications') opens Tinylib's card for it. Setting a reminder with the switch off asks the person to turn it on; left off, the reminder isn't set and set rejects with notifications_off.

Turned back on

tinylib.persona.onChange(async () => {
  if (!tinylib.persona.notificationsOn) return
  const reminders = await tinylib.reminders.list()
  if (!reminders.some((reminder) => reminder.name === 'evening')) await tinylib.reminders.set('evening', evening)
})

Turning the switch off cancels every waiting reminder of the app, on every device. When it's back on, the app sets them again.

Notifications from a room

// rules.js
ctx.notify(next, 'Your turn', `${input.from.name} played.`)
ctx.status(next, 'Your turn', true)

ctx.notify reaches a member's devices only when they don't have the room open; Tinylib applies that. A notification stacks, and a status replaces the last one, so whose turn it is goes in the status, and an event, such as a move made, goes in a notification. Both follow the persona's notifications switch, and notify needs "notifications" in uses.