Skip to main content

Documentation Index

Fetch the complete documentation index at: https://factory-docs-auto-sync-jp-docs.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

This cookbook shows how to set up custom notifications so you know when Droid needs your input or when important events occur during a session.

How it works

Notification hooks can:
  1. Trigger on multiple events: Notification, Stop, SubagentStop, SessionEnd
  2. Support multiple channels: Desktop notifications, system sounds, Slack, email, webhooks
  3. Provide context: Include session details, task completion status, error messages
  4. Filter intelligently: Only notify on important events
  5. Work cross-platform: macOS, Linux, Windows

Prerequisites

Install notification tools for your platform:
# Built-in commands (no installation needed)
which osascript  # For display notifications
which afplay     # For sounds
For Slack notifications, create a webhook at api.slack.com/messaging/webhooks.

Basic notifications

Desktop notification when Droid waits

Get notified when Droid is waiting for your input. Create .factory/hooks/notify-wait.sh:
#!/bin/bash

input=$(cat)
message=$(echo "$input" | jq -r '.message // "Droid needs your attention"')
hook_event=$(echo "$input" | jq -r '.hook_event_name')

# Only notify on actual wait events
if [ "$hook_event" != "Notification" ]; then
  exit 0
fi

# Platform-specific notification
if [[ "$OSTYPE" == "darwin"* ]]; then
  # macOS
  osascript -e "display notification \"$message\" with title \"Droid\" sound name \"Ping\""
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
  # Linux
  notify-send "Droid" "$message" -i dialog-information -u normal
elif [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" ]]; then
  # Windows
  powershell -Command "New-BurntToastNotification -Text 'Droid', '$message'"
fi

exit 0
chmod +x .factory/hooks/notify-wait.sh
Add to ~/.factory/settings.json (user-wide):
{
  "hooks": {
    "Notification": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "~/.factory/hooks/notify-wait.sh",
            "timeout": 5
          }
        ]
      }
    ]
  }
}

Sound alert when task completes

Play a sound when Droid finishes. Create .factory/hooks/completion-sound.sh:
#!/bin/bash

input=$(cat)
hook_event=$(echo "$input" | jq -r '.hook_event_name')

# Only alert on completion events
if [ "$hook_event" != "Stop" ]; then
  exit 0
fi

# Platform-specific sound
if [[ "$OSTYPE" == "darwin"* ]]; then
  # macOS - use system sounds
  afplay /System/Library/Sounds/Glass.aiff
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
  # Linux - use system bell or speaker-test
  paplay /usr/share/sounds/freedesktop/stereo/complete.oga 2>/dev/null || \
    echo -e '\a'  # Fallback to terminal bell
fi

exit 0
chmod +x .factory/hooks/completion-sound.sh
Add to ~/.factory/settings.json:
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "~/.factory/hooks/completion-sound.sh",
            "timeout": 3
          }
        ]
      }
    ]
  }
}

Advanced notifications

Slack integration

Send Slack messages when Droid completes tasks. Create .factory/hooks/slack-notify.sh:
#!/bin/bash
set -e

# Configure your Slack webhook URL
SLACK_WEBHOOK_URL="${SLACK_WEBHOOK_URL:-}"

if [ -z "$SLACK_WEBHOOK_URL" ]; then
  echo "SLACK_WEBHOOK_URL not set, skipping Slack notification"
  exit 0
fi

input=$(cat)
hook_event=$(echo "$input" | jq -r '.hook_event_name')
session_id=$(echo "$input" | jq -r '.session_id')
cwd=$(echo "$input" | jq -r '.cwd')

# Build message based on event type
case "$hook_event" in
  "Stop")
    title="✅ Droid Task Completed"
    color="good"
    ;;
  "SessionEnd")
    title="🏁 Droid Session Ended"
    color="#808080"
    reason=$(echo "$input" | jq -r '.reason')
    ;;
  "SubagentStop")
    title="🤖 Subagent Task Completed"
    color="good"
    ;;
  *)
    exit 0
    ;;
esac

# Send to Slack
curl -X POST "$SLACK_WEBHOOK_URL" \
  -H 'Content-Type: application/json' \
  -d @- << EOF
{
  "attachments": [
    {
      "color": "$color",
      "title": "$title",
      "fields": [
        {
          "title": "Project",
          "value": "$(basename "$cwd")",
          "short": true
        },
        {
          "title": "Session",
          "value": "${session_id:0:8}...",
          "short": true
        }
      ],
      "footer": "Droids",
      "ts": $(date +%s)
    }
  ]
}
EOF

exit 0
chmod +x .factory/hooks/slack-notify.sh
Set your webhook URL:
# Add to ~/.bashrc or ~/.zshrc
export SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
Add to ~/.factory/settings.json:
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "~/.factory/hooks/slack-notify.sh",
            "timeout": 10
          }
        ]
      }
    ],
    "SessionEnd": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "~/.factory/hooks/slack-notify.sh",
            "timeout": 10
          }
        ]
      }
    ]
  }
}

Email notifications

Send email alerts for important events. Create .factory/hooks/email-notify.sh:
#!/bin/bash
set -e

# Configure email settings
EMAIL_TO="${DROID_NOTIFY_EMAIL:-your-email@example.com}"
EMAIL_FROM="${DROID_FROM_EMAIL:-droid@factory.ai}"

input=$(cat)
hook_event=$(echo "$input" | jq -r '.hook_event_name')

# Only notify on session end with errors
if [ "$hook_event" != "SessionEnd" ]; then
  exit 0
fi

reason=$(echo "$input" | jq -r '.reason')
session_id=$(echo "$input" | jq -r '.session_id')
cwd=$(echo "$input" | jq -r '.cwd')

# Check if session ended due to error
if [ "$reason" != "error" ] && [ "$reason" != "other" ]; then
  exit 0
fi

# Send email using sendmail or mail command
subject="Droid Session Ended: $(basename "$cwd")"
body="Session $session_id ended with reason: $reason

Project: $cwd
Time: $(date)

Check the logs for more details."

# Try sendmail first, fallback to mail command
if command -v sendmail &> /dev/null; then
  echo -e "Subject: $subject\nFrom: $EMAIL_FROM\nTo: $EMAIL_TO\n\n$body" | sendmail -t
elif command -v mail &> /dev/null; then
  echo "$body" | mail -s "$subject" "$EMAIL_TO"
else
  echo "No email command available (sendmail or mail)"
  exit 1
fi

exit 0
chmod +x .factory/hooks/email-notify.sh
Configure environment:
# Add to ~/.bashrc or ~/.zshrc
export DROID_NOTIFY_EMAIL="your-email@example.com"

Rich desktop notifications with actions

macOS notifications with action buttons. Create .factory/hooks/rich-notify-macos.sh:
#!/bin/bash

input=$(cat)
hook_event=$(echo "$input" | jq -r '.hook_event_name')
message=$(echo "$input" | jq -r '.message // "Droid needs your attention"')
session_id=$(echo "$input" | jq -r '.session_id')

# Only for macOS
if [[ "$OSTYPE" != "darwin"* ]]; then
  exit 0
fi

case "$hook_event" in
  "Notification")
    # Notification with action buttons
    osascript << EOF
tell application "System Events"
  display notification "$message" with title "Droid Waiting" subtitle "Session: ${session_id:0:8}" sound name "Ping"
end tell
EOF
    ;;
    
  "Stop")
    # Success notification
    osascript << EOF
tell application "System Events"
  display notification "Task completed successfully" with title "Droid Complete" subtitle "$(basename "$PWD")" sound name "Glass"
end tell
EOF
    ;;
    
  "SessionEnd")
    reason=$(echo "$input" | jq -r '.reason')
    # Different sound based on reason
    sound="Purr"
    if [ "$reason" == "error" ]; then
      sound="Basso"
    fi
    
    osascript << EOF
tell application "System Events"
  display notification "Session ended: $reason" with title "Droid Session" subtitle "$(basename "$PWD")" sound name "$sound"
end tell
EOF
    ;;
esac

exit 0
chmod +x .factory/hooks/rich-notify-macos.sh

Webhook integration

Send notifications to custom webhooks: Create .factory/hooks/webhook-notify.sh:
#!/bin/bash
set -e

WEBHOOK_URL="${DROID_WEBHOOK_URL:-}"

if [ -z "$WEBHOOK_URL" ]; then
  exit 0
fi

input=$(cat)

# Forward the entire hook input to webhook
curl -X POST "$WEBHOOK_URL" \
  -H 'Content-Type: application/json' \
  -d "$input" \
  --max-time 5 \
  --silent \
  --show-error

exit 0
chmod +x .factory/hooks/webhook-notify.sh
export DROID_WEBHOOK_URL="https://your-webhook-url.com/droid-events"

Real-world examples

Example 1: Focus mode notifications

Only notify when you’re away from your desk: Create .factory/hooks/smart-notify.sh:
#!/bin/bash

input=$(cat)

# Check if user is idle (macOS)
if [[ "$OSTYPE" == "darwin"* ]]; then
  idle_time=$(ioreg -c IOHIDSystem | awk '/HIDIdleTime/ {print int($NF/1000000000)}')
  
  # Only notify if idle for more than 60 seconds
  if [ "$idle_time" -lt 60 ]; then
    exit 0
  fi
fi

# Send notification
message=$(echo "$input" | jq -r '.message // "Droid needs your attention"')
osascript -e "display notification \"$message\" with title \"Droid\" sound name \"Ping\""

exit 0

Example 2: Team notification dashboard

Log all events to a shared dashboard: Create .factory/hooks/team-logger.sh:
#!/bin/bash
set -e

# Central logging endpoint
LOG_ENDPOINT="${TEAM_LOG_ENDPOINT:-}"

if [ -z "$LOG_ENDPOINT" ]; then
  exit 0
fi

input=$(cat)
hook_event=$(echo "$input" | jq -r '.hook_event_name')
session_id=$(echo "$input" | jq -r '.session_id')
cwd=$(echo "$input" | jq -r '.cwd')

# Add metadata
payload=$(echo "$input" | jq -c ". + {
  user: \"$USER\",
  hostname: \"$HOSTNAME\",
  timestamp: \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",
  project: \"$(basename "$cwd")\"
}")

# Send to logging service
curl -X POST "$LOG_ENDPOINT" \
  -H 'Content-Type: application/json' \
  -d "$payload" \
  --max-time 3 \
  --silent

exit 0

Best practices

1

Keep notification scripts fast

Use short timeouts to avoid blocking Droid:
{
  "timeout": 5  // 5 seconds max for notifications
}
2

Handle failures gracefully

Don’t block execution if notifications fail:
# Continue even if curl fails
curl -X POST "$URL" ... || true
exit 0
3

Respect user preferences

Check environment variables for opt-out:
if [ "$DROID_DISABLE_NOTIFICATIONS" = "true" ]; then
  exit 0
fi
4

Test notifications

Manually trigger hooks for testing:
# Test notification script
echo '{"hook_event_name":"Notification","message":"Test"}' | .factory/hooks/notify-wait.sh
5

Use appropriate notification levels

Different events warrant different urgency:
  • Notification: High urgency (Droid waiting)
  • Stop: Medium urgency (task complete)
  • SessionEnd: Low urgency (FYI only)

Troubleshooting

Problem: No notifications show up Solution: Check notification permissions:
# macOS - check System Settings > Notifications
# Linux - verify notify-send works
notify-send "Test" "This is a test"

# Check if hooks are executing
droid --debug
Problem: Slack messages not sending Solution: Test webhook directly:
curl -X POST "$SLACK_WEBHOOK_URL" \
  -H 'Content-Type: application/json' \
  -d '{"text":"Test from curl"}'
Problem: Getting spammed with alerts Solution: Add rate limiting:
# Only notify once every 5 minutes
LAST_NOTIFY_FILE="/tmp/droid-last-notify"

if [ -f "$LAST_NOTIFY_FILE" ]; then
  last_time=$(cat "$LAST_NOTIFY_FILE")
  current_time=$(date +%s)
  if [ $((current_time - last_time)) -lt 300 ]; then
    exit 0
  fi
fi

date +%s > "$LAST_NOTIFY_FILE"
# ... send notification
Problem: No audio alert Solution: Check audio system:
# macOS - list available sounds
ls /System/Library/Sounds/

# Test sound
afplay /System/Library/Sounds/Glass.aiff

# Linux - check audio
paplay /usr/share/sounds/freedesktop/stereo/complete.oga

See also