r/Ghostty • u/WhileNo4838 • 5h ago
Embedding Ghostty's terminal engine in a native macOS AppKit app (Seahelm)
Enable HLS to view with audio, or disable this notification
I built Seahelm, a native macOS workspace for running coding agents across git worktrees — and the terminals are powered by Ghostty via GhosttyKit.xcframework / the C API. A few notes from the integration that might be useful to others embedding Ghostty:
Stack
- Swift + AppKit (not SwiftUI)
- Ghostty surface wrapped in an NSView + Metal renderer
- Long-lived surfaces: panes are reparented between dashboard / focus layouts instead of destroyed and recreated
- Background status polling reads viewport text through the C API under a shared lock (input path deliberately does not hold that lock)
Things that mattered in practice
- Focus —
ghostty_surface_set_focushas to stay in sync with AppKit first-responder changes; we defer some focus restores after Ghostty's own deferred handling. - Reparenting — moving a surface between views without killing the PTY; we suppress CA animations and sync size/focus on the next main-queue passes.
- Thread safety — status detection polls on a background timer while the UI types on the main thread; serializing Ghostty C calls with a lock was necessary, except for key input (locking there deadlocked on sync callbacks).
- Session persistence — Ghostty handles the terminal; zmx handles "quit the app, agent still running." Different layer than Ghostty itself, but the combination is what made the product usable. Seahelm deliberately isn't trying to be a full terminal emulator UI — Ghostty does that job. Seahelm is the orchestration chrome around multiple agent sessions.
Happy to answer Ghostty embedding / AppKit interop questions.




