feat(notifications): add Pushcut as a notification channel#1062
Open
MHoroszowski wants to merge 1 commit intodanielmiessler:mainfrom
Open
feat(notifications): add Pushcut as a notification channel#1062MHoroszowski wants to merge 1 commit intodanielmiessler:mainfrom
MHoroszowski wants to merge 1 commit intodanielmiessler:mainfrom
Conversation
Adds Pushcut (https://www.pushcut.io) as an iOS-native notification channel alongside ntfy. Pushcut delivers rich push notifications to iPhone with first-class iOS Shortcuts integration, action buttons, and an Automation Server for unattended Shortcut execution. Changes: - hooks/lib/notifications.ts: add sendPushcut() following the existing sendPush() (ntfy) pattern. Fire-and-forget POST, 5s timeout, returns boolean, never throws. Loads config from settings.json with the same ${VAR} env-var expansion the ntfy loader uses. - settings.json: add notifications.pushcut block (enabled: false by default — opt-in). Reads PUSHCUT_WEBHOOK_URL from env. Pattern mirrors the existing twilio block. Usage: ```ts import { sendPushcut } from '~/.claude/hooks/lib/notifications'; await sendPushcut('Long task complete', { title: 'Athena' }); ``` Setup for users: 1. Install Pushcut from the App Store 2. Create a named notification in the Notifications tab 3. Copy the secret webhook URL from the notification's detail view 4. Set PUSHCUT_WEBHOOK_URL in ~/.env 5. Set notifications.pushcut.enabled = true in settings.json Why Pushcut over a custom Apple Push Notification (APNs) integration: APNs requires an Apple Developer account ($99/yr) and a registered iOS app. Pushcut already runs that infrastructure and exposes it via a single webhook URL — strictly less complexity for the same outcome, plus the Shortcuts integration that DIY APNs would not provide. Test plan: - [x] sendPushcut() returns true on HTTP 200 from Pushcut API - [x] Returns false (no throw) on misconfig (missing env var, disabled) - [x] Returns false (no throw) on network error / timeout - [x] Verified end-to-end: bun import + call → notification arrives on iPhone via Pushcut iOS app - [x] Pre-existing sendPush() (ntfy) behavior unchanged - [x] No new dependencies; only uses existing fetch + AbortSignal Out of scope (intentional, follow-up candidates): - Multi-channel dispatcher that consults notifications.routing — the routing block exists in settings.json but no code reads it yet. Would be a separate, larger PR. - Pushcut action buttons / defaultAction support — needs concrete use case to design the API surface. - discord/twilio sender implementations (still settings-only stubs).
MHoroszowski
added a commit
to MHoroszowski/Personal_AI_Infrastructure
that referenced
this pull request
Apr 12, 2026
PAI currently owns the user's ~/.env file via a symlink created during install. This is a home-directory namespace grab: ~/.env is a conventional, user-owned file that many shells and tools look for. If the user installs any other tool that expects to read ~/.env, it either collides with PAI's secrets or is silently overwritten on the next PAI install. This is the wrong shape. The cause is that VoiceServer hardcodes `join(homedir(), '.env')` as the only place it looks for ELEVENLABS_API_KEY. The installer created the ~/.env symlink to make that hardcoded read resolve to the real secrets file at ~/.config/PAI/.env (which is already the XDG-compliant, correct canonical location). This change: - VoiceServer/server.ts: load ~/.config/PAI/.env first (XDG canonical location), then optionally overlay from ~/.env if the user has chosen to put PAI-relevant keys there. Values in ~/.env win on key collisions, preserving the "explicit user override" mental model. The error message when ELEVENLABS_API_KEY is missing now points at the canonical path. - PAI-Install/engine/actions.ts: stop creating the ~/.env symlink. ~/.claude/.env stays symlinked (that path is PAI's own namespace, so the symlink is safe and the hooks' existing reads continue working unchanged). The new comment explains why we no longer touch ~/.env. Backward compatibility: - Existing installs that already have the ~/.env symlink continue to work — both paths point at the same real file, so loading both is a no-op. - Existing installs that already have a real ~/.env with PAI values in it continue to work — loadEnvFile() reads both paths and either one (or both) can contain the keys. - New installs after this change will have a real file at ~/.config/PAI/.env and will NOT touch ~/.env. Users own ~/.env. Related to the VoiceServer cross-platform audio work in danielmiessler#1061 and the Pushcut notification channel in danielmiessler#1062.
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds Pushcut as an iOS-native notification channel alongside ntfy, following the existing `sendPush()` pattern in `hooks/lib/notifications.ts`.
Pushcut delivers rich push notifications to iPhone with first-class iOS Shortcuts integration, action buttons, and an Automation Server for unattended Shortcut execution. It's purpose-built for the "webhook → iPhone notification → optional Shortcuts automation" use case.
Why Pushcut
The Apple-native alternative is a custom Apple Push Notification (APNs) integration, which requires:
Pushcut already runs that infrastructure and exposes it via a single webhook URL. Strictly less complexity for the same delivery guarantees, plus the Shortcuts integration a DIY APNs solution would not provide. The free tier covers most personal notification volumes; Pro is ~$5/mo.
Changes
`sendPushcut(message, options)` matches the `sendPush()` signature exactly:
Usage
```ts
import { sendPushcut } from '~/.claude/hooks/lib/notifications';
await sendPushcut('Long task complete', { title: 'Athena' });
```
User setup (will need a docs entry — happy to add to a follow-up doc PR if useful)
Test plan
Out of scope (intentional, possible follow-ups)
Related
This is a feature add, not a bug fix. Happy to scope it down further or split if maintainers prefer a smaller initial surface.