Quick answer
Create an incoming webhook in Slack or Discord, copy its URL, then attach a Claude Code Stop (and Notification) hook that POSTs a JSON message to it with curl. Slack expects {"text":"..."}; Discord expects {"content":"..."}. Use an absolute path to curl in the hook — hooks run in a non-interactive shell that won't load your PATH — and restart Claude Code so it picks up the new hook. That's the whole setup.
Slack and Discord webhooks are the fastest way to get Claude Code to announce itself — to a team channel, to a personal log, or just to a window you already keep open all day. The setup is a single hook, but there are two details (the payload key and a shell trap) that trip almost everyone. Here's the whole thing.
Step 1: Create the incoming webhook
Slack: create a Slack app for your workspace, enable Incoming Webhooks, and add a webhook for the channel you want to post to (say, #claude-code). Slack gives you a URL like https://hooks.slack.com/services/T000/B000/XXXX. Anyone who can post to that URL can post to that channel, so treat it like a secret.
Discord: open the target channel → Edit Channel → Integrations → Webhooks → New Webhook, then Copy Webhook URL. It looks like https://discord.com/api/webhooks/000/XXXX.
A webhook URL is a credential. Anyone with it can post to your channel, so don't paste it into a public repo or a shared dotfile. If one leaks, delete the webhook and create a new one.
Step 2: Add the hook to settings.json
Attach the webhook to the Stop event so your channel pings when an agent finishes. The one difference between the two services is the JSON key — Slack uses text, Discord uses content.
Slack:
{
"hooks": {
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "/usr/bin/curl -s -X POST \"YOUR_SLACK_WEBHOOK_URL\" -H \"Content-Type: application/json\" -d '{\"text\":\"✅ Claude Code finished — your move.\"}'"
}
]
}
]
}
}
Discord — same shape, but content instead of text:
{
"hooks": {
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "/usr/bin/curl -s -X POST \"YOUR_DISCORD_WEBHOOK_URL\" -H \"Content-Type: application/json\" -d '{\"content\":\"✅ Claude Code finished — your move.\"}'"
}
]
}
]
}
}
Add a second entry under the Notification event with the same command (tweak the message to "needs your input") if you also want to hear about mid-task permission prompts, not just the finish. For why those are two separate events, see how to know when Claude Code is done.
Step 3: Restart Claude Code
Hooks are read when a session starts, so an edit to settings.json mid-session is ignored until you relaunch. Exit and restart Claude Code (then /resume if you want your conversation back). This step alone fixes a lot of "I added the hook and nothing posts" reports.
The one gotcha: absolute paths
If your curl posts fine when you run it by hand but the hook never reaches Slack, this is almost always why: hooks run in a non-interactive shell that doesn't load ~/.zshrc or ~/.bashrc. Any binary that's only on your PATH because of those files won't be found. Use an absolute path:
which curl
# → /usr/bin/curl (paste the full path into your hook command)
This is the single most common cause of a hook that "works when I test it" but silently does nothing on its own. The full list of failure modes is in notifications not working.
Want richer Slack messages? Both services accept structured payloads — Slack "blocks" and Discord "embeds" — so you can add fields, colors, and a title instead of a plain line. Start with plain text to confirm the plumbing works, then upgrade the JSON body once you see messages landing.
Where a chat webhook stops being enough
A Slack or Discord ping is perfect for a shared log or a desktop nudge. But be honest about what it isn't:
- It's fire-and-forget text. The message says something happened; it can't update in place to show live status, and it can't tell you which of five parallel agents pinged unless you put that in the payload yourself.
- You can't act from it. A permission prompt in Slack is just a notice — you still have to switch back to the terminal to approve it.
- It lives on your desk. Great if Slack is always open on your Mac; less great when you've walked away and your phone is the only screen nearby.
Stop babysitting your terminal
Agentfy pushes Claude Code status to your iPhone — Live Activities, Dynamic Island, and instant alerts.
If what you actually want is away-from-desk monitoring — a push to your phone the instant an agent finishes, plus a glanceable Live Activity that shows the current state without opening anything — a dedicated monitor fits better than a chat channel. Agentfy installs the hooks for you via an open-source Claude Code plugin and shows each session as its own card. The two aren't mutually exclusive — plenty of people keep a #claude-code channel for the team log and run a phone monitor for themselves.