Native terminal for iPhone and iPad

An iOS terminal that keeps your session when the network drops.

StoicTerm speaks mosh on the wire, with plain SSH as the fallback. Switch Wi-Fi to cellular, lock the phone, lose signal in a tunnel: your shell is still there.

TestFlight soon, then the App Store. One email when the beta opens, nothing else.

Read the protocol spec

Network

Wi-Fi, 11 ms round trip. Client 10.0.0.7:51822 to devbox, udp 60001.

The session belongs to you, not to the connection.

Mosh keeps the terminal state on the server and syncs it to the phone over UDP. A new address, a sleeping radio, a dropped packet: none of them ends the session. StoicTerm adds the parts a phone needs.

  • Roams between networksWi-Fi to cellular changes your IP address. The server accepts the first authenticated datagram from the new address and carries on. No reconnect, no new login.
  • Survives sleep and backgroundingiOS suspends the app; the server keeps the session. On foreground StoicTerm sends a heartbeat, shows how long since the last contact, then resyncs the screen in one round trip.
  • Stays current on a bad linkMosh syncs the newest screen, not a backlog of bytes. On a lossy link you skip straight to what the shell shows now, and ^C is not stuck behind old output.
One session, three networks: the phone hops stations, the link re-anchors to the new address, and in the gap the server simply waits.

The keys iOS forgot, and the bytes they send.

A row above the keyboard: esc, tab, ctrl, arrows and ^C. Press one here to see what goes down the wire. Arrows are sent as SS3 sequences in mosh mode and CSI sequences in SSH mode; ctrl modifies the next key.

Mode

Mosh carries each keystroke inside an encrypted UDP datagram and keeps resending until the server acknowledges it.

Key
Press a key above
Bytes
—
Sequence
—
On the wire
—

Sent

  1. Nothing sent yet.

Keys are made on the phone and never leave the Keychain.

Generate an Ed25519 key in the app and only the public half ever goes anywhere. Already have keys? Import OpenSSH Ed25519, RSA or ECDSA files. Password login works too, for hosts that insist.

Generate an Ed25519 key

  • Private key stays in the KeychainGenerated on the device, used from there, never written to a file you could paste by mistake.
  • Import what you haveOpenSSH Ed25519, RSA and ECDSA keys, with or without a passphrase.
  • Password login when you mustFor the host that still asks. Nothing is stored unless you say so.

First connection to a new host

devbox is new to this device

The host's ED25519 key fingerprint is

SHA256:06OfHU8dDSdL8yPeWhcNb9IF3wC5k0orl5HwjLBMaWi

Compare it with the server before trusting. StoicTerm will remember it and warn you if it ever changes.

Tabs for every host. Split view and a real keyboard on iPad.

Each tab holds its own session, mosh or SSH. On iPad, put two hosts side by side, type on a hardware keyboard with ctrl and esc as real keys, and pinch to zoom the text.

escdeletetabreturnctrlshiftfnoptcmdcmdopt←↑↓→
Two sessions on one screen, three tabs in the strip, and a keyboard where ctrl and esc are keys again.
  • TabsOne session per tab, mosh or SSH, each with its own host and theme. Close a tab and only that session ends.
  • Hardware keyboardModifier keys work as modifiers. The accessory bar steps aside when a keyboard is attached.
  • Pinch to zoom, themes for day and nightThe native renderer rescales text without reflowing the session. Pick a theme per tab.

Mosh, re-implemented from the written spec.

StoicTerm's mosh client is a clean-room implementation: no code from the reference project, only a written specification of the protocol and its behaviour, and a test suite that checks the result against a stock mosh-server.

The cipher is AES-128-OCB3 running on Apple's CommonCrypto, checked against the test vectors in RFC 7253. The terminal itself is a native renderer, not a WebView, so scrolling, selection and pinch zoom behave like the rest of iOS.

The protocol spec

The specification covers the datagram format, the OCB3 construction, the state-sync diff rules and the roaming handshake. It ships with the beta; the datagram layout below is the summary.

What StoicTerm's mosh client is made of
TransportUDP, state-synchronization protocol
CipherAES-128-OCB3 on CommonCrypto
VerificationRFC 7253 test vectors, stock mosh-server interop
ServerUnmodified mosh-server, started over SSH
FallbackPlain SSH with OpenSSH keys or a password
RendererNative, no WebView
Key storageiOS Keychain
mosh datagram, one UDP packet
┌─ nonce 8 B ─┬── AES-128-OCB3 ciphertext ──┬─ tag 16 B ─┐

nonce      8 B   direction bit + 63-bit sequence, in clear
timestamp  2 B   sender clock in ms, for RTT estimates
ts-reply   2 B   echo of the peer's last timestamp
payload    n B   state diff (protobuf TransportInstruction)
tag       16 B   OCB3 authentication tag

Questions before you install.

Does my server need anything?

For mosh, the host needs mosh-server installed; it ships in most package managers as mosh. StoicTerm starts it over SSH, the same way the desktop client does, then switches to UDP. For plain SSH, nothing extra.

Does it run on iPad?

Yes. Split view with two sessions, a hardware keyboard with ctrl, esc and arrows as real keys, and the same tabs as on the phone.

What about Android?

Later. iPhone and iPad come first. Nothing is scheduled yet.

What happens when I lock the phone?

iOS suspends the app and the server keeps the session. When you come back, StoicTerm sends a heartbeat, shows how long it has been since the last contact, and resyncs the screen in one round trip.

Is it compatible with the mosh I already run?

Yes. It speaks the same UDP protocol to a stock mosh-server. The client is a clean-room implementation from a written spec, and its AES-128-OCB3 is checked against the RFC 7253 test vectors.

Can I try it without a server?

Yes. The app includes an offline “Try the terminal” demo, so you can test the keyboard, the accessory bar and the renderer before connecting anywhere.

Where do my keys live?

Ed25519 keys generated in the app go into the iOS Keychain, and imported OpenSSH keys are stored the same way. Only public keys ever leave the device.

TestFlight opens soon. The App Store follows.

Leave an email and you get the invite when the beta opens. No newsletter, no drip, no sharing.