Context: Studying claude-code-source-code-full (backup branch)

Claude Code Notification System

Claude Code uses terminal-specific OSC sequences to notify users when it needs attention (e.g., permission prompts, elicitation dialogs). Each terminal gets its own protocol:

TerminalOSC CodeMechanism
iTerm2OSC 9iTerm2 proprietary sequence
KittyOSC 99Multi-part: title, body, activate
GhosttyOSC 777notify;title;message
Apple TerminalBEL (\x07)Raw bell (only if bell enabled in profile)

All sequences are wrapped via wrapForMultiplexer() for tmux/screen DCS passthrough, except BEL which stays raw so tmux can trigger its bell-action.

Configuration

Setting: preferredNotifChannel (set via /config or claude config set)

Valid values (from src/utils/configConstants.ts):

  • auto (default): detects terminal via TERM_PROGRAM and picks matching protocol
  • iterm2, iterm2_with_bell, kitty, ghostty, terminal_bell: force a specific channel
  • notifications_disabled: suppresses all notifications

Idle Threshold

Notifications only fire after the user has been idle. Controlled by useNotifyAfterTimeout (src/hooks/useNotifyAfterTimeout.ts):

  • Hardcoded at 6 seconds (DEFAULT_INTERACTION_THRESHOLD_MS = 6000)
  • A setInterval checks every 6s whether the user has typed anything recently
  • If idle > 6s, notification fires; if actively typing, suppressed
  • Interaction timestamp updated in App.tsx’s processKeysInBatch
  • Not configurable. No setting, CLI flag, or env var to change the threshold.

Environment Variables

VariableEffect
TERM_PROGRAMTerminal detection for auto channel routing
TMUXEnables tmux DCS passthrough wrapping
STYEnables GNU screen passthrough wrapping
SSH_CONNECTIONGates native clipboard (pbcopy); affects OSC pipeline
LC_TERMINALSpecial-cases iTerm2 over SSH (disables tmux -w to avoid crashes)
NODE_ENV=testSuppresses notifications entirely
USER_TYPE=antGates OSC 21337 tab-status emission (Anthropic-internal)

Key Source Files

  • src/ink/termio/osc.ts: OSC sequence generation, multiplexer wrapping
  • src/ink/useTerminalNotification.ts: React hook exposing notify methods per terminal
  • src/services/notifier.ts: Notification dispatch (channel routing, analytics)
  • src/hooks/useNotifyAfterTimeout.ts: Idle detection and threshold logic
  • src/utils/configConstants.ts: Valid channel enum
  • src/utils/env.ts: Terminal detection via TERM_PROGRAM

Hook Integration

The settings hook system has a Notification event. When a notification fires, executeNotificationHooks (src/services/notifier.ts:25) runs any user-configured notification hooks before dispatching the terminal notification. This lets users run custom shell commands on notification.