[BUG] SessionStart hook with external command freezes REPL on Windows
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?
When a plugin defines a SessionStart hook with type: "command" that spawns an external process (either node or bash), the REPL becomes completely unresponsive on Windows after the second startup.
- The UI renders correctly (input box, model name visible)
- Keyboard input is completely ignored
- Ctrl+C has no effect — must force-kill the terminal
- The hook itself executes successfully (debug log shows "success")
- Only happens on 2nd+ launch (when
hasTrustDialogAccepted: truein~/.claude.json) - First launch (with trust dialog) always works fine
What Should Happen?
SessionStart hooks with type: "command" should not affect terminal input handling. The REPL should remain fully responsive after hook execution completes.
Error Messages/Logs
No errors in debug log. Hook completes successfully:
2026-02-06T18:16:53.578Z [DEBUG] Hook SessionStart:startup (SessionStart) success:
Skills synced to C:\Dev\Project\...\references
2026-02-06T18:16:53.672Z [DEBUG] [REPL:mount] REPL mounted, disabled=false
All initialization completes normally, but REPL is frozen after mount.
Steps to Reproduce
- Create a plugin with a SessionStart hook in
hooks/hooks.json:
```json
{
"hooks": {
"SessionStart": [{
"matcher": "startup",
"hooks": [{
"type": "command",
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/example.js\""
}]
}]
}
}
Where example.js is any simple script (e.g., console.log("hello"); process.exit(0);)
- Enable the plugin via .claude/settings.json with extraKnownMarketplaces
- Run claude in the project directory — first launch works (trust dialog shown)
- Exit Claude, open a new terminal, run claude again — REPL freezes
- Workaround: remove project entry from ~/.claude.json or empty the hooks
Diagnostic results:
┌─────────────────┬─────────────┬────────┐
│ Hook │ MCP Servers │ Result │
├─────────────────┼─────────────┼────────┤
│ node command │ None │ Frozen │
├─────────────────┼─────────────┼────────┤
│ bash command │ None │ Frozen │
├─────────────────┼─────────────┼────────┤
│ None (hooks {}) │ None │ Works │
├─────────────────┼─────────────┼────────┤
│ None (hooks {}) │ 4 servers │ Works │
└─────────────────┴─────────────┴────────┘
Claude Model
None
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.34
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
Windows Terminal
Additional Information
Root cause hypothesis: The child process spawned by the SessionStart hook corrupts the terminal's raw mode state on Windows. Both node and bash commands trigger this. The issue only manifests when
hasTrustDialogAccepted: true (2nd+ launch), suggesting the hook runs at a different point in the startup sequence when the trust dialog is skipped, which triggers the terminal state corruption.
Workaround: Empty the hooks in hooks.json: { "hooks": {} }
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗