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)
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.
SIGWINCHnever 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
The initial
stty sizematches the terminal. After resizing the terminal window,stty sizestill reports the original dimensions.This is also reproducible with Claude Code directly:
Expected behavior
After resizing the terminal,
stty sizeshould report the new dimensions and processes should receiveSIGWINCH. Claude Code should redraw its TUI to fit the new terminal size.Actual behavior
The remote PTY stays at its initial size. No
SIGWINCHis delivered. This can be confirmed by trapping the signal:The SSH client does send the
window-changerequest (confirmed viassh -vvv):But it's not applied to the remote PTY.
Agent Investigation
Explored the OpenShell codebase to understand the SSH proxy architecture:
openshell-sandboxcrate at/crates/openshell-sandbox/src/ssh.rsusing therusshcrate (v0.57)pty_request()stores the PTY config,start_shell()dispatches tospawn_pty_shell()which callsnix::pty::openpty()with the requestedWinsizewindow_change_request()handler exists and callsunsafe_pty::set_winsize()which usesTIOCSWINSZioctl on the PTY master fdSshHandlerstores the PTY master fd inself.pty_master: Option<std::fs::File>tokio::io::copy_bidirectional()in/crates/openshell-server/src/ssh_tunnel.rsThe infrastructure for handling
window-changeappears complete. The client sends the request, the server has the handler. Something in the path between receiving thewindow-changerequest and applyingTIOCSWINSZto the PTY master fd may be failing silently.Environment
SSH-2.0-russh_0.57.1)