[BUG] Regression in 2.1.163: cursor desync + progressive frame corruption in iOS SSH terminal (Secure ShellFish) — bisected

Open 💬 7 comments Opened Jun 7, 2026 by WanIsmail

Summary

Starting exactly in v2.1.163, Claude Code's TUI corrupts in the iOS SSH client
Secure ShellFish: the hardware cursor sticks at column 0 of the single-line input
(on the glyph) while typed text renders after it, and over time frames shred —
stale statusline copies stack up, and strings from different frames interleave at
character level (e.g. bypasspermissionsuon, shift+tabetodcycle). Long sessions
end up displaying fragments rendered ~an hour apart simultaneously.

v2.1.162 and below render perfectly in the identical stack.

Bisect (each step = fresh launch, type one line, observe caret)

| Version | Result |
|---|---|
| 2.1.109 | ✅ correct |
| 2.1.110 | ✅ correct |
| 2.1.152 | ✅ correct |
| 2.1.160 | ✅ correct |
| 2.1.162 | ✅ correct |
| 2.1.163 | ❌ caret stuck at col 0 |
| 2.1.165 | ❌ stuck |
| 2.1.167 / 2.1.168 | ❌ stuck + progressive frame corruption |

(2.1.164 was never published — 404 on native installer and npm.)

Environment

  • iPad → Secure ShellFish (latest as of 2026-06-07) → SSH → Ubuntu VM (kernel 6.8), zsh
  • Reproduces identically through tmux 3.4, zellij 0.44.3, tmux+zellij nested, and bare SSH (no multiplexer)
  • TERM=xterm-256color; native installer build
  • Not affected: Codex CLI, Cursor CLI, OpenCode — same host, same client, flawless
  • ShellFish shell-integration hooks NOT installed; mouse disabled (CLAUDE_CODE_DISABLE_MOUSE=1) and

CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN=1 tested — no effect; CLAUDE_CODE_DECSTBM=0 no effect

Evidence the final stream state is still consistent (strict emulators tolerate it)

Headless reference test on the affected version: ran claude (2.1.168) in a detached tmux,
typed 17 chars programmatically, asked tmux for its parsed hardware cursor:

tmux display -p '#{cursor_x},#{cursor_y}' → 19,13 # exactly end-of-text after "❯ " + 17 chars

capture-pane -e shows no reverse-video cell — Claude Code draws no caret of its own and
relies on the hardware cursor. So ≥2.1.163 emits something order/timing/sequence-wise
that a strict emulator (tmux) converges on but ShellFish's emulator does not — intermediate
cursor states are now visible/sticky where ≤2.1.162 they were not.

The ask

2.1.162 renders correctly in this client; 2.1.163 does not — please diff the
renderer/terminal-output code between those two releases.
The bisect is the
load-bearing evidence; everything else below is supporting context.

Possibly-related 2.1.163 changelog entries

  • "Fixed terminal misalignment and a multi-second hang when exiting the agent view by pressing Esc" (renderer cursor math)
  • "Fixed keyboard input becoming permanently unresponsive after a paste operation whose end marker is dropped by the terminal" (terminal state machine)

Repro

iOS Secure ShellFish → SSH to Linux → claude (≥2.1.163) → type one line at the prompt.
Caret stays at column 0. Add a newline (Ctrl-J) or let input wrap — caret recovers.
Leave a session streaming for a while — statusline rows duplicate and frames interleave.

Workaround

Pin 2.1.162 (claude install 2.1.162) for sessions accessed from this client.

(Screenshots attached: stuck caret on 2.1.168; clean caret on 2.1.109/110/162 same stack;
frame-corruption shot showing fragments timestamped ~55 minutes apart on screen together.)

View original on GitHub ↗

This issue has 7 comments on GitHub. Read the full discussion on GitHub ↗