// Overview

Sherpa is a native macOS SSH client that replaces juggling Terminal tabs and remembering connection strings. It provides a unified interface for managing servers, keys, and file transfers — with everything synced across devices via iCloud.

Designed for developers who SSH into multiple machines daily, Sherpa brings tabbed sessions, split-pane terminals, and integrated SFTP into a single, fast macOS app.

// Architecture

SwiftUI Views
Combine State
Session Manager
libssh
SwiftTerm
Core Data
|
CloudKit Sync
|
Keychain

The SSH layer uses libssh for connections, authentication, SFTP, and port forwarding. The terminal emulator is powered by SwiftTerm (VT100/xterm-256color), providing full terminal compatibility. State flows reactively through Combine publishers, keeping the UI in sync with session lifecycle events.

// Key Features

  • Tabbed SSH sessions with quick-connect from a saved host list
  • Local terminal with the same interface as remote sessions
  • Split-pane views — work on multiple sessions side by side
  • Integrated SFTP file browser with drag-and-drop transfers
  • Port forwarding (local and remote tunnels)
  • SSH key management — generate, import, and associate keys with hosts
  • iCloud sync for hosts, keys, and settings across all Macs
  • Secure credential storage via Keychain and iCloud Keychain
  • Server grouping and organization

// Technical Details

libssh: Handles the full SSH protocol stack — password and key-based auth, session multiplexing, SFTP channels, and port forwarding tunnels. Wrapped in a Swift-friendly API layer that manages connection lifecycle and error handling.

SwiftTerm: A full VT100/xterm-256color terminal emulator embedded in SwiftUI. Handles escape sequences, mouse reporting, alternate screen buffer, and 256-color support for tools like vim, htop, and tmux.

Core Data + CloudKit: Host configurations, key metadata, and app settings are persisted with Core Data and automatically synced to iCloud. The sync is conflict-aware and works seamlessly across multiple Macs.

// Challenges & Solutions

Challenge: Integrating libssh (a C library) with Swift's strict concurrency model while maintaining responsive terminal rendering.

Solution: Built a bridging layer that isolates all libssh calls on dedicated serial dispatch queues per connection. Terminal output is buffered and flushed to the SwiftTerm view on the main actor at 60fps cadence, preventing UI jank even during heavy output (e.g., large cat operations).

Challenge: Keeping hosts, keys, and settings in sync across devices without data loss during conflicts.

Solution: Used Core Data's NSPersistentCloudKitContainer with custom merge policies. Host records use a last-writer-wins strategy with timestamps, while SSH keys use a union merge — keys are never silently deleted during sync conflicts.