Problem
Warp plugin hook scripts (Stop, PermissionRequest, Notification, etc.) fail to send OSC 777 notifications because Claude Code spawns hook subprocesses
without a controlling TTY.
warp-notify.sh writes to /dev/tty, which silently fails:
printf '\033]777;notify;%s;%s\007' "$TITLE" "$BODY" > /dev/tty 2>/dev/null || true
The || true masks the error, so hooks appear to succeed but no notification is ever delivered.
Evidence
Process tree shows the hook subprocess has no TTY (??), while the parent claude process does:
PID PPID TTY COMMAND
89386 76147 ?? /bin/zsh -c ... (hook subprocess)
76147 43670 ttys007 claude --resume ...
43670 43508 ttys007 -zsh
Running tty from within a hook confirms: not a tty.
Workaround
Modified warp-notify.sh to find the ancestor process's TTY when /dev/tty is unavailable:
TTY_PATH="/dev/tty"
if ! printf '' > "$TTY_PATH" 2>/dev/null; then
ANCESTOR_TTY=$(ps -o tty= -p $PPID 2>/dev/null | tr -d ' ')
if [ -n "$ANCESTOR_TTY" ] && [ "$ANCESTOR_TTY" != "??" ] && [ -e "/dev/$ANCESTOR_TTY" ]; then
TTY_PATH="/dev/$ANCESTOR_TTY"
else
ANCESTOR_TTY=$(ps -o tty= -p $(ps -o ppid= -p $PPID) 2>/dev/null | tr -d ' ')
if [ -n "$ANCESTOR_TTY" ] && [ "$ANCESTOR_TTY" != "??" ] && [ -e "/dev/$ANCESTOR_TTY" ]; then
TTY_PATH="/dev/$ANCESTOR_TTY"
else
exit 0
fi
fi
fi
printf '\033]777;notify;%s;%s\007' "$TITLE" "$BODY" > "$TTY_PATH" 2>/dev/null || true
This fix was tested and confirmed working — notifications are delivered correctly after the change.
Environment
- macOS (Darwin 25.3.0, arm64)
- Warp: v0.2026.05.18.05.32.stable_02
- Claude Code: 2.1.121
- Plugin: warp@claude-code-warp 2.0.0
- WARP_CLI_AGENT_PROTOCOL_VERSION=1
Problem
Warp plugin hook scripts (Stop, PermissionRequest, Notification, etc.) fail to send OSC 777 notifications because Claude Code spawns hook subprocesses
without a controlling TTY.
warp-notify.shwrites to/dev/tty, which silently fails:printf '\033]777;notify;%s;%s\007' "$TITLE" "$BODY" > /dev/tty 2>/dev/null || true
The
|| truemasks the error, so hooks appear to succeed but no notification is ever delivered.Evidence
Process tree shows the hook subprocess has no TTY (
??), while the parentclaudeprocess does:PID PPID TTY COMMAND
89386 76147 ?? /bin/zsh -c ... (hook subprocess)
76147 43670 ttys007 claude --resume ...
43670 43508 ttys007 -zsh
Running
ttyfrom within a hook confirms:not a tty.Workaround
Modified
warp-notify.shto find the ancestor process's TTY when/dev/ttyis unavailable: