* Rename cmuxterm to cmux across entire codebase - Rename GitHub repos: manaflow-ai/cmuxterm -> manaflow-ai/cmux, manaflow-ai/homebrew-cmuxterm -> manaflow-ai/homebrew-cmux - Rename bundle IDs: com.cmuxterm.app -> com.cmux.app - Rename CLI: CLI/cmuxterm.swift -> CLI/cmux.swift - Rename homebrew submodule: homebrew-cmuxterm -> homebrew-cmux - Update all socket paths: /tmp/cmuxterm*.sock -> /tmp/cmux*.sock - Update all GitHub URLs, DMG names, Sparkle URLs - Update all source files, scripts, tests, docs, CI workflows * Bump version to 1.23.0
156 lines
4.2 KiB
Markdown
156 lines
4.2 KiB
Markdown
# Notifications
|
|
|
|
cmux provides a notification panel for AI agents like Claude Code, Codex, and OpenCode. Notifications appear in a dedicated panel and trigger macOS system notifications.
|
|
|
|
## Quick Start
|
|
|
|
```bash
|
|
# Send a notification (if cmux is available)
|
|
command -v cmux &>/dev/null && cmux notify --title "Done" --body "Task complete"
|
|
|
|
# With fallback to macOS notifications
|
|
command -v cmux &>/dev/null && cmux notify --title "Done" --body "Task complete" || osascript -e 'display notification "Task complete" with title "Done"'
|
|
```
|
|
|
|
## Detection
|
|
|
|
Check if `cmux` CLI is available before using it:
|
|
|
|
```bash
|
|
# Shell
|
|
if command -v cmux &>/dev/null; then
|
|
cmux notify --title "Hello"
|
|
fi
|
|
|
|
# One-liner with fallback
|
|
command -v cmux &>/dev/null && cmux notify --title "Hello" || osascript -e 'display notification "" with title "Hello"'
|
|
```
|
|
|
|
```python
|
|
# Python
|
|
import shutil
|
|
import subprocess
|
|
|
|
def notify(title: str, body: str = ""):
|
|
if shutil.which("cmux"):
|
|
subprocess.run(["cmux", "notify", "--title", title, "--body", body])
|
|
else:
|
|
# Fallback to macOS
|
|
subprocess.run(["osascript", "-e", f'display notification "{body}" with title "{title}"'])
|
|
```
|
|
|
|
## CLI Usage
|
|
|
|
```bash
|
|
# Simple notification
|
|
cmux notify --title "Build Complete"
|
|
|
|
# With subtitle and body
|
|
cmux notify --title "Claude Code" --subtitle "Permission" --body "Approval needed"
|
|
|
|
# Notify specific tab/panel
|
|
cmux notify --title "Done" --tab 0 --panel 1
|
|
```
|
|
|
|
## Integration Examples
|
|
|
|
### Claude Code Hooks
|
|
|
|
Add to `~/.claude/settings.json`:
|
|
|
|
```json
|
|
{
|
|
"hooks": {
|
|
"Notification": [
|
|
{
|
|
"matcher": "idle_prompt",
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "command -v cmux &>/dev/null && cmux notify --title 'Claude Code' --body 'Waiting for input' || osascript -e 'display notification \"Waiting for input\" with title \"Claude Code\"'"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": "permission_prompt",
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "command -v cmux &>/dev/null && cmux notify --title 'Claude Code' --subtitle 'Permission' --body 'Approval needed' || osascript -e 'display notification \"Approval needed\" with title \"Claude Code\"'"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
### OpenAI Codex
|
|
|
|
Add to `~/.codex/config.toml`:
|
|
|
|
```toml
|
|
notify = ["bash", "-c", "command -v cmux &>/dev/null && cmux notify --title Codex --body \"$(echo $1 | jq -r '.\"last-assistant-message\" // \"Turn complete\"' 2>/dev/null | head -c 100)\" || osascript -e 'display notification \"Turn complete\" with title \"Codex\"'", "--"]
|
|
```
|
|
|
|
Or create a simple script `~/.local/bin/codex-notify.sh`:
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
MSG=$(echo "$1" | jq -r '."last-assistant-message" // "Turn complete"' 2>/dev/null | head -c 100)
|
|
command -v cmux &>/dev/null && cmux notify --title "Codex" --body "$MSG" || osascript -e "display notification \"$MSG\" with title \"Codex\""
|
|
```
|
|
|
|
Then use:
|
|
```toml
|
|
notify = ["bash", "~/.local/bin/codex-notify.sh"]
|
|
```
|
|
|
|
### OpenCode Plugin
|
|
|
|
Create `.opencode/plugins/cmux-notify.js`:
|
|
|
|
```javascript
|
|
export const CmuxNotificationPlugin = async ({ $, }) => {
|
|
const notify = async (title, body) => {
|
|
try {
|
|
await $`command -v cmux && cmux notify --title ${title} --body ${body}`;
|
|
} catch {
|
|
await $`osascript -e ${"display notification \"" + body + "\" with title \"" + title + "\""}`;
|
|
}
|
|
};
|
|
|
|
return {
|
|
event: async ({ event }) => {
|
|
if (event.type === "session.idle") {
|
|
await notify("OpenCode", "Session idle");
|
|
}
|
|
},
|
|
};
|
|
};
|
|
```
|
|
|
|
## Environment Variables
|
|
|
|
cmux sets these in child shells:
|
|
|
|
| Variable | Description |
|
|
|----------|-------------|
|
|
| `CMUX_SOCKET_PATH` | Path to control socket |
|
|
| `CMUX_TAB_ID` | UUID of the current tab |
|
|
| `CMUX_PANEL_ID` | UUID of the current panel |
|
|
|
|
## CLI Commands
|
|
|
|
```
|
|
cmux notify --title <text> [--subtitle <text>] [--body <text>] [--tab <id|index>] [--panel <id|index>]
|
|
cmux list-notifications
|
|
cmux clear-notifications
|
|
cmux ping
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
1. **Always check availability first** - Use `command -v cmux` before calling
|
|
2. **Provide fallbacks** - Use `|| osascript` for macOS fallback
|
|
3. **Keep notifications concise** - Title should be brief, use body for details
|