| name | notification-hub |
| version | 1.0 |
| description | Operate the notification-hub API and web interface to manage notifications from GitHub, Slack, and Email sources. |
| tools | ["Bash","Read","Write","Edit"] |
notification-hub skill
notification-hub is a unified notification aggregator. It ingests notifications from GitHub, Slack, and Email, normalises them into a single feed, and lets you filter, mute, label, archive, and digest them through a web UI and REST API.
Environment
The server listens on PORT (default 3000). Set these variables before running:
NOTIFICATION_HUB_PORT=3000
NOTIFICATION_HUB_DB=./data/notifications.db
NOTIFICATION_HUB_ENCRYPTION_KEY=<32-byte hex> # AES-256-GCM key for OAuth token storage
NOTIFICATION_HUB_SESSION_SECRET=<random>
GITHUB_CLIENT_ID=<app client id>
GITHUB_CLIENT_SECRET=<app client secret>
GITHUB_CALLBACK_URL=http://localhost:3000/auth/github/callback
SLACK_CLIENT_ID=<app client id>
SLACK_CLIENT_SECRET=<app client secret>
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=alerts@example.com
SMTP_PASS=<password>
DIGEST_RECIPIENT=you@example.com
Starting the server
pnpm install
pnpm dev
pnpm build && pnpm start
Or with Docker:
docker compose up
REST API
All routes are prefixed /api. Authenticate with the session cookie or the API token via Authorization: Bearer <token>.
Feed
curl http://localhost:3000/api/notifications
curl "http://localhost:3000/api/notifications?source=github&unread=1&priority=high"
curl "http://localhost:3000/api/notifications?q=auth+middleware"
curl http://localhost:3000/api/notifications/:id
curl -X PATCH http://localhost:3000/api/notifications/:id \
-H 'Content-Type: application/json' \
-d '{"read": true}'
curl -X PATCH http://localhost:3000/api/notifications/:id \
-H 'Content-Type: application/json' \
-d '{"priority": "high"}'
curl -X POST http://localhost:3000/api/notifications/:id/archive
curl -X POST http://localhost:3000/api/notifications/bulk \
-H 'Content-Type: application/json' \
-d '{"ids": ["id1","id2"], "action": "read"}'
curl -X POST http://localhost:3000/api/notifications/bulk \
-H 'Content-Type: application/json' \
-d '{"ids": ["id1","id2"], "action": "archive"}'
Sources
curl http://localhost:3000/api/sources
curl http://localhost:3000/api/sources/:id
curl -X POST http://localhost:3000/api/sources/:id/sync
curl -X DELETE http://localhost:3000/api/sources/:id
curl -X PATCH http://localhost:3000/api/sources/:id \
-H 'Content-Type: application/json' \
-d '{"config": {"repos": ["acme/api-gateway","acme/frontend"]}}'
curl -X PATCH http://localhost:3000/api/sources/:id \
-H 'Content-Type: application/json' \
-d '{"config": {"channels": ["C012ABCDE","C999FGHIJ"]}}'
Mute rules
curl http://localhost:3000/api/mute-rules
curl -X POST http://localhost:3000/api/mute-rules \
-H 'Content-Type: application/json' \
-d '{
"pattern": "repo:acme/billing-api",
"source": "github",
"expiresAt": null
}'
curl -X POST http://localhost:3000/api/mute-rules \
-H 'Content-Type: application/json' \
-d '{
"pattern": "title:chore*",
"source": "github",
"expiresAt": "2026-04-01T00:00:00Z"
}'
curl -X PATCH http://localhost:3000/api/mute-rules/:id \
-H 'Content-Type: application/json' \
-d '{"enabled": false}'
curl -X DELETE http://localhost:3000/api/mute-rules/:id
Supported pattern prefixes: repo:, channel:, title:, from:, type:. Use * as a wildcard.
Digest
curl http://localhost:3000/api/digest/config
curl -X PATCH http://localhost:3000/api/digest/config \
-H 'Content-Type: application/json' \
-d '{"enabled": true, "deliveryTime": "08:00", "timezone": "UTC"}'
curl -X POST http://localhost:3000/api/digest/send
curl http://localhost:3000/api/digest/history
Labels
curl http://localhost:3000/api/labels
curl -X POST http://localhost:3000/api/labels \
-H 'Content-Type: application/json' \
-d '{"name": "incident", "color": "#dc2626"}'
curl -X POST http://localhost:3000/api/notifications/:id/labels \
-H 'Content-Type: application/json' \
-d '{"labelId": "lbl_xyz"}'
curl -X DELETE http://localhost:3000/api/notifications/:id/labels/:labelId
Stats
curl http://localhost:3000/api/stats
curl "http://localhost:3000/api/stats?from=2026-03-01&to=2026-03-31"
Connecting GitHub
- Go to Settings > Sources > Add Source > GitHub.
- Click "Authorize with GitHub" to begin the OAuth2 flow (passport-github2).
- After authorization, select the repositories to watch.
- The OAuth access token is stored encrypted with AES-256-GCM using
NOTIFICATION_HUB_ENCRYPTION_KEY.
- GitHub notifications are polled every
SYNC_INTERVAL_MS milliseconds (default 300000).
Connecting Slack
- Go to Settings > Sources > Add Source > Slack.
- Enter your Slack Bot Token (
xoxb-...). The token is validated immediately.
- Select the channels to watch.
- The bot token is stored encrypted at rest.
- Messages are polled via the Slack Web API (
conversations.history).
Connecting Email (IMAP)
- Go to Settings > Sources > Add Source > Email.
- Enter your IMAP host, port, username, and password.
- Credentials are stored encrypted at rest.
Digest email
The daily digest is sent via nodemailer using the SMTP credentials in the environment. To test delivery without waiting for the scheduled time:
curl -X POST http://localhost:3000/api/digest/send
API token rotation
curl -X POST http://localhost:3000/api/settings/api-token/rotate \
-H 'Authorization: Bearer <current_token>'
Store the new token returned in the response. The old token is invalidated immediately.