[BUG] Stop hook fires on every response turn, not session exit — breaks interactive workflows
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
The Stop hook event fires after every agent response completion, not only on session termination. Any script attached
to the Stop hook (interactive dialogs, cleanup tasks, backup routines) interrupts the user mid-workflow on every
response turn.
What Should Happen?
Stop should fire once when the session actually ends — /clear, /stop, window close, or process termination. It should
not fire on every response turn.
Alternatively, the distinction between "response turn completed" and "session ending" should be documented clearly,
with separate events for each.
Current workaround
Migrating to SessionEnd (which does fire only on actual session termination) resolves the issue. However:
- The Stop event name implies session-level semantics, not turn-level
- Most users building hooks will expect Stop to mean "session is stopping"
- The current behavior is undocumented and surprising
Impact
This is a significant barrier for users building agentic workflows with hooks. Any automation attached to Stop —
backups, cleanup, logging, notifications — fires repeatedly during normal conversation. For users running interactive
scripts (macOS dialogs, terminal prompts), it creates a disruptive UX that breaks flow during multi-turn work like code
reviews, brainstorming sessions, and iterative development.
The issue compounds with voice mode and party-style multi-agent patterns where turns are frequent and the user is not
at the keyboard to dismiss dialogs.
Proposed fix
Either:
- Change Stop semantics to fire only on session termination (breaking change, but matches user expectation)
- Document the distinction clearly and recommend SessionEnd for session-exit hooks in the hooks documentation
- Add a reason field to the Stop hook input so scripts can distinguish between turn completion and session exit
Error Messages/Logs
Steps to Reproduce
- Add a Stop hook in ~/.claude/settings.json:
"Stop": [{ "hooks": [{ "type": "command", "command": "osascript -e 'display dialog \"Stop fired\"'" }] }]
- Start a session, send a message, get a response
- The dialog appears immediately after Claude's response — not on session exit
- Send another message. Dialog appears again after the next response.
- In multi-turn workflows (party mode, Q&A, iterative design), the dialog fires on every single turn.
Claude Model
None
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.81
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
VS Code integrated terminal
Additional Information
_No response_
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗