Skip to content

Instantly share code, notes, and snippets.

@iboss-ptk
Last active April 21, 2026 05:02
Show Gist options
  • Select an option

  • Save iboss-ptk/3c036277237f4e483447a9f450244e58 to your computer and use it in GitHub Desktop.

Select an option

Save iboss-ptk/3c036277237f4e483447a9f450244e58 to your computer and use it in GitHub Desktop.
Claude Code stop hook: ntfy.sh + say notification

Claude Code Stop Hook — ntfy.sh Push Notification

Sends a push notification when a Claude Code session finishes — but only if it ran longer than 30 seconds.

Motivation

When Claude is doing a long agentic task (running tests, implementing a feature, exploring a codebase), you often switch context and forget to check back. Short sessions don't need a ping — you're still watching. Long ones do — you've moved on.

This hook solves that by tracking session duration and only notifying when Claude actually did meaningful work.

This is an extension from idea here.

How it works

Two hooks wire together:

session-start.sh — runs on SessionStart. Writes the current Unix timestamp to /tmp/claude_session_<session_id>.

push-notify.sh — runs on Stop. Reads the timestamp, computes elapsed time, and exits silently if under 30 seconds. Otherwise sends a message to ntfy.sh with the project directory, current git branch, and stop reason.

Setup

  1. Copy both scripts to ~/.claude/hooks/ and make them executable:

    chmod +x ~/.claude/hooks/session-start.sh
    chmod +x ~/.claude/hooks/push-notify.sh
  2. Generate a unique private topic:

    openssl rand -hex 16
  3. Set NTFY_TOPIC in your environment (e.g. in ~/.zshrc or ~/.claude/settings.json env block):

    export NTFY_TOPIC=your_hex_topic_here
  4. Add to ~/.claude/settings.json:

    {
      "hooks": {
        "SessionStart": [{
          "hooks": [{ "type": "command", "command": "bash ~/.claude/hooks/session-start.sh" }]
        }],
        "Stop": [{
          "hooks": [{ "type": "command", "command": "bash ~/.claude/hooks/push-notify.sh" }]
        }]
      }
    }
  5. Install ntfy on your phone/desktop and subscribe to your topic.

Dependencies

  • jq — parse hook JSON input
  • curl — send ntfy request
  • git — optional, for branch name in message
#!/usr/bin/env bash
INPUT=$(cat)
SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // ""' 2>/dev/null)
REASON=$(echo "$INPUT" | jq -r '.stop_reason // "completed"' 2>/dev/null)
START_FILE="/tmp/claude_session_${SESSION_ID}"
[ ! -f "$START_FILE" ] && exit 0
START=$(cat "$START_FILE")
NOW=$(date +%s)
ELAPSED=$((NOW - START))
rm -f "$START_FILE"
[ "$ELAPSED" -lt 30 ] && exit 0
DIR=$(basename "$(pwd)")
BRANCH=$(git branch --show-current 2>/dev/null || echo "")
MSG="Claude done: $DIR"
[ -n "$BRANCH" ] && MSG="$MSG ($BRANCH)"
[ -n "$REASON" ] && MSG="$MSG — $REASON"
curl -s -d "$MSG" "https://ntfy.sh/${NTFY_TOPIC}" 2>/dev/null &
# Optional: add `say` command here so that your computer also speaks something when it's done.
exit 0
#!/usr/bin/env bash
INPUT=$(cat)
SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // ""' 2>/dev/null)
[ -z "$SESSION_ID" ] && exit 0
echo "$(date +%s)" > "/tmp/claude_session_${SESSION_ID}"
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment