Discord ping
Sends a Discord notification when a task the user tagged with /ping is
done. Opt-in and per-message only — this is not a standing "notify me for
everything" mode.
First-time setup (only runs once, ever)
Before sending anything, check whether ~/.claude/notify-skills/config.json
exists and has a ping.webhook_url value.
If it already exists, skip straight to Trigger — setup is done, just use the saved webhook.
If it doesn't exist yet, this is the first time
/pinghas been used. Stop and do setup before doing anything else with the task in this message:Tell the user this is a one-time setup step for
/ping.Explain how to create a Discord webhook, if they don't already have one:
- Open Discord, go to the server and channel they want pings posted to.
- Channel Settings (gear icon) → Integrations → Webhooks → New Webhook.
- Name it whatever they like, click Copy Webhook URL.
Ask them to paste that webhook URL.
Ask (optional) whether they want a specific person
@mentionedin every ping — if so, ask for that Discord user ID (right-click their name with Developer Mode on → Copy User ID). This can be skipped; pings still work without a mention.Save the answer(s) to
~/.claude/notify-skills/config.json:{ "ping": { "webhook_url": "https://discord.com/api/webhooks/....", "mention_id": "123456789012345678" } }If the file already exists (e.g.
dingalready set up its own section), merge into it rather than overwriting other keys. Create the~/.claude/notify-skills/directory first if needed.Confirm setup is complete, then proceed with the actual task from the user's message as normal.
Never commit or print the webhook URL anywhere other than this local config file — it's a bearer credential; anyone with the URL can post to that channel.
Trigger
Only act on this skill when the literal text /ping appears somewhere in
the user's message — it doesn't have to be the first word, e.g. "Build the
retry logic and /ping once it's ready for me to test" is a valid trigger.
If /ping is not present, do not send anything, no matter how long or
important the task is.
Scope: exactly the task in that message, exactly once
/ping applies only to the specific task described in the same message it
appears in — not to unrelated later tasks in the conversation, and not to
every sub-step along the way. Read the message for what "done" means to the
user:
- If they give a specific milestone ("/ping once this is ready for me to test", "/ping when the build finishes"), that milestone is the completion condition — not full task completion, not intermediate progress, not each file edit or each background command. Ping exactly when that milestone is reached.
- If they don't specify a milestone (just "/ping" attached to a task), the completion condition is the task actually being done — including waiting out any background jobs it spawns and knowing the real result, not just having handed it off to the background.
Fire at most one ping for that task. Do not ping on intermediate
progress, partial completion, or for other tasks that didn't include
/ping in their own message.
Sending the ping
Read the webhook URL (and optional mention_id) from
~/.claude/notify-skills/config.json.
Content must be plain ASCII only — no em dashes (—), smart quotes, or
other non-ASCII punctuation. Piping a curl -d JSON body containing
non-ASCII characters through Git Bash can mangle the UTF-8 encoding and
Discord will reject it with {"message": "The request body contains invalid JSON.", "code": 50109} — silently, unless you check the response
body. Use a hyphen - instead of an em dash, and avoid curly quotes.
If a mention_id is set, prefix the content with <@mention_id>. If not,
just send the content without a mention.
WEBHOOK_URL="<from config.json>"
MENTION="<@mention_id or blank>"
curl -s -H "Content-Type: application/json" \
-d "{\"content\": \"$MENTION Task complete: **<short task name>** - <one-line result summary>\"}" \
"$WEBHOOK_URL"
Don't add -o /dev/null — check the actual response. A successful post
returns nothing (empty body); anything printed back is an error worth
reading, not ignoring.
PowerShell form (handles UTF-8 explicitly, safe even with non-ASCII content if that's ever needed):
$config = Get-Content "$HOME\.claude\notify-skills\config.json" | ConvertFrom-Json
$mention = if ($config.ping.mention_id) { "<@$($config.ping.mention_id)> " } else { "" }
$body = @{ content = "$mention Task complete: **<short task name>** - <summary>" } | ConvertTo-Json -Compress
Invoke-RestMethod -Uri $config.ping.webhook_url -Method Post -ContentType "application/json; charset=utf-8" -Body ([System.Text.Encoding]::UTF8.GetBytes($body))
Replace <short task name> with a plain-language label and the summary
with a short factual result (e.g. "ready to test" or "blocked - needs a
decision on X"). Keep the whole message under ~300 characters — Discord
mobile notifications truncate long text.
Still give the normal in-chat response too — the Discord ping is in addition to, not instead of, telling the user directly in the conversation.
If the user ever wants pings routed to a different Discord channel, just
update ~/.claude/notify-skills/config.json directly (or delete the
ping key to trigger setup again next time /ping is used).