claude-code-slack-stop-hook.json

Slack ping when a long Claude Code turn finishes

A Claude Code hook that posts to Slack when a turn takes longer than two minutes, so you can walk away from long agent runs and get pulled back when they're done.

Install

  1. Save 1-notify-long-turn.sh to ~/.claude/hooks/notify-long-turn.sh, then chmod +x it.
  2. Create a Slack incoming webhook and export the URL as SLACK_WEBHOOK_URL.
  3. Set MENTION in the script to your own Slack member ID (Slack profile -> More -> Copy member ID). Without the mention the message is silent -- the mention is what makes Slack actually notify you.
  4. Merge 2-settings-snippet.json into ~/.claude/settings.json, replacing the paths with absolute ones. settings.json does not expand $HOME.

Requires jq and curl.

How it works

UserPromptSubmit stamps the turn's start time to /tmp. Stop reads it back, and if the turn ran >= THRESHOLD_SECS (default 120) it posts to the webhook.

A missing stamp file means the Stop came from /clear, a resume, or a compact, so there's nothing to time and the hook exits quietly.

The Stop hook is async, so it never adds latency to your turn.

Tuning

  • THRESHOLD_SECS -- raise it if you get pinged too often.
  • Stamp files are per-session in /tmp; a session that dies without a Stop leaves one behind. Harmless, but rm /tmp/claude-turn-start-* clears them.

Note

The webhook call is fire-and-forget: output is discarded, so the hook reports success whether or not Slack accepted the post. Fine for a personal nudge, but don't debug Slack delivery by trusting that message.

#!/usr/bin/env bash
# Slack-ping yourself when a Claude Code turn runs long.
# start (UserPromptSubmit) -> stamp the turn's start time
# stop (Stop) -> post if the turn took >= THRESHOLD_SECS
set -uo pipefail
THRESHOLD_SECS=120
SLACK_WEBHOOK_URL=${SLACK_WEBHOOK_URL:?set this to your Slack incoming webhook}
MENTION="<@U0123456789>" # your Slack member ID, so the post actually notifies
mode=${1:-stop}
payload=$(cat)
session=$(printf '%s' "$payload" | jq -r '.session_id // "unknown"')
cwd=$(printf '%s' "$payload" | jq -r '.cwd // ""')
stamp="/tmp/claude-turn-start-${session}"
if [[ $mode == start ]]; then date +%s >"$stamp"; exit 0; fi
# No stamp = Stop from /clear, resume, or compact. Nothing to time.
[[ -f $stamp ]] || exit 0
started=$(<"$stamp"); rm -f "$stamp"
elapsed=$(($(date +%s) - started))
((elapsed >= THRESHOLD_SECS)) || exit 0
text="$MENTION Claude Code finished after $((elapsed / 60))m$((elapsed % 60))s in $(basename "${cwd:-$PWD}")"
jq -nc --arg t "$text" '{text:$t}' \
| curl -sS -X POST -H 'Content-type: application/json' --data @- "$SLACK_WEBHOOK_URL" >/dev/null
jq -nc --arg m "$text" '{systemMessage:("Slack ping sent - " + $m)}'
{
"hooks": {
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "/home/YOUR_USERNAME/.claude/hooks/notify-long-turn.sh start"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "/home/YOUR_USERNAME/.claude/hooks/notify-long-turn.sh stop",
"timeout": 120,
"async": true
}
]
}
]
}
}
添加评论
点赞收藏
点踩分享查看原文
评论
?
参与讨论