feat: add notifying-through-ntfy skill

Amolith created

Sends push notifications via ntfy.sh when the user explicitly asks to be
notified. Includes curl examples in SKILL.md and alternative HTTP client
references (ht, httpie, wget, python, nodejs) for environments where
curl is unavailable.

Change summary

skills/notifying-through-ntfy/SKILL.md             | 80 +++++++++++++
skills/notifying-through-ntfy/references/ht.md     | 42 +++++++
skills/notifying-through-ntfy/references/httpie.md | 38 ++++++
skills/notifying-through-ntfy/references/nodejs.md | 92 ++++++++++++++++
skills/notifying-through-ntfy/references/python.md | 68 +++++++++++
skills/notifying-through-ntfy/references/wget.md   | 42 +++++++
6 files changed, 362 insertions(+)

Detailed changes

skills/notifying-through-ntfy/SKILL.md 🔗

@@ -0,0 +1,80 @@
+---
+name: notifying-through-ntfy
+description: Sends push notifications via ntfy.sh. Use when the user asks to be notified, says "ntfy me", or requests a notification when a task is done.
+license: GPL-3.0-or-later
+metadata:
+  author: Amolith <amolith@secluded.site>
+---
+
+Send a notification only when the user explicitly asks for one.
+
+## Environment
+
+Two environment variables are required:
+
+- `$NTFY_TOPIC_LLM` — the ntfy topic to publish to
+- `$NTFY_ACCESS_TOKEN` — bearer token for authentication
+
+If either is unset or empty, ask the user to set them before proceeding.
+
+## Headers
+
+Set headers on every notification:
+
+- **Title** (`-H "Title: ..."`) — brief, informative, sentence-case summary of what happened (e.g. "Refactored authentication middleware in rumilo")
+- **Tags** (`-H "Tags: ..."`) — comma-separated emoji shortcodes (prefer one). Must be a valid shortcode or ntfy treats it as a text tag instead of an emoji prefix.
+- **Priority** (`-H "Priority: ..."`) — integer 1–5. Only set when something went wrong; 3 is default and omitted.
+  - 1 (min) / 2 (low): quiet, no vibration
+  - 3 (default): normal notification
+  - 4 (high): long vibration burst
+  - 5 (max/urgent): very long vibration burst, may bypass Do Not Disturb
+- **Click** (`-H "Click: ..."`) — optional URL opened when the notification is tapped. If your environment provides a way to generate a link back to the current conversation or session, include it. If not, only set this header when linking to something directly relevant (a PR, a deploy, a docs page, etc.). Never fabricate a conversation URL.
+
+## Body
+
+The body is a slightly longer, friendly paragraph saying who finished what in which project. Keep it conversational and informative — a sentence or two is plenty.
+
+## Examples
+
+```bash
+# normal success
+curl -H "Authorization: Bearer $NTFY_ACCESS_TOKEN" \
+  -H "Title: Refactored authentication middleware in rumilo" \
+  -H "Tags: hammer_and_wrench" \
+  -d "Finished refactoring the auth middleware in rumilo. Session validation is cleaner now and all tests pass." \
+  "https://ntfy.sh/$NTFY_TOPIC_LLM"
+
+# success with a relevant click URL
+curl -H "Authorization: Bearer $NTFY_ACCESS_TOKEN" \
+  -H "Title: Updated AUR package for kagi-ken" \
+  -H "Tags: package" \
+  -H "Click: https://aur.archlinux.org/packages/kagi-ken" \
+  -d "Bumped the kagi-ken AUR package to v0.4.2 and updated the checksums." \
+  "https://ntfy.sh/$NTFY_TOPIC_LLM"
+
+# something went wrong
+curl -H "Authorization: Bearer $NTFY_ACCESS_TOKEN" \
+  -H "Title: Build failed in pi-mono — disk full" \
+  -H "Tags: rotating_light" \
+  -H "Priority: 4" \
+  -d "Ran into a full disk on the build server while compiling pi-mono. /var/log looks like it needs rotation. The build is blocked until there's space." \
+  "https://ntfy.sh/$NTFY_TOPIC_LLM"
+
+# urgent failure
+curl -H "Authorization: Bearer $NTFY_ACCESS_TOKEN" \
+  -H "Title: Production database unreachable" \
+  -H "Tags: sos" \
+  -H "Priority: 5" \
+  -d "The primary Postgres instance stopped responding during a migration. Rolled back what we could, but the app is down." \
+  "https://ntfy.sh/$NTFY_TOPIC_LLM"
+```
+
+## Alternative HTTP clients
+
+If `curl` is unavailable or blocked, use one of these instead:
+
+- **ht** (httpie-go): see [ht.md](references/ht.md)
+- **HTTPie**: see [httpie.md](references/httpie.md)
+- **wget**: see [wget.md](references/wget.md)
+- **Python**: see [python.md](references/python.md)
+- **Node.js**: see [nodejs.md](references/nodejs.md)

skills/notifying-through-ntfy/references/ht.md 🔗

@@ -0,0 +1,42 @@
+# ht (httpie-go)
+
+`ht` uses httpie-style `Header:Value` syntax. The request body is passed via stdin.
+
+## Examples
+
+```bash
+# normal success
+ht POST "https://ntfy.sh/$NTFY_TOPIC_LLM" \
+  "Authorization:Bearer $NTFY_ACCESS_TOKEN" \
+  "Title:Refactored authentication middleware in rumilo" \
+  "Tags:hammer_and_wrench" <<'EOF'
+Finished refactoring the auth middleware in rumilo. Session validation is cleaner now and all tests pass.
+EOF
+
+# success with a relevant click URL
+ht POST "https://ntfy.sh/$NTFY_TOPIC_LLM" \
+  "Authorization:Bearer $NTFY_ACCESS_TOKEN" \
+  "Title:Updated AUR package for kagi-ken" \
+  "Tags:package" \
+  "Click:https://aur.archlinux.org/packages/kagi-ken" <<'EOF'
+Bumped the kagi-ken AUR package to v0.4.2 and updated the checksums.
+EOF
+
+# something went wrong
+ht POST "https://ntfy.sh/$NTFY_TOPIC_LLM" \
+  "Authorization:Bearer $NTFY_ACCESS_TOKEN" \
+  "Title:Build failed in pi-mono — disk full" \
+  "Tags:rotating_light" \
+  "Priority:4" <<'EOF'
+Ran into a full disk on the build server while compiling pi-mono. /var/log looks like it needs rotation. The build is blocked until there's space.
+EOF
+
+# urgent failure
+ht POST "https://ntfy.sh/$NTFY_TOPIC_LLM" \
+  "Authorization:Bearer $NTFY_ACCESS_TOKEN" \
+  "Title:Production database unreachable" \
+  "Tags:sos" \
+  "Priority:5" <<'EOF'
+The primary Postgres instance stopped responding during a migration. Rolled back what we could, but the app is down.
+EOF
+```

skills/notifying-through-ntfy/references/httpie.md 🔗

@@ -0,0 +1,38 @@
+# HTTPie
+
+HTTPie (`http` command) uses `Header:Value` syntax for headers and reads the body from stdin with `<` or via echo/pipe.
+
+## Examples
+
+```bash
+# normal success
+echo 'Finished refactoring the auth middleware in rumilo. Session validation is cleaner now and all tests pass.' | \
+  http POST "https://ntfy.sh/$NTFY_TOPIC_LLM" \
+  "Authorization:Bearer $NTFY_ACCESS_TOKEN" \
+  "Title:Refactored authentication middleware in rumilo" \
+  "Tags:hammer_and_wrench"
+
+# success with a relevant click URL
+echo 'Bumped the kagi-ken AUR package to v0.4.2 and updated the checksums.' | \
+  http POST "https://ntfy.sh/$NTFY_TOPIC_LLM" \
+  "Authorization:Bearer $NTFY_ACCESS_TOKEN" \
+  "Title:Updated AUR package for kagi-ken" \
+  "Tags:package" \
+  "Click:https://aur.archlinux.org/packages/kagi-ken"
+
+# something went wrong
+echo 'Ran into a full disk on the build server while compiling pi-mono. /var/log looks like it needs rotation. The build is blocked until there is space.' | \
+  http POST "https://ntfy.sh/$NTFY_TOPIC_LLM" \
+  "Authorization:Bearer $NTFY_ACCESS_TOKEN" \
+  "Title:Build failed in pi-mono — disk full" \
+  "Tags:rotating_light" \
+  "Priority:4"
+
+# urgent failure
+echo 'The primary Postgres instance stopped responding during a migration. Rolled back what we could, but the app is down.' | \
+  http POST "https://ntfy.sh/$NTFY_TOPIC_LLM" \
+  "Authorization:Bearer $NTFY_ACCESS_TOKEN" \
+  "Title:Production database unreachable" \
+  "Tags:sos" \
+  "Priority:5"
+```

skills/notifying-through-ntfy/references/nodejs.md 🔗

@@ -0,0 +1,92 @@
+# Node.js
+
+Uses the built-in `https` module — no third-party dependencies required. Run each example as a standalone script.
+
+## Examples
+
+### Normal success
+
+```javascript
+const https = require("https");
+const req = https.request(
+  `https://ntfy.sh/${process.env.NTFY_TOPIC_LLM}`,
+  {
+    method: "POST",
+    headers: {
+      Authorization: `Bearer ${process.env.NTFY_ACCESS_TOKEN}`,
+      Title: "Refactored authentication middleware in rumilo",
+      Tags: "hammer_and_wrench",
+    },
+  },
+  (res) => res.resume()
+);
+req.end(
+  "Finished refactoring the auth middleware in rumilo. Session validation is cleaner now and all tests pass."
+);
+```
+
+### Success with a relevant click URL
+
+```javascript
+const https = require("https");
+const req = https.request(
+  `https://ntfy.sh/${process.env.NTFY_TOPIC_LLM}`,
+  {
+    method: "POST",
+    headers: {
+      Authorization: `Bearer ${process.env.NTFY_ACCESS_TOKEN}`,
+      Title: "Updated AUR package for kagi-ken",
+      Tags: "package",
+      Click: "https://aur.archlinux.org/packages/kagi-ken",
+    },
+  },
+  (res) => res.resume()
+);
+req.end(
+  "Bumped the kagi-ken AUR package to v0.4.2 and updated the checksums."
+);
+```
+
+### Something went wrong
+
+```javascript
+const https = require("https");
+const req = https.request(
+  `https://ntfy.sh/${process.env.NTFY_TOPIC_LLM}`,
+  {
+    method: "POST",
+    headers: {
+      Authorization: `Bearer ${process.env.NTFY_ACCESS_TOKEN}`,
+      Title: "Build failed in pi-mono — disk full",
+      Tags: "rotating_light",
+      Priority: "4",
+    },
+  },
+  (res) => res.resume()
+);
+req.end(
+  "Ran into a full disk on the build server while compiling pi-mono. /var/log looks like it needs rotation. The build is blocked until there's space."
+);
+```
+
+### Urgent failure
+
+```javascript
+const https = require("https");
+const req = https.request(
+  `https://ntfy.sh/${process.env.NTFY_TOPIC_LLM}`,
+  {
+    method: "POST",
+    headers: {
+      Authorization: `Bearer ${process.env.NTFY_ACCESS_TOKEN}`,
+      Title: "Production database unreachable",
+      Tags: "sos",
+      Priority: "5",
+    },
+  },
+  (res) => res.resume()
+);
+req.end(
+  "The primary Postgres instance stopped responding during a migration. Rolled back what we could, but the app is down."
+);
+```

skills/notifying-through-ntfy/references/python.md 🔗

@@ -0,0 +1,68 @@
+# Python
+
+Uses the standard library `urllib.request` — no third-party dependencies required. Run each example as a standalone script.
+
+## Examples
+
+### Normal success
+
+```python
+import os, urllib.request
+
+req = urllib.request.Request(
+    f"https://ntfy.sh/{os.environ['NTFY_TOPIC_LLM']}",
+    data=b"Finished refactoring the auth middleware in rumilo. Session validation is cleaner now and all tests pass.",
+)
+req.add_header("Authorization", f"Bearer {os.environ['NTFY_ACCESS_TOKEN']}")
+req.add_header("Title", "Refactored authentication middleware in rumilo")
+req.add_header("Tags", "hammer_and_wrench")
+urllib.request.urlopen(req)
+```
+
+### Success with a relevant click URL
+
+```python
+import os, urllib.request
+
+req = urllib.request.Request(
+    f"https://ntfy.sh/{os.environ['NTFY_TOPIC_LLM']}",
+    data=b"Bumped the kagi-ken AUR package to v0.4.2 and updated the checksums.",
+)
+req.add_header("Authorization", f"Bearer {os.environ['NTFY_ACCESS_TOKEN']}")
+req.add_header("Title", "Updated AUR package for kagi-ken")
+req.add_header("Tags", "package")
+req.add_header("Click", "https://aur.archlinux.org/packages/kagi-ken")
+urllib.request.urlopen(req)
+```
+
+### Something went wrong
+
+```python
+import os, urllib.request
+
+req = urllib.request.Request(
+    f"https://ntfy.sh/{os.environ['NTFY_TOPIC_LLM']}",
+    data=b"Ran into a full disk on the build server while compiling pi-mono. /var/log looks like it needs rotation. The build is blocked until there's space.",
+)
+req.add_header("Authorization", f"Bearer {os.environ['NTFY_ACCESS_TOKEN']}")
+req.add_header("Title", "Build failed in pi-mono — disk full")
+req.add_header("Tags", "rotating_light")
+req.add_header("Priority", "4")
+urllib.request.urlopen(req)
+```
+
+### Urgent failure
+
+```python
+import os, urllib.request
+
+req = urllib.request.Request(
+    f"https://ntfy.sh/{os.environ['NTFY_TOPIC_LLM']}",
+    data=b"The primary Postgres instance stopped responding during a migration. Rolled back what we could, but the app is down.",
+)
+req.add_header("Authorization", f"Bearer {os.environ['NTFY_ACCESS_TOKEN']}")
+req.add_header("Title", "Production database unreachable")
+req.add_header("Tags", "sos")
+req.add_header("Priority", "5")
+urllib.request.urlopen(req)
+```

skills/notifying-through-ntfy/references/wget.md 🔗

@@ -0,0 +1,42 @@
+# wget
+
+`wget` can POST with `--post-data`. Headers are added with `--header`.
+
+## Examples
+
+```bash
+# normal success
+wget --quiet --output-document=- \
+  --header="Authorization: Bearer $NTFY_ACCESS_TOKEN" \
+  --header="Title: Refactored authentication middleware in rumilo" \
+  --header="Tags: hammer_and_wrench" \
+  --post-data="Finished refactoring the auth middleware in rumilo. Session validation is cleaner now and all tests pass." \
+  "https://ntfy.sh/$NTFY_TOPIC_LLM"
+
+# success with a relevant click URL
+wget --quiet --output-document=- \
+  --header="Authorization: Bearer $NTFY_ACCESS_TOKEN" \
+  --header="Title: Updated AUR package for kagi-ken" \
+  --header="Tags: package" \
+  --header="Click: https://aur.archlinux.org/packages/kagi-ken" \
+  --post-data="Bumped the kagi-ken AUR package to v0.4.2 and updated the checksums." \
+  "https://ntfy.sh/$NTFY_TOPIC_LLM"
+
+# something went wrong
+wget --quiet --output-document=- \
+  --header="Authorization: Bearer $NTFY_ACCESS_TOKEN" \
+  --header="Title: Build failed in pi-mono — disk full" \
+  --header="Tags: rotating_light" \
+  --header="Priority: 4" \
+  --post-data="Ran into a full disk on the build server while compiling pi-mono. /var/log looks like it needs rotation. The build is blocked until there's space." \
+  "https://ntfy.sh/$NTFY_TOPIC_LLM"
+
+# urgent failure
+wget --quiet --output-document=- \
+  --header="Authorization: Bearer $NTFY_ACCESS_TOKEN" \
+  --header="Title: Production database unreachable" \
+  --header="Tags: sos" \
+  --header="Priority: 5" \
+  --post-data="The primary Postgres instance stopped responding during a migration. Rolled back what we could, but the app is down." \
+  "https://ntfy.sh/$NTFY_TOPIC_LLM"
+```