I Couldn't Give Up Ghostty, So I Put It Inside My App

Confession first: I built myself a dev cockpit and then didn't use it.
My daily setup is Bun + tmux + Ghostty: my tt CLI (towles-tool) driving a tmux grid, one Claude Code session per pane. I've been rewriting it as a Rust + Tauri app (towles-tool-rs) with embedded xterm.js terminals. Every time I tried to switch, I lasted a few minutes and went back. The app was fine. The terminals weren't. I couldn't give up Ghostty.
So when Mitchell Hashimoto announced libghostty, extracting Ghostty's terminal core into embeddable libraries, the fix was obvious: put Ghostty inside the app.

| Old | New | |
|---|---|---|
| Runtime | Bun/TypeScript CLI | Rust |
| Windowing | tmux | Tauri app |
| Terminal | Ghostty | libghostty (Ghostty's core, embedded) |
The catch: libghostty has never been released. No version tag, no artifacts. You build it from the Ghostty repo, and the C API breaks weekly. But the core is the same code that's run the Ghostty app for years, so pin your commit and it's fine.
What you get in libghostty-vt: the SIMD VT parser and the full terminal state machine (scrollback, styles, Kitty graphics, reflow on resize) plus a render-state API for writing your own renderer. No PTY, no renderer, no font shaping. You bring those.
My setup now: each terminal is a Rust thread owning a libghostty-vt Terminal (via the libghostty-rs bindings). PTY bytes in, dirty-row frames out as JSON, and the WebView just paints them on a canvas. With xterm.js all the parsing and state lived in the JS heap and died on every reload. Now it lives in Rust: reload the WebView and your shells survive.

Numbers from the spike: parsing ~418 MB/s, full 200×50 render pass ~190µs. The terminal state layer is just not a cost anymore.
The costs were real too. I had to write a canvas renderer (a few hundred lines) and keyboard encoding (~150 lines, IME is the usual trap), and Zig joined my toolchain since the crate builds libghostty from source.
The whole migration took a couple hours with Claude Code on Fable, and used 5% of my weekly quota. I expected it to eat the week. A few of the prompts driving it came straight from Thariq's field guide.

After it shipped I had Fable generate a report on the change with a quiz I had to pass, becuase "the AI did it in a day" is worthless if I can't defend it in review. Another one of his prompts — I liked it enough it's now a /comprehend command in towles-tool-rs, my Claude Code plugin.
If you've got embedded terminals and have been waiting on libghostty: it's real, it works today. Just pin your commit.