Profile
Back to NewsBack
GitHub Trending 5 min
Reader Mode
eriklangille/clauntty: iOS Terminal with native Claude Code support

eriklangille/clauntty: iOS Terminal with native Claude Code support

Clauntty

iOS SSH terminal with persistent sessions and GPU-accelerated rendering.

Why Clauntty?

Most mobile terminals lose your session when the app backgrounds or your connection drops. Clauntty solves this with automatic session persistence - no tmux or screen required.

Key Features

Persistent Sessions (via rtach)

  • Sessions survive app backgrounding, connection drops, and device restarts
  • Full scrollback history replayed on reconnect
  • Zero server-side setup - rtach binary auto-deployed on first connect
  • Battery-optimized pause/resume protocol
GPU-Accelerated Rendering (via Ghostty)
  • Metal-based renderer from Ghostty
  • Smooth 60fps scrolling and output
  • Proper Unicode, emoji, and color support
  • 20+ built-in themes (Dracula, Monokai, Solarized, etc.)
Native iOS Experience
  • Multi-tab with swipe gestures
  • Keyboard accessory bar (Esc, Tab, Ctrl, arrows, ^C/^L/^D)
  • Text selection with long-press
  • Port forwarding with in-app browser
  • SSH key authentication (Ed25519)
Open Source
  • No accounts, no telemetry, no subscriptions

Requirements

  • Xcode 15+ (full app, not just command-line tools — needed for iOS SDK, simulator, and signing)
  • iOS 17.0+
  • Zig 0.15.2+ — install via brew install zig or from ziglang.org/download
  • Go — install via brew install go; builds the embedded Tailscale framework. Any recent Go works: the build script downloads the exact version libtailscale's go.mod pins
  • Apple Developer account — free Apple ID works for simulator and personal device builds; paid ($99/year) required for TestFlight distribution

Building

1. Clone the repos

The project is a monorepo of sibling repos. The directory layout matters: ghostty references ../libxev and the app references ../libtailscale at build time.

mkdir clauntty && cd clauntty
git clone https://github.com/eriklangille/clauntty.git clauntty
git clone https://github.com/eriklangille/ghostty.git ghostty
git clone https://github.com/eriklangille/rtach.git rtach
git clone https://github.com/eriklangille/libxev.git libxev
git clone https://github.com/tailscale/libtailscale.git libtailscale

You should end up with:

clauntty/
├── clauntty/   # iOS app (this repo)
├── ghostty/    # Ghostty fork (terminal emulator)
├── rtach/      # Session persistence daemon
├── libxev/     # Event loop (iOS fixes)
└── libtailscale/  # Tailscale's embeddable tsnet library (upstream)

2. Build dependencies

Build in this order — each step depends on the previous:

# 1. Build GhosttyKit framework (requires libxev at ../libxev)
cd ghostty && zig build -Demit-xcframework -Doptimize=ReleaseFast && cd ..

2. Build rtach Linux binaries (auto-copies to clauntty/Clauntty/Resources/rtach/)

cd rtach && zig build cross && cd ..

3. Build TailscaleKit framework (requires Go and libtailscale at ../libtailscale).

Creates the clauntty/Frameworks/TailscaleKit.xcframework symlink target.

cd clauntty && ./scripts/build-tailscalekit.sh && cd ..

After building, verify both framework symlinks resolve:

ls clauntty/Frameworks/GhosttyKit.xcframework clauntty/Frameworks/TailscaleKit.xcframework
The app won't build without both. If only TailscaleKit is missing, run step 3 again. If missing, create it:
ln -s ../../ghostty/zig-out/GhosttyKit.xcframework clauntty/Frameworks/GhosttyKit.xcframework

3. Build the iOS app

Simulator

cd clauntty
./scripts/sim.sh run                    # Build, install, launch
./scripts/sim.sh debug <connection>     # Full debug cycle with logs
./scripts/sim.sh quick <connection>     # Skip build, faster iteration
./scripts/sim.sh help                   # All commands
is a saved SSH connection profile name (e.g., devbox). Create one in the app's connection list UI first, or use the Docker test server for local testing.

sim.sh uses Facebook IDB for simulator automation. Install it first:

./scripts/setup-idb.sh

Physical Device

Replace iPhone 16 with your device name (visible in Xcode → Window → Devices):

xcodebuild -project Clauntty.xcodeproj -scheme Clauntty \
  -destination 'platform=iOS,name=<YOUR DEVICE>' -quiet build

xcrun devicectl device install app --device "<YOUR DEVICE>" \ ~/Library/Developer/Xcode/DerivedData/Clauntty-*/Build/Products/Debug-iphoneos/Clauntty.app

Building your own fork

To ship under your own identity, update these:

| What | Where | Current value | |------|-------|---------------| | Bundle ID | Xcode → Target → Signing & Capabilities | com.octerm.clauntty | | Team ID | Xcode → Target → Signing & Capabilities | 65533RB4LC | | Team ID | ExportOptions.plist → teamID | 65533RB4LC | | URL scheme | Clauntty/Info.plist → CFBundleURLSchemes | clauntty |

The easiest way: open Clauntty.xcodeproj in Xcode, select the Clauntty target, go to Signing & Capabilities, and pick your team. Xcode will update the bundle ID and signing automatically.

Project Structure

Clauntty/
├── Core/
│   ├── Terminal/          # GhosttyApp, TerminalSurface, GhosttyBridge
│   ├── SSH/               # SSHConnection, SSHAuthenticator, RtachDeployer
│   ├── Session/           # SessionManager, Session
│   ├── Tailscale/         # TailscaleManager (embedded tsnet node)
│   └── Storage/           # ConnectionStore, SSHKeyStore, KeychainHelper
├── Views/                 # SwiftUI views
├── Models/                # Data models
└── Resources/
    ├── rtach/             # Pre-built rtach binaries for deployment
    ├── Themes/            # Terminal color themes
    └── shell-integration/ # Shell scripts for title updates

RtachClient/ # Swift module for rtach protocol parsing Frameworks/ # GhosttyKit.xcframework, TailscaleKit.xcframework (symlinks) scripts/ # Build and test automation

Key Files

| File | Purpose | |------|---------| | Core/Terminal/GhosttyApp.swift | Ghostty C API wrapper, theme management | | Core/Terminal/TerminalSurface.swift | UIViewRepresentable for Metal rendering | | Core/SSH/SSHConnection.swift | SwiftNIO SSH client | | Core/SSH/RtachDeployer.swift | rtach binary deployment, session listing | | Core/Session/SessionManager.swift | Tab/session lifecycle management | | RtachClient/ | rtach protocol parsing (Swift) |

Architecture

┌─────────────────────────────────────────────────────────────┐
│  SwiftUI Views                                              │
│  ┌──────────────┐  ┌─────────────────┐  ┌────────────────┐  │
│  │ Terminal UI  │  │ Connection List │  │ Keyboard Bar   │  │
│  └──────┬───────┘  └─────────────────┘  └────────────────┘  │
│         │                                                    │
│         ▼                                                    │
│  ┌──────────────────────────────────────────────────────┐   │
│  │ SessionManager                                        │   │
│  │ - Manages tabs (terminal + web)                       │   │
│  │ - Connection pooling (reuse SSH to same server)       │   │
│  │ - Lazy reconnect (only active tab connected)          │   │
│  └──────┬───────────────────────────────────────────────┘   │
│         │                                                    │
│  ┌──────┴──────┐  ┌─────────────────┐  ┌────────────────┐   │
│  │ Session     │  │ GhosttyKit      │  │ RtachClient    │   │
│  │ (per tab)   │  │ (Metal render)  │  │ (protocol)     │   │
│  └──────┬──────┘  └────────┬────────┘  └───────┬────────┘   │
│         │                  │                    │            │
│         └──────────────────┴────────────────────┘            │
│                            │                                 │
│                    SSHConnection (SwiftNIO)                  │
└────────────────────────────┼─────────────────────────────────┘
                             │
                             ▼
                      Remote Server
                    (rtach + $SHELL)

Data Flow

Input: User types → Keyboard → RtachClient (frame) → SSH channel → rtach server → PTY → shell

Output: Shell → PTY → rtach server → SSH channel → RtachClient (parse) → GhosttyKit → Metal

Debugging

# Simulator logs
./scripts/sim.sh logs
./scripts/sim.sh logs 30s

Physical device logs

idevicesyslog -u $(idevice_id -l) 2>&1 | grep -i clauntty

Crash reports

uv run scripts/parse_crash.py --latest

Testing

# Unit tests
xcodebuild test -project Clauntty.xcodeproj -scheme ClaunttyTests \
  -destination 'platform=iOS Simulator,name=iPhone 16'

Local SSH test server (Docker)

./scripts/docker-ssh/ssh-test-server.sh start

Connect to localhost:22, user: testuser, pass: testpass

Dependencies

| Dependency | Purpose | Source | |------------|---------|--------| | GhosttyKit | Terminal emulation + Metal rendering | eriklangille/ghostty | | rtach | Session persistence daemon | eriklangille/rtach | | libxev | Cross-platform event loop (iOS fixes) | eriklangille/libxev | | swift-nio-ssh | SSH protocol | apple/swift-nio-ssh |

Chat with me