cmux/docs-site/content/docs/claude-code-hooks.mdx
Lawrence Chen f36525f5f1 Add documentation site and Homebrew installation
- Add Fumadocs-based docs site (docs-site/)
- Document all features: tabs, notifications, splits, socket API, CLI
- Add Claude Code hooks guide with cmuxterm detection
- Update README with native macOS emphasis and brew install
- Add homebrew-cmuxterm to .gitignore (has its own repo)
2026-01-29 04:41:39 -08:00

266 lines
5.4 KiB
Text

---
title: Claude Code Hooks
description: Set up notifications for Claude Code using cmuxterm hooks
---
# Claude Code Hooks
cmuxterm 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 cmuxterm
Before sending notifications, you should detect if you're running inside cmuxterm to avoid conflicts with other terminals.
### Detection Methods
**1. Check for the socket:**
```bash
[ -S /tmp/cmuxterm.sock ] && echo "In cmuxterm"
```
**2. Check for the CLI:**
```bash
command -v cmuxterm &>/dev/null && echo "cmuxterm available"
```
**3. Check the TERM_PROGRAM environment variable:**
```bash
[ "$TERM_PROGRAM" = "ghostty" ] && [ -S /tmp/cmuxterm.sock ] && echo "In cmuxterm"
```
<Callout type="info">
cmuxterm 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/cmuxterm-notify.sh"
]
}
],
"Stop": [
"/path/to/cmuxterm-notify.sh"
]
}
}
```
## Notification Hook Script
Create a script that checks for cmuxterm and sends notifications:
```bash
#!/bin/bash
# ~/.claude/hooks/cmuxterm-notify.sh
# Only proceed if we're in cmuxterm
if [ ! -S /tmp/cmuxterm.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")
cmuxterm notify \
--title "Claude Code" \
--subtitle "Task Complete" \
--body "Session $SESSION finished"
;;
"PostToolUse")
if [ "$TOOL_NAME" = "Task" ]; then
cmuxterm notify \
--title "Claude Code" \
--subtitle "Agent Finished" \
--body "Task agent completed in session $SESSION"
fi
;;
esac
```
Make it executable:
```bash
chmod +x ~/.claude/hooks/cmuxterm-notify.sh
```
## Example Configurations
### Notify on All Completions
Get notified whenever Claude Code finishes a task:
```json
{
"hooks": {
"Stop": [
"~/.claude/hooks/cmuxterm-notify.sh"
]
}
}
```
### Notify on Long-Running Tasks
Only notify for Task tool completions (agent subprocesses):
```json
{
"hooks": {
"PostToolUse": [
{
"matcher": "Task",
"hooks": ["~/.claude/hooks/cmuxterm-notify.sh"]
}
]
}
}
```
### Notify on Errors
Add error notifications:
```bash
#!/bin/bash
# cmuxterm-notify.sh with error handling
if [ ! -S /tmp/cmuxterm.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
cmuxterm notify \
--title "Claude Code Error" \
--body "$ERROR"
elif [ "$EVENT_TYPE" = "Stop" ]; then
cmuxterm notify \
--title "Claude Code" \
--body "Task complete"
fi
```
## Advanced: Conditional Notifications
Only notify if the terminal is not focused:
```bash
#!/bin/bash
# cmuxterm-notify.sh with focus detection
if [ ! -S /tmp/cmuxterm.sock ]; then
exit 0
fi
# cmuxterm 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
cmuxterm 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/cmuxterm.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/cmuxterm-notify.sh << 'EOF'
#!/bin/bash
# cmuxterm notification hook for Claude Code
# Skip if not in cmuxterm
[ -S /tmp/cmuxterm.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")
cmuxterm notify --title "Claude Code" --body "Session complete"
;;
"PostToolUse")
[ "$TOOL" = "Task" ] && cmuxterm notify --title "Claude Code" --body "Agent finished"
;;
esac
EOF
chmod +x ~/.claude/hooks/cmuxterm-notify.sh
```
3. Configure Claude Code:
```bash
cat > ~/.claude/settings.json << 'EOF'
{
"hooks": {
"Stop": ["~/.claude/hooks/cmuxterm-notify.sh"],
"PostToolUse": [
{
"matcher": "Task",
"hooks": ["~/.claude/hooks/cmuxterm-notify.sh"]
}
]
}
}
EOF
```
4. Restart Claude Code to apply the hooks.
Now you'll receive desktop notifications in cmuxterm whenever Claude Code finishes a task or needs attention.