# Rewrite: Hook-based detection architecture ## Task Replaced the unreliable macOS accessibility tree polling approach with Cursor's native hooks API for detecting when the agent needs user attention. ## Problem The a11y-based approach had fundamental issues: - Cursor's "Stop" button during agent generation is NOT exposed in the accessibility tree - Approval button text persists in chat history, causing false positives - Required complex baseline tracking and state machine to mitigate, still unreliable ## Solution Switched to Cursor's lifecycle hooks (`preToolUse`, `stop`) which fire directly from Cursor when: - The agent wants to use a tool (shell command, file write, etc.) that may need approval - The agent loop completes (task finished, waiting for next prompt) Architecture: Hook script → Unix domain socket → Daemon → Window flash overlay ## Changes - **New**: `hooks/notify.py` — hook script that sends workspace/event info to daemon socket - **New**: `src/cursor_flasher/windows.py` — window discovery and geometry (a11y used only for positions) - **Rewritten**: `src/cursor_flasher/daemon.py` — Unix socket listener instead of a11y polling - **Rewritten**: `src/cursor_flasher/overlay.py` — single brief flash instead of continuous pulse - **Rewritten**: `src/cursor_flasher/cli.py` — added `install`/`uninstall` commands for hook management - **Rewritten**: `src/cursor_flasher/config.py` — simplified config (no sound, no polling settings) - **Deleted**: `detector.py`, `state.py`, `sound.py`, `scripts/` directory - **Rewritten**: All tests for new architecture (13 tests passing) - **Updated**: `README.md`, `.gitignore`, `pyproject.toml` (bumped to 0.2.0) ## Follow-up - The daemon is running and hooks are installed globally at `~/.cursor/hooks.json` - Hooks fire on every `preToolUse` — could add matcher filtering if too noisy - No sound from cursor-flasher; relies on Cursor's built-in sound