A native terminal for Apple platforms

Written in Swift.
Built for your Mac.

A Swift 6.4 terminal core with libghostty behavioral parity, rendered through Metal and CoreText. Native AppKit on macOS and UIKit on iPhone and iPad, with shells that outlive the window.

mise install && mise run app

macOS 27+ · iOS & iPadOS · visionOS · tvOS

Sessions that outlive the window.

The agent keeps the shell. Windows come and go.

SWIFTMUX WORKSPACE · YOUR MAC
~/code/my-project

# Every window is a SwiftMux workspace.

❯swmux new -s work

✓swiftmux-agent owns the PTY

✓Pane frames rendered by Metal

✓TERM=swmux-256color

❯swmux attach -t work

Reattached. The shell kept running while no window was open.

persistent workspaceprefix C-b

Roaming SSH over QUIC

iPhone and iPad clients survive network changes.

RST/1

Illustrative session · inside Swiftty, with the SwiftMux agent installed

Tested against real programs.
Recorded and replayed.

sh vim less tmux top SSH Metal

Native APIs. Measured gains.

A terminal that feels like the platform.

Darwin PTYs, CoreText and Metal, with no portability layer.
Every improvement is benchmarked.

Faster than Ghostty, measured.

Parser and terminal-state throughput beat Ghostty on all 14 inputs by median, up to 3.8× on OSC-heavy output. Allocation budgets run in Release.

See the benchmarks

Metal and CoreText. Nothing between.

One serial queue owns the parser and grid; the renderer draws immutable snapshots. Common ASCII, UTF-8, CSI and cell updates make zero steady-state allocations.

Read the architecture

Shells that outlive the window.

A per-user agent owns shells, PTYs, history and layouts. Quitting detaches; tabs and splits grow the same workspace. Reattach from the app or swmux.

Explore SwiftMux

Roam without reconnecting.

RST/1 sends complete current screens over QUIC, not a byte log, so iPhone and iPad sessions survive Wi-Fi and cellular changes. No speculative echo.

Set up roaming

Know when a program needs you.

Every pane parses OSC 7501 status, shown or not. The toolbar counts Needs you requests; open, snooze or review them, or follow a deep link to the pane.

Open the inbox

Script it in JavaScript.

config.js ships with typed swiftty.d.ts: output filters, pane splits, status items, notifications and command, directory and status events. No Node.js required.

Automate the terminal

More ways to make it yours

Use the app. Or embed the core.

Run it on every Apple screen, configure it in JSONC, bring your own shell, or drive the engine from your own transport.

TerminalSession.receive(_:)

Embed the core.

SwifttyEngine is headless; SwifttyCore adds rendering and sessions. Feed bytes through receive, send input from onWrite. Shell embeds it through its libghostty API.

Embed swiftty
-scheme SwifttyMobile

iPhone, iPad, Vision Pro, Apple TV.

The UIKit frontend runs on iOS and iPadOS and builds for Mac Catalyst, visionOS and tvOS, where the focus engine and hardware keyboards provide input.

Build for mobile
swsh -c 'echo $HOME'

A native shell, too.

swsh brings pipelines, ordered redirects, Darwin job control, functions, subshells and native programmable completion, with no word splitting surprises.

Read the shell spec
~/.config/swiftty/config.jsonc

JSONC with a schema.

Comments, trailing commas and a published $schema for editor completion. Settings writes back to the same file; Reload Configuration applies edits.

Configure swiftty
Settings › SSH Keys

SSH keys as identities.

Generate or import Ed25519 keys into the Keychain, device-only by default or opt in to iCloud Keychain. A missing key fails closed and never falls back to a password.

Manage SSH keys
swmux new -s work -c ~/code

A multiplexer in the terminal.

swmux attaches, lists, detaches and ends the same workspaces the app shows, with a C-b prefix and up to 32 panes per workspace.

Use swmux

Working on durability? A separate swiftmux-gateway is building toward sessions that survive app and gateway updates; it is installed explicitly and not yet registered by the app installer. Read the durability spec →

Release builds · Apple M5 Max

Measured.
Not assumed.

Same inputs, same machine, alternating runs.
Swift 6.4 against Ghostty built with Zig ReleaseFast.

  1. 14 of 14 inputs faster

    Parser and terminal-state throughput, by median.

  2. p50 16.7–17.0 ms key to pixel

    Versus 18.6–21.3 ms for Ghostty 1.3.1, same display.

  3. p95 2.93 ms on iPad Pro

    120×40 offscreen full redraw on a physical device.

100 MiB inputs · 120×80Methodology →
Input Ghostty Swiftty Swiftty time relative to Ghostty Relative
ascii 99.0 ms 93.8 ms 105.6%
compiler-log 140.9 ms 125.1 ms 112.7%
csi-heavy 477.5 ms 357.4 ms 133.6%
ghostty-osc 4,104.0 ms 1,092.8 ms 375.6%
ghostty-styled 409.1 ms 211.9 ms 193.1%
osc-heavy 1,111.7 ms 541.4 ms 205.3%
scroll 406.4 ms 303.9 ms 133.7%
unicode-joins 348.2 ms 258.6 ms 134.7%
utf8-cjk 100.6 ms 92.4 ms 108.9%

Lower times are better.

Medians of 20 alternating runs after two warmups, including startup and file I/O, reading 64 KiB chunks. Relative throughput is Ghostty time divided by Swiftty time.

14/14 fasterup to 375.6%zero steady-state allocs

Mixed-script UTF-8 has little margin (100.2%). The key-to-pixel probe uses synthetic keys and screen capture; physical-keyboard and photon-level latency have not been measured. All measurements →

From checkout to first prompt

Your next shell,
a little more native.

Build from source with Xcode and mise, then install the app with its persistent SwiftMux agent.

Read the build guide

macOS 27+ · Xcode 27 · Swift 6.4

# Build and launch the macOS terminal.
git clone https://github.com/chr33s/swiftty.git
cd swiftty
mise install
mise run app

Use Xcode’s Swift 6.4 toolchain; mise.toml pins the other tools. mise run test-native runs the full unit suite and real PTY sessions with sh, vim, less, tmux and top. Build and test →

Embedded by: Shell, through its libghostty API. Configuration lives in ~/.config/swiftty/config.jsonc.