notification-scheduler
Configure and manage scheduled dose reminders using node-cron and Web Notifications API. Use when building or debugging notification delivery in medication or health tracking apps.
Best use case
notification-scheduler is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Configure and manage scheduled dose reminders using node-cron and Web Notifications API. Use when building or debugging notification delivery in medication or health tracking apps.
Teams using notification-scheduler should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/notification-scheduler/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How notification-scheduler Compares
| Feature / Agent | notification-scheduler | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Configure and manage scheduled dose reminders using node-cron and Web Notifications API. Use when building or debugging notification delivery in medication or health tracking apps.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# notification-scheduler
Server-side cron scheduling combined with client-side Web Notifications API for medication reminders.
## Architecture
Two-layer delivery:
1. Server: node-cron fires at each scheduled dose time, emits WebSocket event
2. Client: receives WebSocket event, shows browser notification via Notifications API
## Server setup (node-cron)
```typescript
import cron from 'node-cron';
import { WebSocketServer } from 'ws';
interface ScheduledJob {
taskId: string;
medicationId: number;
scheduledTime: string; // "HH:MM"
task: cron.ScheduledTask;
}
const jobs = new Map<string, ScheduledJob>();
function scheduleReminder(medicationId: number, time: string, leadMins: number): void {
const [hour, minute] = time.split(':').map(Number);
const reminderMin = minute - leadMins;
// Adjust hour if minutes go negative
const cronMin = ((reminderMin % 60) + 60) % 60;
const cronHour = hour + (reminderMin < 0 ? -1 : 0);
const expression = `${cronMin} ${cronHour} * * *`;
const task = cron.schedule(expression, () => {
broadcast({ type: 'dose_reminder', medicationId, scheduledTime: time });
});
const key = `${medicationId}-${time}`;
jobs.set(key, { taskId: key, medicationId, scheduledTime: time, task });
}
function broadcast(data: object): void {
const message = JSON.stringify(data);
wss.clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send(message);
}
});
}
```
## Client setup (Web Notifications API)
```typescript
// src/client/src/lib/notifications.ts
export async function requestPermission(): Promise<boolean> {
if (!('Notification' in window)) return false;
if (Notification.permission === 'granted') return true;
if (Notification.permission === 'denied') return false;
const result = await Notification.requestPermission();
return result === 'granted';
}
export function showDoseReminder(medicationName: string, scheduledTime: string): void {
if (Notification.permission !== 'granted') return;
const n = new Notification('Dose reminder', {
body: `Time to take ${medicationName} (scheduled ${scheduledTime})`,
icon: '/icon.png',
tag: `dose-${medicationName}-${scheduledTime}`,
requireInteraction: false,
});
n.onclick = () => {
window.focus();
n.close();
};
}
export function connectReminders(onReminder: (medicationId: number, time: string) => void): WebSocket {
const ws = new WebSocket(`ws://${window.location.host}/ws`);
ws.onmessage = (event) => {
const data = JSON.parse(event.data as string) as {
type: string;
medicationId: number;
scheduledTime: string;
};
if (data.type === 'dose_reminder') {
onReminder(data.medicationId, data.scheduledTime);
}
};
return ws;
}
```
## React integration
```typescript
// In App.tsx or a top-level hook
import { useEffect } from 'react';
import { requestPermission, showDoseReminder, connectReminders } from './lib/notifications';
function useNotifications(medications: Medication[]) {
useEffect(() => {
requestPermission();
const ws = connectReminders((medicationId, time) => {
const med = medications.find((m) => m.id === medicationId);
if (med) showDoseReminder(med.name, time);
});
return () => ws.close();
}, [medications]);
}
```
## Scheduling on app startup
When the server starts, load all active schedule_times from SQLite and call `scheduleReminder` for each. When a medication is added, updated, or deleted, cancel existing jobs for that medication and reschedule.
```typescript
async function initScheduler(db: Database, leadMins: number): Promise<void> {
const times = db.prepare(
'SELECT st.medication_id, st.time_of_day FROM schedule_times st JOIN medications m ON m.id = st.medication_id WHERE m.is_active = 1'
).all() as Array<{ medication_id: number; time_of_day: string }>;
for (const { medication_id, time_of_day } of times) {
scheduleReminder(medication_id, time_of_day, leadMins);
}
}
```
## Troubleshooting
### Notifications not appearing
1. Check `Notification.permission` in browser console - must be `'granted'`
2. Some browsers block notifications on `http://localhost` - check browser notification settings
3. On macOS, check System Settings > Notifications for the browser
### Jobs not firing
1. Verify `cron.schedule` expression with `cron.validate(expression)`
2. Check server timezone matches user's timezone expectation
3. Ensure `node-cron` is installed: `pnpm add node-cron`Related Skills
notification-hub
Operate the notification-hub API and web interface to manage notifications from GitHub, Slack, and Email sources.
irrigation-scheduler
Schedule and monitor irrigation zones with weather-aware skip rules and water usage tracking. Use when asked to manage irrigation timing, set up zone schedules, configure rain-based skip rules, check water usage, trigger manual watering, or apply seasonal duration presets. Triggers include "irrigation", "sprinkler schedule", "watering zones", "skip when raining", "water usage tracking", "manual run irrigation", or any task involving automated watering management.
Skill: crew-scheduler
## Purpose
Skill: Uptime Monitoring
## Overview
Skill: Status Page
## Overview
Skill: unit-conversion
## Overview
Skill: recipe-scaler
## Overview
reading-list
Operate the reading-list API to save, manage, tag, search, and export articles.
email-digest
Configure, test, and troubleshoot the reading-list daily email digest delivered via nodemailer.
websocket-realtime
Use the WebSocket connection in poll-builder to receive live vote updates. Use when you need to stream real-time poll results, monitor a poll for new votes, or build a live dashboard. Triggers include "live results", "real-time updates", "stream votes", "watch poll", or "WebSocket".
poll-builder
Self-hosted poll creation tool with real-time results. Use when you need to create a poll, check vote counts, close a poll, export results, or get the shareable link for a poll. Triggers include "create poll", "vote", "poll results", "survey", "collect votes", "share poll", or any task involving polling or voting.
Skill: personal-finance
## Overview