Wire protocol v0 · open sourceQUIC / UDP 7322 · TLS WebSocket / TCP 7322

The terminal protocol that never drops.

Like ssh, but the session survives the network. Like mosh, but it forwards ports, runs commands and works where UDP is blocked.

osewa runs your remote shell over QUIC when UDP gets through and TLS WebSocket when it doesn't. The session lives on the host, not in the connection, so a dead link is just a reconnect.

Get started →Star on GitHubBenchmarks
$ history
1995 ssh devbox
2012 mosh devbox
2026 osewa attach devbox
$
12×
faster key echo than ssh during a download on cellular
0.4 s
to resume after sleep or an IP change (mosh 1.1 s, ssh dies)
4×
faster than ssh to connect and run a command, Thailand → Tokyo
14.3 MB
memory per idle session on the host, half of ssh's
§1 Why now

ssh and mosh were built for networks we no longer have.

Bandwidth is no longer the hard part. Soon almost anywhere will have at least Starlink, and even that carries tens of Mbit/s. What hurts now is latency, deep buffers, switching networks and blocked UDP. And on the other end there's often a coding agent, redrawing a full-screen TUI for hours while you check in from a laptop or a phone.

ssh1995
Built for one steady wired link. The session is its TCP connection, so it dies when the network changes, and under load each key waits behind the download.
mosh2012
Bet on saving scarce bandwidth with its own emulator. When that emulator reads output differently from your terminal you get garbled text, and it's UDP only, with no forwards and no scrollback.
osewa2026
Built for plenty of bandwidth with bad latency and queues. The session lives on the host with Ghostty's terminal engine, and forwards and exec share the same connection, over QUIC or TCP.
Side by side
sshmoshosewa
SessionDies with the TCP connectionSurvives roamingLives on the host: survives roaming, sleep and server restarts
TransportTCPUDP onlyQUIC, falling back to TLS over TCP
Screen on the hostNone, bytes are replayedIts own emulator, no scrollbacklibghostty-vt, Ghostty's terminal engine
Beyond the shellPort forwards, execTerminal onlyPort forwards and exec on the same connection
Kitty protocolsPassed throughNoKeyboard; graphics with animation, kept on the host and redrawn on reconnect; clipboard reads and paste events
Modern OSCPassed throughFewYes: hyperlinks, cwd, prompt marks, agent status (OSC 7501)
§2 Benchmarks

On a bad network, keys echo 8–100× faster than ssh.

Key echo while a download runs on the same connection

osewa · bestssh
Cellular60 ms · deep buffer
138 ms
1,714 ms
12×
Wi-Fi20 ms · 1% loss
44 ms
374 ms
8×
1 Mbit/s100 ms · 1% loss
154 ms
no echo in 15 s →
>100×
05001,0001,5002,000 ms

Back after an IP change

Client moved to a new IP after 5 s offline. Time from the network coming back to a working session.

osewa
0.4 s
mosh
1.1 s
ssh
✕ session gone
never
00.51.01.52.0 s

Connect and run a command, 120 ms away

QUIC's 1-RTT handshake and a pinned device key, against ssh's key exchange and auth round trips.

osewa
388 ms
ssh
1,630 ms
04008001,2001,600 ms

Every lab result

osewamoshssh
TransportQUIC + TLS WebSocket, racedUDP only (SSP)TCP
Survives sleep / IP changeYes, resumes in 0.4 sYes, 1.1 sNo
Echo p50 during a download, cellular (60 ms, deep buffer)138 ms—1,714 ms
Echo p50 during a download, Wi-Fi (20 ms, 1% loss)44 ms—374 ms
Echo during a download, 1 Mbit/s (100 ms, 1% loss)154 ms—none within 15 s
Connect + run a command, 120 ms RTT388 ms—1,630 ms
Local echo predictionYesYesNo
Port forwarding, execYesNoYes
Works with UDP blockedYes, falls back to TCPNoYes
Bulk throughputEqual to ssh; ahead on lossy Wi-Fi (0.99 vs 0.92 MB/s)——

osewa over QUIC, its default, from the full run of 2026-10-31. Same container and ports for every side, netem-shaped links. Over TLS WebSocket, echo during a download was faster still on cellular (73 ms) and at 1 Mbit/s (125 ms). Reproduce: make bench-vs · make bench-mosh.

§3 Real world

Thailand to Tokyo, over the public internet.

From a Mac in Thailand to a 1-vCPU Linode in Tokyo, about 100 ms away over the public internet. osewa connects four times faster than ssh and six times faster than mosh, downloads at three times ssh's speed, and during the download echoes keys in 102 ms, as fast as idle. ssh's take 145.

Connect + run a command

osewa QUIC
311 ms
osewa WS
511 ms
ssh
1,337 ms
mosh
1,993 ms

Key echo during a download, p50 → p95

osewa QUIC
102 / 105
osewa WS
104 / 143
mosh
113 / 119
ssh
145 / 150
90125160 ms
● p50 · ○ p95 · differences under ~20 ms are path noise

Download, while typing / alone

osewa QUIC
30.55 / 39.67
osewa WS
27.28 / 27.26
ssh
11.55 / 11.96
mosh*
15.45 / n/a
010203040 MB/s
thick: while typingthin: alone* mosh's download is a separate ssh connection

With a fast path, keeping keys ahead of bulk costs osewa nothing: it downloads at three times ssh's speed and still echoes keys as fast as idle.

The setup

Client
Mac on a home line in Thailand
Host
Linode Nanode in Tokyo: 1 vCPU, 1 GB, Ubuntu 24.04
Path
The public internet, no VPN, about 100 ms round trip
Same rig
Every tool on the same path in the same session, median of 5 runs. ssh and mosh used sshd on port 2222, since some fresh connections to port 22 got no answer on this path

ssh's download swings a lot run to run here, so read the ssh and mosh download numbers as rough. osewa QUIC's download while typing ranged 15.8–39.9 MB/s across the runs; the WebSocket's held at 27 in every one.

Median of 5 runsosewa QUICosewa WebSocketsshmosh
Connect + run a command311 ms511 ms1,337 ms1,993 ms
Echo p50, idle99 ms101 ms110 ms114 ms
Echo p50 / p95 during a download102 / 105 ms104 / 143 ms145 / 150 ms113 / 119 ms
Download alone39.67 MB/s27.26 MB/s11.96 MB/sn/a
Download while typing30.55 MB/s27.28 MB/s11.55 MB/s15.45 MB/s

Echo is timed with prediction off, so it's the real round trip of a key. mosh carries only the terminal, so its download is a separate ssh connection beside the session, which is why it can beat ssh's own. Runs of 2026-10-31 with osewa-bench vs, server build 377ebff.

§4 Resource use

Light when idle. Honest about the cost.

osewa keeps the real screen, so it parses everything the program writes, where ssh just forwards bytes. That's host CPU on heavy output, and it's why a flood can't slow your program down.

Host memory, idlelower is better
osewa
14.3 MB
mosh
20.6 MB
ssh
27.4 MB
Client memory, idlelower is better
osewa
6.9 MB
mosh
14.3 MB
ssh
8.2 MB
Host CPU per MB, log tail50 kB/s · ssh wins here
osewa
302 ms
mosh
434 ms
ssh
66 ms
Host CPU per MB, floodoutput as fast as it comes
osewa
6 ms
mosh
45 ms
ssh
12 ms

Same container and run as the lab benchmarks, osewa over TLS WebSocket. An idle session uses under 0.1% CPU on both ends for all three. In a flood the program wrote 173 MB/s under osewa, 22 MB/s under mosh and 1.2 MB/s under ssh.

§5 Quick start

ssh once. osewa after that.

osewa login uses ssh one time to install itself on the host and enroll your device with an Ed25519 key. From then on it runs on its own port, and even updates go over osewa. Linux and macOS hosts.

$ osewa login --service me@devbox # install, enroll, run as a user service
$ osewa attach devbox # attach to (or create) a session
$ osewa forward devbox 3000 # forward localhost:3000
$ osewa exec devbox -- make test # run a command, no terminal
$ osewa update devbox # upgrade the host over osewa
§6 Roadmap

A transport any terminal can ride, then a mux on top.

✓
M0 · shipped
Wire protocol v0An open contract for frames, sessions and channels, in docs/PROTOCOL.md.
✓
M1 · shipped
Sessions that surviveQUIC with TLS WebSocket fallback, sessions held on the host, exactly-once input, keystrokes ahead of bulk, the latest screen on a slow link.
✓
M2 · shipped
Agent-awareStatus from the agent (OSC 7501), colour queries answered on the host, kitty keys and graphics.
M3 · release · you are here
Release: the osewa CLIOne binary for macOS and Linux. osewa login once over ssh, then attach, forward, exec and update over osewa.
M4 · next
In the Moshi apposewa as a transport in Moshi on iOS and Android, beside mosh. The first app to ride it: resume, forwarding, and no UDP needed.
M5 · later
MuxTabs, splits and workspaces held on the host, like tmux. Every pane is its own session with its own flow control.
M6 · later
Every screenA terminal, a desktop app or a phone attaches to the same layout. One terminal engine between you and the program.
Transportusable on its own, today
Muxone client of the same protocol
§7 How it works

Separate the session from the transport. Then make the transport hard to kill.

01 · hybrid carrier

QUIC and TLS WebSocket, raced on every connect

The same frames run on both. QUIC gets a 300 ms head start; if UDP is blocked, the WebSocket wins. Nothing to configure.

client
QUIC · UDP1 RTT
TLS WebSocket · TCP+300 ms
host
connected over QUIC in one round trip
02 · the host keeps the real screen

Connections come and go. The session stays.

Each terminal runs in its own process on the host and keeps the exact screen with libghostty-vt. Reconnecting sends one snapshot, not a replay. Pings spot a dead path in about a second, and unacked keys are resent.

laptopwi-fiasleep5G
host · sessionPTY alivescreen kept · 0 keys lost
~1 sdead path detected
500 msbetween redial races
exactly onceevery keystroke
03 · keystrokes first

A download can't bury your echo

Frames go out by priority: control, terminals, exec, then forwards. While you type, bulk is held to the path's bandwidth-delay product plus 40 ms of queue. Each forward gets its own QUIC stream, so a lost packet in a download never blocks a key.

one TCP stream · keys queue behind the download
k
deep buffer: the queue grows until each key waits behind it
echo p50, cellular, during a download1,714 ms
§8 Built for agents

The agent keeps working. You check in when it needs you.

A coding agent runs for hours in a full-screen TUI, and you check in from wherever you are. osewa keeps that screen on the host in libghostty-vt, so what the agent's terminal does reaches you whole on every reconnect. The host answers the agent's queries itself, so it never waits on a client that's asleep.

Status, from the agent to you (OSC 7501)

$ osewa ls devbox
ID TITLE IDLE STATUS
api claude-code 2h working 40%blocked: permission — Apply?done 
web codex 14m working
logs tail -f 3d -

osewa keeps each session's status on the host. When you attach, a blocked or done agent shows a one-line notice. A new prompt (OSC 133) ends a working or blocked status.

What the agent's output may do

agenthostyour terminal
reaches
✓ drawn
Prompt marks, links, titles, current directory, pointer shape, notifications (live only), clipboard copies, kitty keys, kitty graphics and kitty paste events.
answered
asleep is fine
Colour and light/dark queries are answered on the host, from your terminal's last known colours. Status is kept there too.
dropped
✕ never sent
Other OSCs, DCS (including tmux passthrough), APC, PM and SOS. Clipboard reads need --clipboard-read, and only the owner gets them.

Every sequence: what mosh and osewa do with it

SequenceWhat it ismosh 1.4osewa
OSC 7501Agent status: working, blocked, done, idle, with progress and a messageDroppedKept per session: osewa ls shows it, and attach shows a notice when the agent is blocked or done
OSC 133Prompt marksDroppedPassed to your terminal; a new prompt ends a working or blocked status
OSC 9, OSC 777Desktop notificationsDroppedSent to your terminal as one, live only, never replayed on reconnect
OSC 52ClipboardCopies, selection c only; no readsCopies reach your clipboard; reads only with --clipboard-read, owner only
OSC 8HyperlinksDroppedKept in the screen and passed through
OSC 7Current directoryDroppedPassed through
OSC 0, 1, 2Window and tab titlesPassed through, cut to 256 charactersPassed through, control characters stripped
OSC 4, 10, 11, 12, 21 and resets 104, 110–112Palette, foreground, background and cursor colorsQueries go unanswered; colors the program sets are droppedYour terminal's colors answer the agent's queries; colors it sets are drawn on your terminal and reset on detach
DSR 996, mode 2031Light or dark appearanceNo answerAnswered from your terminal's, and reported when it changes
OSC 22Pointer shapeDroppedYour terminal's pointer follows
Kitty keyboard (CSI u)Unambiguous keys and modifiersNot supportedSupported
Kitty graphics (APC G)Images, including animationDroppedDrawn on terminals that draw them (kitty, Ghostty, WezTerm; --graphics to choose): kept on the host and redrawn on reconnect; images sent inline only
OSC 5522Kitty's clipboard protocolDroppedReads wait for the owner like OSC 52's, text only, with --clipboard-read; pastes arrive as Kitty paste events when the program asks for them

Everything else (other OSCs, DCS including tmux passthrough, APC, PM, SOS) is dropped before it reaches your terminal. The remote program doesn't get to command it. mosh column: mosh 1.4.0, its latest release, read from its source; its main branch has since added OSC 8 hyperlinks, not yet released.

FAQ

Does it replace ssh?

For interactive work, yes. You need ssh once, to enroll; after that osewa runs on its own port (TCP and UDP 7322).

What if UDP is blocked?

The client races QUIC against a TLS WebSocket and takes whichever connects first. With UDP blocked, that costs 300 ms per connect.

How is it different from mosh?

mosh keeps sessions alive and predicts echo too, but it is UDP-only and carries only the terminal. osewa adds TCP fallback, port forwarding and exec, and keeps keystrokes ahead of bulk data on the same connection.

Does it work behind a VPN or tailnet?

Yes. QUIC starts with 1200-byte packets to fit a WireGuard MTU, and our Mac-to-Mac runs to Tokyo, in the README, were taken over Tailscale.

Is it as safe as ssh?

The cryptography is: TLS 1.3 only, and both ends prove who they are with Ed25519 keys on every connection, no passwords. The server's key comes to you during enrollment over ssh, so there's no “trust this host?” prompt, and a revoked device is out on its next connect. Where ssh is ahead is age: OpenSSH has decades of audits and osewa has none yet, it adds a second open port, and its device key is a plain file (mode 0600), not one behind a passphrase or an agent.

Can a program on the host reach into my terminal?

Only through what osewa lets past. The screen is parsed on the host, and only known sequences reach your terminal: other OSCs, DCS (including tmux passthrough), APC, PM and SOS are dropped, and titles lose their control characters. Clipboard reads go only to the session's owner, and only when they attached with --clipboard-read.