PTY shell
Open
let shell = try await connection.openShell(
terminalType: "xterm-256color",
columns: 120,
rows: 32
) { event in
if case .standardOutput(let data) = event {
FileHandle.standardOutput.write(data)
}
}
try await shell.write("ls -la\n")
try await shell.write(Data([0x03])) // Ctrl-C
try await shell.close()
The event handler runs off the worker queue; do your own dispatch if you need to mutate UI state.
Resize
try await shell.resize(columns: 200, rows: 50)
Resizing emits SIGWINCH on the remote PTY. Resize early and often if you have a terminal view that the user can drag.
Events
SSHShellEvent has three cases:
.standardOutput(Data)— bytes from the PTY (merged stdout + stderr)..standardError(Data)— reserved for non-PTY shell backends; PTY shells merge stderr into stdout..closed(Int32)— channel exit status. The event handler will not be invoked again after this.
PTY modes
openShell requests a PTY from the remote with a fixed, conservative mode set. The current public API exposes the terminal type and dimensions; the line discipline itself is not configurable. SSHKit picks values that match what an interactive OpenSSH client would request, so you get the same behavior most users (and most remote shells) already expect.
What is on
- Echo — the remote echoes typed characters back (
ECHO,ECHOE,ECHOK,ECHOCTL,ECHOKE).ECHONLis off. Sensitive prompts (password, sudo) still suppress echo on the remote side as usual; that is the remote app’s call, not SSHKit’s. - Canonical input (
ICANON) — the remote line discipline buffers a line and lets the user edit it before delivery. Combined with the standard control characters:VINTR=^C,VQUIT=^\\,VERASE=DEL,VKILL=^U,VEOF=^D,VSUSP=^Z,VREPRINT=^R,VWERASE=^W,VLNEXT=^V,VDISCARD=^O. - Signals (
ISIG) —^Cand friends generate signals on the remote rather than being delivered as bytes. - Software flow control (
IXON,VSTART=^Q,VSTOP=^S) —^Spauses output,^Qresumes it. - CR/LF translation (
ICRNL,ONLCR,OPOST) — CR on input becomes NL, NL on output becomes CRLF.INLCRandIGNCRare off. - UTF-8 input (
IUTF8) — the line editor counts multibyte characters as one column. - Extended functions (
IEXTEN). - Reported baud —
ISPEEDandOSPEEDare reported as 38400.
Implications
- If you wire
SSHShellto a terminal view, do not echo the local keystrokes yourself — you would get double characters. The remote does the echo. - SSHKit doesn’t handle local line editing for you. Backspace, Ctrl-U, Ctrl-W, etc. are all interpreted on the remote side because canonical mode is on.
- For a raw / non-canonical session (full-screen editors, ssh-into-a-program that wants every byte), let the remote app put the TTY into raw mode the way it normally does; for example a remote shell can switch with
stty raw -echo, and full-screen programs likevimandtmuxset raw mode themselves. SSHKit does not currently expose a per-call override. - Resizing through
resize(columns:rows:)changes the reported window size only — it does not change any of the modes above.