Hooks need a way to write escape sequences to the user's terminal

Resolved 💬 2 comments Opened May 12, 2026 by alec-coast Closed May 12, 2026

Context

In v2.1.132, hooks were intentionally cut off from terminal access to prevent corrupting interactive prompts. This was a good fix for the corruption bug, but it broke a legitimate use case: hooks that write ANSI escape sequences to change terminal appearance (e.g., background color theming based on Claude's state).

Problem

Stop, UserPromptSubmit, and SessionEnd hooks that write to /dev/tty now fail with:

/bin/sh: /dev/tty: Device not configured

The hooks in question are doing things like:

# Change terminal background on Stop (visual indicator Claude is idle)
printf '\033]11;#132b1a\007' > /dev/tty

# Reset terminal background on UserPromptSubmit / SessionEnd
printf '\033]111\007' > /dev/tty

These are non-destructive escape sequences that don't interfere with Claude's UI — they modify the terminal emulator's background color, not the content area.

Suggested fix

Expose the user's actual tty device path as an environment variable in the hook subprocess (e.g., CLAUDE_CODE_TTY=/dev/ttys003). This would let hooks that need terminal access opt in explicitly:

[ -n "$CLAUDE_CODE_TTY" ] && printf '\033]11;#132b1a\007' > "$CLAUDE_CODE_TTY"

This preserves the v2.1.132 fix (hooks don't get /dev/tty by default) while giving hook authors a way to reach the terminal when they need to.

Environment

  • Claude Code 2.1.139
  • macOS (Ghostty terminal)
  • zsh

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗