Ghostel Puts libghostty Inside Emacs Terminals
An embeddable VT engine is closing the gap between standalone terminals and in-editor shells.
In-editor terminals have always been a compromise. You either get correct, modern protocol support by leaving the editor for something like Ghostty, or you stay inside Emacs with a PTY that is good enough until a TUI, hyperlink, or keyboard sequence exposes the cracks. Ghostel is interesting because it treats that compromise as a library problem. It embeds libghostty-vt, the same VT engine behind Ghostty, as a Zig native module and lets Elisp own buffers, keymaps, and remote process glue.
That is a real architectural shift, not just another M-x term clone. Terminal correctness is moving out of full applications and into reusable engines. Ghostel is the first serious Emacs-facing proof of that idea.
Terminals as libraries, not just apps
Ghostty itself is a GPU-accelerated, platform-native terminal written in Zig. The important detail for tooling is that its VT layer is usable outside the full app. Ghostel follows the same two-layer pattern as emacs-libvterm: native code owns terminal state, rendering, and local PTY I/O; Elisp owns the Emacs surface. The difference is the engine. libvterm targets a conservative VT220/xterm model. libghostty-vt targets the protocols people actually ship TUIs against now.
That shows up immediately in the feature set Ghostel can claim and vterm cannot: Kitty keyboard and graphics protocols, five underline styles plus underline color, OSC 8 hyperlinks, OSC 4/10/11 color queries, and synchronized output (DEC 2026). Those are not decorative. They are why btop, yazi, lazygit, and modern Neovim UIs either look right or look broken.
The practical consequence is that Emacs no longer has to lag a full generation behind standalone terminals just because the editor is not a Cocoa or GTK app. Correctness lives in the VT library. The editor only has to host it.
What ships today
Ghostel requires Emacs 28.1+ with dynamic module support on macOS, Linux, FreeBSD, or native Windows. The common install path is MELPA plus M-x ghostel. The native module is a prebuilt binary that downloads on first use, so most people never touch Zig. Source builds need Zig 0.15.2+ if you want to compile yourself.
Shell integration is on by default for local bash, zsh, fish, and nushell: directory tracking and prompt navigation without hand-editing RC files. Input is modeled after eat-style modes:
- semi-char (default): most keys go to the terminal, Emacs still keeps escapes like
M-xandC-c - char: full passthrough
- line: type in Emacs, send on RET
- emacs / copy: navigate and select in a read-only buffer; copy mode freezes output so nothing scrolls away under the point
Mouse events are encoded and passed through with SGR mouse protocol instead of being intercepted only for point motion. That matters for TUIs that expect drag and click. Clipboard, OSC 52, password-prompt detection, bookmarks, file/URL detection, and TRAMP remotes are first-class. There are also packaged bridges for Evil, compile/recompile, eshell visual commands, and comint coloring.
Inline images use the Kitty graphics protocol, with the usual caveats around what Emacs can display and how large previews behave. Color queries are more immediately useful: tools can ask Emacs for foreground/background via OSC 4/10/11 and adapt to light or dark themes without COLORFGBG hacks.
How it stacks up against vterm and eat
Ghostel is not subtle about the comparison. Against vterm, the story is "same general design, newer engine, more protocol surface, higher throughput." Against eat, the story is "eat stays pure Elisp with zero native deps; Ghostel is much faster and broader."
| Capability | Ghostel | vterm | eat |
|---|---|---|---|
| Native module | Zig / libghostty-vt | C / libvterm | None (Elisp) |
| Kitty keyboard / graphics | Yes | No | Limited / no |
| OSC 8 hyperlinks | Yes | No | Partial |
| Auto shell integration inject | Yes | Manual scripts | Yes |
| TRAMP remotes | Yes | Yes | Yes |
| Default scrollback | ~5,000 | 1,000 | Config-dependent |
| Plain ASCII PTY throughput | ~65 MB/s | ~29 MB/s | Far lower |
| Default redraw | ~30 fps | ~10 fps | Elisp-bound |
On streamed PTY benchmarks with roughly 1,000 lines of scrollback, Ghostel roughly doubles vterm on plain ASCII (65 vs 29 MB/s) and still leads on URL-heavy output (42 vs 24 MB/s). With link detection off, Ghostel holds ~65 MB/s regardless of content shape. Author measurements put it about 15–20× faster than eat on bursty output. Burst absorption (for example, cat of a multi-megabyte file) and typing latency are treated as first-class concerns, not afterthoughts.
Architecture choices back that up. Ghostel uses three-level dirty tracking with per-row granularity and batches consecutive identically styled cells via text properties. The renderer owns buffer-position preservation so redraw does not thrash point semantics. Local PTY ownership sits in the native module; remote work goes through TRAMP with optional automatic shell-integration injection or a permanent remote setup.
None of this makes eat obsolete. If you refuse native modules on principle, or you live on a constrained platform where a Zig .so is political, eat remains the pure-Elisp answer. Ghostel just makes the performance and protocol tax of that choice more obvious.
What this means in a working Emacs setup
If you already run vterm, the migration path is mostly habit, not plumbing. Install from MELPA:
(use-package ghostel
:ensure t
:bind (("C-x m" . ghostel)
:map project-prefix-map
("m" . ghostel-project)))
Then open a terminal with M-x ghostel or bind project-local terminals. The semi-char map is where you re-home muscle memory: keep search on C-s via consult-line, map M-p/M-n to shell history if you came from eshell, and whitelist Elisp callouts with ghostel-eval-cmds so shell helpers can open find-file-other-window, dired, or Magit without becoming a free-form eval channel.
For build workflows, ghostel-compile-global-mode routes compile / recompile / project-compile through Ghostel and gives live mode switching while a job runs. For eshell, only visual commands need the bridge; plain eshell stays eshell. For comint buffers, you can swap the ANSI color path for Ghostel's VT parser if you want consistent escape handling across more than one process UI.
Remote work is the part that usually bites. TRAMP-launched Ghostel can inject shell integration automatically for convenience, or you can install the remote pieces permanently on hosts you use daily. You also need the xterm-ghostty terminfo story sorted: auto-machinery for TRAMP launches, outbound ssh from a local Ghostel buffer, or a fully manual install if you distrust the injection path. If a host is hostile to fancy terminals, you can drop the Ghostty advertisement entirely and fall back to safer terminfo.
Trade-offs to keep in mind:
- Native module. Auto-download removes the CMake/libvterm compile tax for most people, but it is still a binary trust decision. Corporate Emacs builds with modules disabled are out.
- Windows. Native Windows Emacs is supported, with optional ConPTY redistributable bits for better latency and correctness than older inbox ConPTY. WSL-only setups are a different shape.
- Images. Kitty graphics work; do not expect every standalone-terminal image workflow to map 1:1 into Emacs buffers.
- Input modes. Power comes from switching modes intentionally. If you leave everything in char mode, you will fight Emacs. If you never leave semi-char, some full-screen TUIs will feel under-keyed.
Who should switch now: people living in Emacs who already depend on vterm, who run mouse-driven TUIs, who care about hyperlinks and theme-aware color queries, or who hate waiting on bursty build logs. Who can wait: pure-Elisp purists, users without module support, and anyone whose terminal use is mostly ls and git status.
The larger pattern
Ghostel is less about one Emacs package winning a popularity contest and more about where terminal infrastructure is heading. Once the hard VT work is a library, editors, IDEs, remote multiplexers, and even browser-based shells can share one correctness surface instead of reimplementing OSC soup forever. vterm proved the native-module pattern. Ghostel updates the engine and raises the protocol floor.
If libghostty-vt keeps improving as Ghostty itself does, Emacs is no longer stuck waiting for libvterm's conservatism to thaw. The editor can track modern terminal behavior by upgrading a module. That is a healthier dependency story than hoping a full GUI terminal and an in-buffer emulator stay in sync by accident.
Ghostel is production-usable today for local work and careful TRAMP setups, with the usual early-adopter edge cases around remotes, terminfo, and image limits. It is not hype. It is the first Emacs terminal that feels like it was designed after Kitty protocols and synchronized output became normal rather than optional extras.
Sources & further reading
- Ghostel.el: Terminal emulator powered by libghostty — dakra.github.io
- GitHub - dakra/ghostel: Terminal emulator powered by libghostty · GitHub — github.com
- ghostel — a modern terminal emulator for Emacs, powered by Ghostty's VT engine - programming.dev — programming.dev
- Ghostty Terminal: Setup and Configuration Guide (2026) - Petronella Cybersecurity News — petronellatech.com
Priya covers AI frameworks, developer productivity tooling, and the startup ecosystem across South and Southeast Asia, bringing a researcher's rigour and a practitioner's empathy to every story. She is deeply sceptical of benchmarks and asks hard questions so her readers don't have to.
Discussion 0
No comments yet
Be the first to weigh in.