Fix Claude Code Terminal Enhanced Keyboard Mode (kitty Keyboard Protocol/modifyOtherKeys) Persisting After Exit — Ctrl-C/Ctrl-D Broken in Ghostty, Kitty, WezTerm, and tmux (v2.1.86 Fix)
After exiting Claude Code, the terminal remains stuck in enhanced keyboard input mode (kitty keyboard protocol and/or modifyOtherKeys/XTMODKEYS), causing Ctrl-C, Ctrl-D, and other control key combinations to produce raw escape sequences (e.g., '9;5u', '0;133u') instead of sending SIGINT and EOF. This affects all terminals that support enhanced keyboard protocols — Ghostty, Kitty, WezTerm, foot, and tmux sessions. The root cause is that Claude Code enables these protocols for its own key handling but does not restore the terminal to the previous state on exit or when spawning subprocesses. Anthropic staff (@ashwin-ant) confirmed the fix in v2.1.86. Three community-verified workarounds provide immediate relief: a one-shot printf escape sequence, a persistent Stop hook in settings.json, or the classic 'reset' command. This issue accumulated 63 reactions and 22 comments with confirmations across macOS, Linux, and multiple terminal emulators.
Symptoms
- Ctrl-C produces '9;5u' or '0;133u' escape sequences instead of sending SIGINT after exiting Claude Code
- Ctrl-D produces '0;133u', '0;5u', or similar CSI u sequences instead of sending EOF after exiting Claude Code
- Ctrl-W, Ctrl-Z, Ctrl-/, and other control key combinations stop functioning in the shell after Claude Code exits
- Pressing Ctrl-D at an empty bash/zsh prompt closes the terminal tab/window instead of exiting the shell normally
- Running 'reset' or opening a new terminal tab restores normal behavior, confirming the issue is terminal state corruption rather than shell misconfiguration
- Issue occurs inconsistently — some Claude Code sessions exit cleanly while others leave the terminal in broken keyboard mode
- Inside tmux, escape sequences differ from outside tmux (e.g., '0;133u' in tmux vs '0;5u' in bare terminal), requiring different escape sequence handling
Error signatures
Ctrl-C produces '9;5u'
Ctrl-D produces '0;133u'
Ctrl-D produces '0;5u'
modifiedOtherKeys not restored on exit
kitty keyboard protocol left enabled
terminal enhanced keyboard mode not disabled
Possible causes
- Claude Code enables the kitty keyboard protocol (CSI > flags u) for rich key event handling in its TUI but does not send the pop command (CSI < u) to restore the terminal's keyboard mode stack on exit. The protocol remains active, causing all subsequent keyboard input to be encoded as CSI u escape sequences instead of raw control characters
- Claude Code enables modifyOtherKeys / XTMODKEYS mode 2 (CSI > 4 ; 2 m) for its own key handling but does not restore the previous mode on exit or when spawning subprocesses (e.g., via $EDITOR). This leaves the terminal mapping Ctrl+key combinations to escape sequences
- Unlike the kitty keyboard protocol which supports progressive enhancement queries (CSI ? u), XTMODKEYS has no standard query mechanism to detect the current state, making it harder for applications to restore the original terminal configuration
- The issue is most visible in terminals that support enhanced keyboard protocols (Ghostty, Kitty, WezTerm, foot) and in tmux sessions where the escape sequence handling differs between the inner and outer terminal
- The bug was introduced when Claude Code added enhanced keyboard support for its TUI and was not present in earlier versions
Solutions
Permanent Fix: Upgrade to Claude Code v2.1.86 or Later
Anthropic staff (@ashwin-ant, Ashwin Bhat at Anthropic) confirmed the fix was shipped in Claude Code v2.1.86. The terminal's enhanced keyboard mode (both kitty keyboard protocol and modifyOtherKeys/XTMODKEYS) is now properly disabled on exit. This is the recommended permanent solution for all users. If you still see the issue on v2.1.86+, report it with your terminal emulator, OS, and reproduction steps.
- Check your current Claude Code version with claude --version
- Upgrade to v2.1.86 or later via npm (latest is recommended)
- Remove any Stop hook workaround after upgrading (it's no longer needed)
- Verify the fix by starting Claude Code in a terminal with enhanced keyboard support, exiting, and testing Ctrl-C
- If the issue persists on v2.1.86+, note your terminal emulator (Ghostty/Kitty/WezTerm), its version, and whether tmux is in use, then file a new issue
Commands
claude --version
npm install -g @anthropic-ai/claude-code@latest
npm install -g @anthropic-ai/claude-code@2.1.86
Risks
- Upgrading Claude Code may introduce unrelated behavior changes. Test in a non-critical project first
- Very low risk — v2.1.86 is a point release specifically fixing this keyboard protocol cleanup issue
Verification
- Step 1: Run `claude --version` → expect: version ≥ 2.1.86 (latest is v2.1.175 as of June 2026)
- Step 2: Start Claude Code in a terminal with enhanced keyboard support enabled (Ghostty, Kitty, or WezTerm with enable_kitty_keyboard=true) → expect: Claude Code starts normally
- Step 3: Exit Claude Code (`/exit`) → expect: returned to shell prompt
- Step 4: Press Ctrl-C → expect: '^C' displayed (SIGINT), NOT '9;5u' or any escape sequence
- Step 5: Press Ctrl-D at empty prompt → expect: shell exits normally (EOF sent), terminal window does NOT close unexpectedly
Persistent Fix: Automatic Terminal Restore via Claude Code Stop Hook
Configure a Claude Code Stop hook in ~/.claude/settings.json to automatically run the terminal restore escape sequence every time Claude Code exits. This eliminates the need to manually type the printf command after each session. The hook fires on every exit, including normal exits, crashes, and /exit commands. The combined escape sequence covers both kitty keyboard protocol and modifyOtherKeys for maximum compatibility.
- Open or create ~/.claude/settings.json
- Add a Stop hook with the combined kitty + modifyOtherKeys reset escape sequence
- For tmux users, use the tmux-wrapped version of the escape sequence
- The hook fires automatically on every Claude Code exit — no manual intervention needed
- Test by starting and exiting Claude Code, then verifying Ctrl-C works
Commands
mkdir -p ~/.claude
cat ~/.claude/settings.json 2>/dev/null || echo '{}'claude --version
Config examples
{
"hooks": {
"Stop": [{
"matcher": "",
"hooks": [{
"type": "command",
"command": "printf '\\e[<u\\e[>0m'"
}]
}]
}
}Risks
- The Stop hook runs a shell command on every exit. Ensure the command string is correct — a malformed escape sequence could leave the terminal in an unexpected state
- Tmux users must use the tmux-wrapped version: `printf '\ePtmux;\e\e[<u\e\e[>0m\e\\'` in the hook command
- The hook fires even when Claude Code crashes, which is the desired behavior for this fix
Verification
- Step 1: Verify Claude Code version with `claude --version` → expect: version displayed (any version — hook works regardless)
- Step 2: Add the Stop hook configuration to `~/.claude/settings.json` as shown in config_examples → expect: file saved with valid JSON (run `cat ~/.claude/settings.json | python3 -m json.tool` to validate)
- Step 3: Start a new Claude Code session (`claude`) → expect: Claude Code starts normally with no error about settings.json
- Step 4: Exit Claude Code (`/exit` or Escape) → expect: returned to shell prompt, hook executes silently in background
- Step 5: Press Ctrl-C → expect: '^C' displayed (normal SIGINT), NOT escape sequence. Press Ctrl-D → expect: sends EOF normally
Immediate Fix: Restore Terminal with One-Shot Escape Sequence
Send the appropriate escape sequence to pop the kitty keyboard protocol stack and disable modifyOtherKeys. This instantly restores normal Ctrl-C/Ctrl-D behavior without restarting the terminal. Works on any terminal that supports enhanced keyboard protocols. Three variants are provided: kitty-only, modifyOtherKeys-only, and combined (recommended).
- First, diagnose which protocol is active by pressing Ctrl-C and observing the output
- If output is '9;5u' or contains ';u', the kitty keyboard protocol is active — use the kitty pop command
- If output contains ';' but not 'u' (e.g., '9;5'), modifyOtherKeys is active — use the disable command
- For tmux users, wrap escape sequences with tmux passthrough syntax
- Verify Ctrl-C and Ctrl-D work normally after applying the fix
Commands
printf '\e[<u'
printf '\e[=0u'
printf '\e[<u\e[>0m'
printf '\ePtmux;\e\e[<u\e\\'
reset
Risks
- None — these escape sequences are standard and only affect the current terminal session
- Inside tmux, plain escape sequences are captured by tmux and not passed to the outer terminal. Use the tmux wrapper syntax: `printf '\ePtmux;\eESCAPE_SEQUENCE\e\\'`
Verification
- Step 1: After exiting Claude Code, press Ctrl-C → expect: raw escape sequence like '9;5u' or '0;133u' (confirms protocol is stuck active)
- Step 2: If output contains ';u' suffix, run `printf '\e[<u'` → expect: command executes silently (kitty protocol stack popped)
- Step 3: If output contains ';' but no 'u' suffix, run `printf '\e[>0m'` → expect: command executes silently (modifyOtherKeys disabled)
- Step 4: Press Ctrl-C → expect: '^C' displayed (normal SIGINT behavior, NOT escape sequence)
- Step 5: Press Ctrl-D at an empty prompt → expect: sends EOF (exits shell normally, does NOT close terminal window)
Agent JSON
Canonical machine-readable representation of this issue:
{
"issue_id": "e131a20e-740e-40c3-9497-a724d68005de",
"slug": "fix-claude-code-terminal-enhanced-keyboard-mode-kitty-keyboard-protocol-modifyotherkeys-persisting-after-exit-ctrl-c-ctr-dfkjnf",
"verification_status": "unverified",
"canonical_json": "https://codekb.dev/v1/issues/fix-claude-code-terminal-enhanced-keyboard-mode-kitty-keyboard-protocol-modifyotherkeys-persisting-after-exit-ctrl-c-ctr-dfkjnf"
}