Skip to content

bug(ssh): window-change requests not applied to remote PTY — terminal resize broken #543

Description

@chenstanilovsky

Description

When connecting to a sandbox, the terminal is allocated with the correct initial dimensions but does not resize when the terminal window changes size. SIGWINCH never reaches the process inside the sandbox.

This directly impacts Claude Code — its TUI renders at the initial terminal size and never redraws when the terminal is resized, leaving the interface clipped or misaligned.

Reproduction steps

# 1. Create a sandbox
openshell sandbox create --name test

# 2. Connect to it
openshell sandbox connect test

# 3. Inside the sandbox, check initial size (correct)
stty size

# 4. Resize your terminal window

# 5. Check size again (unchanged — should have updated)
stty size

The initial stty size matches the terminal. After resizing the terminal window, stty size still reports the original dimensions.

This is also reproducible with Claude Code directly:

# 1. Connect and launch Claude Code
openshell sandbox connect test
claude

# 2. Resize the terminal window — Claude Code's TUI does not redraw to the new size

Expected behavior

After resizing the terminal, stty size should report the new dimensions and processes should receive SIGWINCH. Claude Code should redraw its TUI to fit the new terminal size.

Actual behavior

The remote PTY stays at its initial size. No SIGWINCH is delivered. This can be confirmed by trapping the signal:

trap "echo WINCH" WINCH
# Resize terminal window — "WINCH" is never printed

The SSH client does send the window-change request (confirmed via ssh -vvv):

debug2: client_check_window_change: changed
debug2: channel 0: request window-change confirm 0

But it's not applied to the remote PTY.

Agent Investigation

Explored the OpenShell codebase to understand the SSH proxy architecture:

  • The SSH server is implemented in the openshell-sandbox crate at /crates/openshell-sandbox/src/ssh.rs using the russh crate (v0.57)
  • PTY allocation is fully implemented: pty_request() stores the PTY config, start_shell() dispatches to spawn_pty_shell() which calls nix::pty::openpty() with the requested Winsize
  • The window_change_request() handler exists and calls unsafe_pty::set_winsize() which uses TIOCSWINSZ ioctl on the PTY master fd
  • The SshHandler stores the PTY master fd in self.pty_master: Option<std::fs::File>
  • The gateway tunnels SSH traffic bidirectionally via tokio::io::copy_bidirectional() in /crates/openshell-server/src/ssh_tunnel.rs

The infrastructure for handling window-change appears complete. The client sends the request, the server has the handler. Something in the path between receiving the window-change request and applying TIOCSWINSZ to the PTY master fd may be failing silently.

Environment

  • openshell 0.0.13
  • Linux aarch64
  • OpenSSH client 9.2p1
  • russh 0.57.1 (server banner: SSH-2.0-russh_0.57.1)

Activity

  1. self-assigned this
    on Mar 23, 2026
  2. added 3 commits that reference this issue on Mar 24, 2026
    834c075
    72892c7
    8c9f987
  3. added 2 commits that reference this issue on Mar 30, 2026
    666bdfa
    c0fe697
  4. added a commit that references this issue on Apr 8, 2026
    e14d1b7
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions