Major changes: - Add StyleConfig dataclass with independent color, width, opacity, duration, pulse_speed, sound, and volume per mode (running/completed) - Replace flat flash_*/sound_*/play_on config with running: and completed: YAML sections - Replace CGEventTap (silently fails in forked daemon) with CGEventSourceSecondsSinceLastEventType polling for reliable input-based pulse dismissal when Cursor is already frontmost - Update overlay, sound, and daemon to pass StyleConfig per call - Rewrite tests for new config shape and dismiss mechanism Made-with: Cursor
3.4 KiB
3.4 KiB
cursor-flasher
Flash a colored border on the Cursor IDE window when the AI agent needs your attention — tool approval, questions, or task completion.
How It Works
Uses Cursor hooks for reliable detection:
preToolUse— fires when the agent wants to run a shell command, write a file, or use any tool that may need approval. Pulses the border continuously and plays a sound until you click the Cursor window.stop— fires when the agent loop ends. Flashes the border once, briefly.
Only tools in the approval_tools list trigger the pulse (default: Shell, Write, Delete). Auto-approved tools like Read and Grep are ignored.
Prerequisites
- macOS
- uv
- Cursor IDE
- Accessibility permission for your terminal (System Settings → Privacy & Security → Accessibility)
Installation
# Clone and install
git clone <repo-url> && cd cursor-flasher
uv sync
# Install Cursor hooks (global, applies to all projects)
uv run cursor-flasher install
# Start the daemon
uv run cursor-flasher start
The install command copies the hook script to ~/.cursor/hooks/ and adds entries to ~/.cursor/hooks.json. Cursor auto-reloads hooks.
Usage
uv run cursor-flasher start # background daemon
uv run cursor-flasher start --foreground # foreground (for debugging)
uv run cursor-flasher status
uv run cursor-flasher stop
Configuration
Optional config file at ~/.cursor-flasher/config.yaml:
running: # approval pulse (continuous until you interact)
color: "#FF9500" # border color (hex)
width: 4 # border thickness in pixels
opacity: 0.85 # max border opacity
pulse_speed: 1.5 # pulse cycle speed in seconds
sound: "Glass" # macOS system sound ("" to disable)
volume: 0.5 # 0.0 to 1.0
# sounds: Basso, Blow, Bottle, Frog, Funk, Glass, Hero,
# Morse, Ping, Pop, Purr, Sosumi, Submarine, Tink
completed: # agent stop flash (brief fade-in/out)
color: "#00FF00" # different color for completion
width: 4
opacity: 0.85
duration: 1.5 # flash duration in seconds
sound: "" # no sound by default (Cursor plays its own)
volume: 0.0
flash:
mode: "screen" # "window", "screen", or "allscreens"
# Tools that trigger the pulse + sound (approval mode).
# Others are silently ignored (e.g., Read, Grep, Glob, Task).
approval_tools:
- Shell
- Write
- Delete
general:
approval_delay: 2.5 # seconds to wait before pulsing (filters auto-approvals)
cooldown: 2.0 # minimum seconds between flashes
Each mode (running and completed) has its own color, border style, and sound settings. Set sound: "" to disable sound for a particular mode.
Uninstall
uv run cursor-flasher uninstall
uv run cursor-flasher stop
Troubleshooting
Flashing on every tool call (too noisy):
- Edit
~/.cursor-flasher/config.yamland narrow downapproval_toolsto justShell.
No flash at all:
- Check daemon:
uv run cursor-flasher status - Check hooks installed:
ls ~/.cursor/hooks/cursor-flasher-notify.py - Check Cursor Settings → Hooks tab for execution logs
Pulse doesn't stop:
- Click the Cursor window to bring it to focus — the pulse auto-dismisses when Cursor is the frontmost app.