Visual feedback system for Claude Code running in iTerm2. Get immediate visual cues when Claude is thinking vs waiting for your input.
| Event | Visual Feedback |
|---|---|
| You submit a prompt | Moon phases animate in session title bar |
| Claude stops responding | Your pane flashes white |
| You start typing | Your pane goes back to black |
Per-session isolation: Each Claude Code session has independent visual feedback - perfect for multi-pane workflows.
When Claude is working:
🌒 Your Session Name 🌟⏳🟥🔥
When Claude finishes: Screen flashes white then waits for your input.
When you start typing: Screen goes black (acknowledged!)
- iTerm2 with Python API enabled
- macOS (uses iTerm2's Python API)
- Python 3.8+
- Claude Code CLI
git clone https://github.com/bfeld/claude-iterm-visual-feedback.git
cd claude-iterm-visual-feedback
./install.sh-
Enable iTerm2 Python API:
- iTerm2 → Preferences → General → Magic → Enable Python API ✓
-
Create the scripts directory:
mkdir -p ~/.claude/iterm -
Copy the scripts:
cp window_color.py typing_monitor.py animate_title.py ~/.claude/iterm/ -
Create Python virtual environment:
cd ~/.claude/iterm python3 -m venv .venv .venv/bin/pip install iterm2
-
Configure Claude Code hooks - Add to
~/.claude/settings.json:{ "hooks": { "UserPromptSubmit": [ { "matcher": "*", "hooks": [ { "type": "command", "command": "~/.claude/iterm/.venv/bin/python3 ~/.claude/iterm/animate_title.py start" }, { "type": "command", "command": "~/.claude/iterm/.venv/bin/python3 ~/.claude/iterm/typing_monitor.py stop" } ] } ], "Stop": [ { "matcher": "*", "hooks": [ { "type": "command", "command": "~/.claude/iterm/.venv/bin/python3 ~/.claude/iterm/window_color.py white" }, { "type": "command", "command": "~/.claude/iterm/.venv/bin/python3 ~/.claude/iterm/animate_title.py stop" }, { "type": "command", "command": "~/.claude/iterm/.venv/bin/python3 ~/.claude/iterm/typing_monitor.py start" } ] } ] } }
The scripts use process tree matching to identify which iTerm session Claude Code is running in. This works even when ITERM_SESSION_ID isn't available to hook subprocesses.
- Walk up the process tree from the script
- Match against iTerm session PIDs via the Python API
- Target only that specific session
For iTerm profiles with "Use separate colors for light and dark mode" enabled, the scripts set both:
background_color(Light Mode)background_color_dark(Dark Mode)
| Script | Purpose |
|---|---|
window_color.py |
Flash screen white/black for a specific session |
typing_monitor.py |
Daemon that detects keystrokes and triggers color change |
animate_title.py |
Moon phase animation in session title bar |
In animate_title.py, adjust:
REFRESH_RATE = 0.1 # seconds between frames (default: 100ms)In animate_title.py, modify the animation arrays:
MOON_PHASES = ['🌑', '🌒', '🌓', '🌔', '🌕', '🌖', '🌗', '🌘']
END_ANIMATIONS = [STARS, HOURGLASS, RAINBOW, FIRE]In window_color.py, modify BASE_COLORS_255:
BASE_COLORS_255 = {
"white": (255, 255, 255), # Flash color
"black": (0, 0, 0), # Return color
# Add custom colors...
}-
Check iTerm2 Python API is enabled:
- iTerm2 → Preferences → General → Magic → Enable Python API
-
Test the scripts manually:
~/.claude/iterm/.venv/bin/python3 ~/.claude/iterm/window_color.py white # Should flash your current pane white
The scripts use process tree detection. If this fails:
- Check if
ITERM_SESSION_IDis set in your shell - Verify iTerm2 Python API can enumerate sessions
iTerm may be showing session names instead of window titles. The updated animate_title.py uses session.async_set_name() which should work with most iTerm configurations.
MIT License - Feel free to use, modify, and share!
Developed for use with Claude Code by Anthropic.