---
title: Claude Code Hooks
description: Set up notifications for Claude Code using cmux hooks
---

# Claude Code Hooks

cmux integrates with [Claude Code](https://docs.anthropic.com/en/docs/claude-code) via hooks to notify you when tasks complete or when Claude needs attention.

## Detecting cmux

Before sending notifications, you should detect if you're running inside cmux to avoid conflicts with other terminals.

### Detection Methods

**1. Check for the socket:**

```bash
[ -S /tmp/cmux.sock ] && echo "In cmux"
```

**2. Check for the CLI:**

```bash
command -v cmux &>/dev/null && echo "cmux available"
```

**3. Check the TERM_PROGRAM environment variable:**

```bash
[ "$TERM_PROGRAM" = "ghostty" ] && [ -S /tmp/cmux.sock ] && echo "In cmux"
```

<Callout type="info">
  cmux sets `TERM_PROGRAM=ghostty` since it's built on Ghostty. Use the socket check to distinguish from regular Ghostty.
</Callout>

## Setting Up Hooks

Claude Code supports hooks that run on specific events. Add these to your `~/.claude/settings.json`:

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Task",
        "hooks": [
          "/path/to/cmux-notify.sh"
        ]
      }
    ],
    "Stop": [
      "/path/to/cmux-notify.sh"
    ]
  }
}
```

## Notification Hook Script

Create a script that checks for cmux and sends notifications:

```bash
#!/bin/bash
# ~/.claude/hooks/cmux-notify.sh

# Only proceed if we're in cmux
if [ ! -S /tmp/cmux.sock ]; then
    exit 0
fi

# Parse the hook event from stdin (Claude Code passes JSON)
EVENT=$(cat)

# Extract event type and details
EVENT_TYPE=$(echo "$EVENT" | jq -r '.event // "unknown"')
TOOL_NAME=$(echo "$EVENT" | jq -r '.tool_name // ""')
SESSION=$(echo "$EVENT" | jq -r '.session_id // ""' | cut -c1-8)

case "$EVENT_TYPE" in
    "Stop")
        cmux notify \
            --title "Claude Code" \
            --subtitle "Task Complete" \
            --body "Session $SESSION finished"
        ;;
    "PostToolUse")
        if [ "$TOOL_NAME" = "Task" ]; then
            cmux notify \
                --title "Claude Code" \
                --subtitle "Agent Finished" \
                --body "Task agent completed in session $SESSION"
        fi
        ;;
esac
```

Make it executable:

```bash
chmod +x ~/.claude/hooks/cmux-notify.sh
```

## Example Configurations

### Notify on All Completions

Get notified whenever Claude Code finishes a task:

```json
{
  "hooks": {
    "Stop": [
      "~/.claude/hooks/cmux-notify.sh"
    ]
  }
}
```

### Notify on Long-Running Tasks

Only notify for Task tool completions (agent subprocesses):

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Task",
        "hooks": ["~/.claude/hooks/cmux-notify.sh"]
      }
    ]
  }
}
```

### Notify on Errors

Add error notifications:

```bash
#!/bin/bash
# cmux-notify.sh with error handling

if [ ! -S /tmp/cmux.sock ]; then
    exit 0
fi

EVENT=$(cat)
EVENT_TYPE=$(echo "$EVENT" | jq -r '.event // "unknown"')
ERROR=$(echo "$EVENT" | jq -r '.error // ""')

if [ -n "$ERROR" ] && [ "$ERROR" != "null" ]; then
    cmux notify \
        --title "Claude Code Error" \
        --body "$ERROR"
elif [ "$EVENT_TYPE" = "Stop" ]; then
    cmux notify \
        --title "Claude Code" \
        --body "Task complete"
fi
```

## Advanced: Conditional Notifications

Only notify if the terminal is not focused:

```bash
#!/bin/bash
# cmux-notify.sh with focus detection

if [ ! -S /tmp/cmux.sock ]; then
    exit 0
fi

# cmux automatically suppresses notifications for focused tabs,
# so we can always send - it will handle suppression for us

EVENT=$(cat)
EVENT_TYPE=$(echo "$EVENT" | jq -r '.event // "unknown"')

if [ "$EVENT_TYPE" = "Stop" ]; then
    cmux notify \
        --title "Claude Code" \
        --subtitle "Ready" \
        --body "Waiting for your input"
fi
```

## Using OSC Sequences Directly

If you prefer not to use the CLI, you can emit OSC sequences directly:

```bash
#!/bin/bash
# Direct OSC notification (no CLI needed)

if [ ! -S /tmp/cmux.sock ]; then
    exit 0
fi

EVENT=$(cat)
EVENT_TYPE=$(echo "$EVENT" | jq -r '.event // "unknown"')

if [ "$EVENT_TYPE" = "Stop" ]; then
    # OSC 777 notification
    printf '\e]777;notify;Claude Code;Task complete\a'
fi
```

## Full Example Setup

1. Create the hooks directory:

```bash
mkdir -p ~/.claude/hooks
```

2. Create the notification script:

```bash
cat > ~/.claude/hooks/cmux-notify.sh << 'EOF'
#!/bin/bash
# cmux notification hook for Claude Code

# Skip if not in cmux
[ -S /tmp/cmux.sock ] || exit 0

EVENT=$(cat)
EVENT_TYPE=$(echo "$EVENT" | jq -r '.event // "unknown"')
TOOL=$(echo "$EVENT" | jq -r '.tool_name // ""')

case "$EVENT_TYPE" in
    "Stop")
        cmux notify --title "Claude Code" --body "Session complete"
        ;;
    "PostToolUse")
        [ "$TOOL" = "Task" ] && cmux notify --title "Claude Code" --body "Agent finished"
        ;;
esac
EOF
chmod +x ~/.claude/hooks/cmux-notify.sh
```

3. Configure Claude Code:

```bash
cat > ~/.claude/settings.json << 'EOF'
{
  "hooks": {
    "Stop": ["~/.claude/hooks/cmux-notify.sh"],
    "PostToolUse": [
      {
        "matcher": "Task",
        "hooks": ["~/.claude/hooks/cmux-notify.sh"]
      }
    ]
  }
}
EOF
```

4. Restart Claude Code to apply the hooks.

Now you'll receive desktop notifications in cmux whenever Claude Code finishes a task or needs attention.
