add-push-notification
Skill50 starsChanged 20 days agoApache-2.0View on GitHub
Adds push notifications (Web Push) to a Next.js app. Generates the VAPID keys, creates the subscriptions table, extends the PWA service worker with the push handlers, and adds an 'Enable notifications' button on the user side plus a server-side send helper. DEPENDS on /add-pwa (web push needs the service worker installed by the PWA): if the app is not a PWA, the skill explains this and offers to turn it into a PWA first. Also depends on /add-db and /add-auth (users mode).
- Reads credentials
- Installs packages
1 other project uses a version of this.
Adopted by
Most recently taken up by
- flavien-ia/hypervibe-craftword for word, first seen Oct 25, 2026
Other versions1 project uses a version of this.
Word for word · 1
- flavien-ia/hypervibe-craft★ 50100% same
Edited · 0
None found.
Wrote their own version · 0
None found.
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository89 other files it gives its agents.
- accessibilitySkill
- add-2faSkill
- add-agent-dashboardSkill
- add-aiSkill
- add-analyticsSkill
- add-authSkill
- add-automationSkill
- add-backup-dbSkill
- add-collabSkill
- add-cronSkill
- add-dark-modeSkill
- add-dbSkill
- add-domainSkill
- add-emailSkill
- add-github-authSkill
- add-google-authSkill
- add-i18nSkill
- _add-keyringSkill
- add-mapSkill
- add-notification-centerSkill
- add-pwaSkill
- add-roleSkill
- add-routineSkill
- add-storageSkill
- add-stripeSkill
- add-testSkill
- bootstrapSkill
- _check-depsSkill
- cleanSkill
- _collect-secretSkill
- _convert-to-turborepoSkill
- _create-agentSkill
- _create-cloudflare-workerSkill
- _create-contact-pageSkill
- _create-render-workerSkill
- _create-routineSkill
- _create-workflowSkill
- delete-projectSkill
- _detect-project-rootSkill
- _dns-brevoSkill
- _dns-cloudflareSkill
- _dns-gandiSkill
- _dns-godaddy-manualSkill
- _dns-hostingerSkill
- _dns-infomaniak-manualSkill
- _dns-ionos-manualSkill
- _dns-lwsSkill
- _dns-namecheapSkill
- _dns-ovhSkill
- _dns-porkbunSkill
- _dns-resendSkill
- _dns-squarespace-manualSkill
- eco-auditSkill
- _ensure-aiSkill
- _ensure-vaultSkill
- _generate-secretSkill
- geoSkill
- _get-secretSkill
- gscSkill
- _hash-passwordSkill
- The first 60 shown.
The file
We split this skill into the rules it gives an agent
5 rules. About 0 are common, 3 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 14
Use plain, non-technical business language.
- Distinctive: line 15
When generating user-facing content for the scaffolded project (UI labels, emails, copy), write it in the user's language too.
- Very specific: line 65
Auth in users mode: read <WEB_DIR>/src/server/auth.ts and look for the // hypervibe:auth-modes marker.
- Distinctive: line 127
Wiring the notification center (any order): check whether the in-app center is already installed:
- Very specific: line 185
Check test -f "<WEB_DIR>/src/server/notify.ts".
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Add Push Notification: Web Push (PWA)
You add push notifications to the current project's app: the user can enable notifications on their device, and the server can send notifications even when the app is closed.
Communication
- Detect the user's language from the conversation (the user's own messages, anywhere in the session - not just this invocation: a bare slash command like
/bootstrapcarries no language signal by itself). If nothing in the conversation gives a signal, fall back to the OS locale (node -e "console.log(Intl.DateTimeFormat().resolvedOptions().locale)") before defaulting to English. ALWAYS reply in that language for every user-facing message: questions, progress, confirmations, summaries, errors - including any example text quoted in this skill, which is illustrative and must be translated, never sent verbatim. - Use plain, non-technical business language. Never expose internal script names (*.mjs) or jargon; describe actions in human terms.
- When generating user-facing content for the scaffolded project (UI labels, emails, copy), write it in the user's language too.
- Show progress as a short natural-language checklist (in-progress and done states).
Step 0: Re-run? (idempotence)
Detect whether push is already in place: the hypervibe:push marker at the top of <WEB_DIR>/src/server/push.ts.
test -f "<WEB_DIR>/src/server/push.ts" && grep -q "hypervibe:push" "<WEB_DIR>/src/server/push.ts" && echo present || echo absentpresent → first, the version of
web-pushthe project carries. A project set up while this skill installed it unpinned may have web-push 4, whichsrc/server/push.tscannot load (no default export): sending fails at run time.node -e "const v=require('<WEB_DIR>/node_modules/web-push/package.json').version;console.log(v.split('.')[0]==='3'?'ok':'v'+v)" 2>/dev/null || echo missingAnything but
ok: runcd <WEB_DIR> && pnpm add "web-push@^3.6.7" && pnpm add -D "@types/web-push@^3.6.4"and tell the user in one sentence that the push library goes back to version 3, the one the app's code is written for. Then the menu: (1) reinstall the enable button, (2) regenerate the VAPID keys (warning: invalidates existing subscriptions), (3) resend a test notification. Handle it, then skip to the summary.- absent → Step 1.
Step 1: Prerequisites (order matters)
Templates/scripts path: ${CLAUDE_SKILL_DIR}/../../templates/push/ and ${CLAUDE_SKILL_DIR}/../../scripts/.
- Detect project root: invoke
_detect-project-root→WEB_DIR,IS_MONOREPO,IS_NEXTJS. Abort if not Next.js. PWA present? (hard dependency)
test -f "<WEB_DIR>/src/app/manifest.ts" && grep -q "hypervibe:pwa" "<WEB_DIR>/src/app/manifest.ts" \ && test -f "<WEB_DIR>/src/app/sw.ts" && echo pwa-ok || echo pwa-missing- pwa-ok → continue.
pwa-missing → explain then offer, via
AskUserQuestion:Push notifications are not possible until your app is a PWA (an installable app). It is the invisible component of the PWA, the "service worker", that receives notifications and displays them, even when the app is closed. Without it, there is no technical way to push a notification.
I can turn your app into a PWA now (installable + offline cache), then continue on to notifications. It is quick and risk-free.
Options:
- Yes, turn my app into a PWA → run the
/add-pwaskill, then re-test the marker above. Oncepwa-ok, continue. - No, not now → stop cleanly: "No problem. Run
/add-push-notificationagain whenever you want, and I will offer to install the PWA first."
- Yes, turn my app into a PWA → run the
- Database: invoke
_check-deps db. Ifdb_ok = false, offer/add-db(push subscriptions are stored in the database), then re-check. - Auth in users mode: read
<WEB_DIR>/src/server/auth.tsand look for the// hypervibe:auth-modesmarker. If it does not containusers, offer/add-auth(users mode): a push subscription is tied to a logged-in user. Once it is in place, come back here.
Step 2: Install web-push
# Major 3 pinned: web-push 4 is ESM with no default export, and templates/push/server-push.ts
# imports it by default (`import webpush`). `import * as webpush` is not the way out yet: it fails at
# run time on 3.x (CommonJS). Move to 4 when server-push.ts and @types/web-push (3.6.x today) both follow it.
pnpm add "web-push@^3.6.7"
pnpm add -D "@types/web-push@^3.6.4"Step 3: VAPID keys (project-specific secrets)
First check whether they already exist in the environment (NEXT_PUBLIC_VAPID_PUBLIC_KEY): if so, do not regenerate (that would invalidate the subscriptions). Otherwise, generate them:
cd "<WEB_DIR>" && node "${CLAUDE_SKILL_DIR}/../../scripts/generate-vapid-keys.mjs" --env \
| node "${CLAUDE_SKILL_DIR}/../../scripts/push-env-vars.mjs" --stdinThe two keys go from the generator to the local .env and Vercel on a pipe: the private key never appears in the conversation, nor in a process argument. Then push the subject, which is not a secret, via _push-env-vars:
VAPID_SUBJECT=mailto:<project contact email>(readBREVO_SENDER_EMAIL/ADMIN_EMAIL/ the project domain; defaultmailto:contact@<domain>).
These are project-specific secrets (like AUTH_SECRET): they go in .env + Vercel, never in the global vault.
Step 4: Subscriptions table
- Insert the contents of
templates/push/schema-snippet.tsinto the Drizzle schema (<WEB_DIR>/src/server/db/schema.ts, orpackages/db/src/schema.tsin a monorepo), after theuserstable. Check that the imports used (index,text,timestamp,sql,createTable,users) are present (add them otherwise). AdaptcreateTableto the project conventions if the helper has a different name. - Push the schema:
cd "<WEB_DIR>" && pnpm db:push
Step 5: Extend the service worker (the heart of the dependency)
Insert the push handlers into the service worker created by /add-pwa. Read templates/push/sw-push-handlers.ts, replace __APP_NAME__, and insert its contents into <WEB_DIR>/src/app/sw.ts right after the // hypervibe:push-handlers marker line.
Idempotence: if src/app/sw.ts already contains an addEventListener("push", do not reinsert. Exception: if the existing push handler does NOT contain the postMessage({ type: "hv:new-notification" }) broadcast (older installs), add that broadcast block to the existing handler — it is what lets the notification-center bell update in real time without aggressive polling (which keeps the Neon database awake: it only autosuspends after 5 min without a query).
(The public/sw.js is regenerated at the next build: in dev the SW is disabled, so push can only be observed after deployment.)
Step 6: Server (send helper + tRPC router)
- Copy
templates/push/server-push.tsto<WEB_DIR>/src/server/push.ts. Replace__VAPID_SUBJECT__with themailto:from Step 3. The template already contains the// hypervibe:pushmarker on the first line (detected at Step 0 and by/add-notification-center): keep it. - Copy
templates/push/push-router.tsto<WEB_DIR>/src/server/api/routers/push.ts. - Wire the router into
appRouter(<WEB_DIR>/src/server/api/root.ts):import { pushRouter } from "~/server/api/routers/push"; // inside createTRPCRouter({ ... }): push: pushRouter, - Wiring the notification center (any order): check whether the in-app center is already installed:
test -f "<WEB_DIR>/src/server/notify.ts" && grep -q "hypervibe:notification-center" "<WEB_DIR>/src/server/notify.ts" && echo center-present || echo center-absent- center-present → follow
templates/notif-center/notify-push-block.ts: add thesendPushToUserimport at the top ofnotify.tsand replace the marker line// hypervibe:notify-pushwithawait sendPushToUser(db, userId, payload);(idempotent). That waynotifyUserrings the bell and pushes to the phone. - center-absent → do nothing here (offered at Step 9).
- center-present → follow
To send a push from anywhere on the server side:
await sendPushToUser(db, userId, { title: "...", body: "...", url: "/..." }).
(If the in-app center is present, prefer notifyUser(...) which does both.)
Step 7: "Enable notifications" button (user side)
- Copy
templates/push/enable-notifications.tsxto<WEB_DIR>/src/components/. - Toasts: the template uses
sonner. If the project does not havesonneror a mounted<Toaster />, either install it (pnpm add sonner+ mount<Toaster />in the layout), or replace thetoast.*calls with a simple visual feedback (local state + message). Also adapt the colors to the palette. - Mount
<EnableNotifications />in a logged-in area (account page, dashboard, settings). Ask the user where they want the button if the placement is not obvious, or put it on the account page by default.
Step 8 (bis): Declare the delivery service
The payload does not travel from your server to the device: it goes through the push service of the browser the person uses (Apple, Google, Mozilla). That service is a recipient, whatever the site publisher decides, so it belongs in the registry.
node "${CLAUDE_SKILL_DIR}/../../scripts/update-privacy-policy.mjs" --add web-pushWorth saying to the user, because it is the reassuring half: the payload is encrypted with the VAPID keys generated at Step 3, so the service that carries it cannot read it. Only the destination device can.
Step 8: CLAUDE.md + verification
- Invoke
_update-claude-md:stack:- **Push**: Web Push (web-push + VAPID), subscriptions in the \push_subscription` table, handlers in the service worker.`env-vars:- \NEXT_PUBLIC_VAPID_PUBLIC_KEY` / `VAPID_PRIVATE_KEY` / `VAPID_SUBJECT`: Web Push (VAPID) keys`conventions:- Send a notification: \sendPushToUser(db, userId, { title, body, url })` from `~/server/push`. `url` is an internal path (`/orders/12`): a click on the notification opens the home page for anything else, never another site.`
- Verify:
cd "<WEB_DIR>" && pnpm tsc --noEmit && pnpm lint
Step 9: Summary + iOS caveat
- Users can enable notifications from the button, and the server can send them notifications via
sendPushToUser. - iOS caveat (important, tell the user): on iPhone/iPad, web push only works if the app has been installed to the home screen (PWA, iOS 16.4+), and the activation must be triggered by a user gesture (the button). This is an Apple constraint, not a bug.
- To test after deployment: install the app on mobile, click "Enable notifications", then trigger a test send.
- Without deployment there is nothing to observe: the service worker is disabled in dev.
Cross-offer: in-app notification center (if absent)
Check test -f "<WEB_DIR>/src/server/notify.ts". If absent, offer via AskUserQuestion:
You now have system notifications (push): they arrive on the phone, even with the app closed. You can also add an in-app notification center: a bell with a badge showing the unread count and the list of notifications, viewable at any time.
The difference: push grabs attention outside the app (and disappears); the bell keeps a viewable history inside it (read/unread). The two complement each other, and a single
notifyUsercall will send both.
- Yes → run
/add-notification-center(which will detect push and wire push sending intonotifyUser). - No → "No problem. You can add it later with
/add-notification-center."
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

