Let's talk a bit about what makes the Superlogical multiplexer different architecturally from traditional terminal multiplexers! There's a lot (a LOT) more coming, but wanted to share a little bit about the terminal-specific part compared to tmux and zellij.
Show more
The Ghostty non-profit has signed our first long-term paid contributor via a 12-month agreement with
@vancluever. He's a top-quality engineer, has been part of the Ghostty community for years, and has consistently demonstrated an extremely high quality and judgement bar.
He is the creator and maintainer of z2d, the vector graphics library that Ghostty uses. He has contributed upstream to the Zig compiler and Arocc C compiler dozens of times.
The way Ghostty contributor contracts work is that there is no stated or mandated area of focus. I trust Chris to work on worthwhile tasks, and Chris has demonstrated he does so far, so there's no need to push him one way or the other. He chooses what to work on and describes his work to the non-profit (so it's all aligned and legal to compensate).
As I spend more time focused on libghostty, especially the libghostty needs of
@superlogical, I want to ensure that the broader Ghostty project continues to be staffed and healthy. We'll be signing more contributor contracts soon!
Show more
I've started a new company:
@superlogical! We're going to begin by building a terminal multiplexer. The entire vision is much larger, but the multiplexer is the foundation. Sign up for the newsletter to get beta access and devlogs (product updates only I promise).
Show more
Btw this is why computer science matters. Yes, you can self teach it if you really want to (I personally wouldn't have had the discipline, so college was a way better force). However you learn it, the theoretical fundamentals matter and get applied to work every single day.
Show more
If you're interested in "how" or "why": the major culprit is that each row in Alacritty has 32 bytes of metadata and each cell is 24 bytes. In Ghostty, every row and cell is represented by exactly 8 byte each. How do we do this?
The first major culprit is styles. Alacritty stores the full cell style alongside each cell (foreground, background, underline, etc.). Ghostty stores a 16-bit style ID and de-dupes all styles into a look-aside custom reference-counted hash table.
MOST cells are unstyled, and when there are styles MOST styles are shared, and when styles are shared MOST are repeated in a run (multiple cells with the same style in a row). Put this all together, and the tradeoff on compute to access it doesn't even end up being slower.
Next, codepoints. Alacritty stores multi-codepoint graphemes (like, Emoji) by having an 8-byte nullable pointer to a `Vec`. This hurts doubly: (1) its almost always null (because multi-codepoint is rare) yet you pay an 8 byte cost on every cell and (2) every multi-codepoint grapheme triggers a heap allocation to make that Vec.
Ghostty stores single codepoints inline, but multiple codepoints in a look-aside table. The memory for this table uses a custom bitmap-tracked chunk-allocator (since grapheme frequency follows a measurable curve we calculated by scanning various online texts). The presence of graphemes is marked by a 2-bit content tag in our packed 64-bit cell. To keep the key small in the hash table, its limited to a 16-bit unsigned int that is an offset from a base pointer.
Okay, the astute systems programmer will quickly notice there are a lot of 16-bit integers and ask: so this is all limited to a max of ~65K values?
Nay. We maintain our grid using a linked list of contiguous ~400KB memory chunks (which themselves are in a memory pool using a custom allocator to speed up alloc/free). Each memory chunk is limited to 2^16. If/when we reach a limit, we move to the next page. In practice, this really doesn't happen except under pathological cases... the important point is we handle it.
Lots, lots, lots more details, but thats a 10,000 foot view.
These things alone account for ~95% of the difference of our uncompressed vs. Alacritty's uncompressed memory usage. (Theres also a reason why Alacritty's data structures aren't trivially compressable but thats a whole other topic)
Show more
If you're interested in "how" or "why": the major culprit is that each row in Alacritty has 32 bytes of metadata and each cell is 24 bytes. In Ghostty, every row and cell is represented by exactly 8 byte each. How do we do this?
The first major culprit is styles. Alacritty stores the full cell style alongside each cell (foreground, background, underline, etc.). Ghostty stores a 16-bit style ID and de-dupes all styles into a look-aside custom reference-counted hash table.
MOST cells are unstyled, and when there are styles MOST styles are shared, and when styles are shared MOST are repeated in a run (multiple cells with the same style in a row). Put this all together, and the tradeoff on compute to access it doesn't even end up being slower.
Next, codepoints. Alacritty stores multi-codepoint graphemes (like, Emoji) by having an 8-byte nullable pointer to a `Vec`. This hurts doubly: (1) its almost always null (because multi-codepoint is rare) yet you pay an 8 byte cost on every cell and (2) every multi-codepoint grapheme triggers a heap allocation to make that Vec.
Ghostty stores single codepoints inline, but multiple codepoints in a look-aside table. The memory for this table uses a custom bitmap-tracked chunk-allocator (since grapheme frequency follows a measurable curve we calculated by scanning various online texts). The presence of graphemes is marked by a 2-bit content tag in our packed 64-bit cell. To keep the key small in the hash table, its limited to a 16-bit unsigned int that is an offset from a base pointer.
Okay, the astute systems programmer will quickly notice there are a lot of 16-bit integers and ask: so this is all limited to a max of ~65K values?
Nay. We maintain our grid using a linked list of contiguous ~400KB memory chunks (which themselves are in a memory pool using a custom allocator to speed up alloc/free). Each memory chunk is limited to 2^16. If/when we reach a limit, we move to the next page. In practice, this really doesn't happen except under pathological cases... the important point is we handle it.
Lots, lots, lots more details, but thats a 10,000 foot view.
These things alone account for ~95% of the difference of our uncompressed vs. Alacritty's uncompressed memory usage. (Theres also a reason why Alacritty's data structures aren't trivially compressable but thats a whole other topic)
Show more
libghostty vs. Alacritty (alacritty_terminal crate) memory usage. This tests pure terminal state with various payloads: empty screen, full screen, 10K row scrollback with plain text, unicode, heavy styling, and mixed. This is the most accurate read to what an embedder sees.
So, when you see meme posts about Ghostty (or any of its embedders) memory usage, that is the fault of the application. Ghostty GUI itself certainly has some memory bloat! But its the GUI apps causing this, not libghostty.
Note that Ghostty's results include our active scrollback compression, which Alacritty doesn't support. This is fair because it is on by default and happens automatically (while we still have higher IO throughput than Alacritty). It is the proper like-for-like comparison because it's what you'd experience.
I included uncompressed numbers too though even though you'd have to actively try to get these, just to show even uncompressed is significantly better.
Also, these were all run within the same Rust-written binary that embeds both, so it also avoids measuring the binary overhead differently since they run from an identical binary.
I'm working on also measuring libvte and writing a longer form blog post to share the whole testing setup. I needed something to link to whenever I see the memes.
libghostty is small, nimble, and excellent software.
Show more
libghostty vs. Alacritty (alacritty_terminal crate) memory usage. This tests pure terminal state with various payloads: empty screen, full screen, 10K row scrollback with plain text, unicode, heavy styling, and mixed. This is the most accurate read to what an embedder sees.
So, when you see meme posts about Ghostty (or any of its embedders) memory usage, that is the fault of the application. Ghostty GUI itself certainly has some memory bloat! But its the GUI apps causing this, not libghostty.
Note that Ghostty's results include our active scrollback compression, which Alacritty doesn't support. This is fair because it is on by default and happens automatically (while we still have higher IO throughput than Alacritty). It is the proper like-for-like comparison because it's what you'd experience.
I included uncompressed numbers too though even though you'd have to actively try to get these, just to show even uncompressed is significantly better.
Also, these were all run within the same Rust-written binary that embeds both, so it also avoids measuring the binary overhead differently since they run from an identical binary.
I'm working on also measuring libvte and writing a longer form blog post to share the whole testing setup. I needed something to link to whenever I see the memes.
libghostty is small, nimble, and excellent software.
Show more
Absolutely love seeing the proliferation of libghostty from fun projects like this to very serious projects run by multi-B companies. Full-featured, high-performance, modern terminal emulation is available to anyone and everyone.
Show more
rofl added a terminal via libghostty to remarkable in one night. insane. ai actually just lets you do so much fun stuff
My SIMD post was on HN and the general hostility towards understanding how computers work and owning your own outcomes is really depressing. A large amount of people seem to simply have the attitude that they hope someone else pays their bills for them.
Show more
Wrote up a practical introduction to SIMD using a real example from Ghostty. SIMD has a reputation for being complex, but the common case follows a simple, repeatable shape and shouldn’t be scary! Everyone should know at least this much.
Show more
Ghostty and libghostty are now on Zig 0.16! This was done by a [paid!] contributor. Through this process, the Ghostty non-profit also paid for hours to contribute over a dozen patches upstream to the translate-c and arocc projects which help the entire ecosystem. Amazing work.
Zig 0.16 came out awhile ago, but in reality it wasn't a focus of the project to upgrade until the past few weeks. It did take a few weeks to upgrade, but the primary complexity was due to C translation/integration and not Zig itself.
Zig 0.16 switched C translation from clang to the translate-c/arocc projects which are faster and a much smaller dependency.
Ghostty is a very complex C user, consuming Apple headers (e.g. blocks), Windows headers, GTK headers, SIMD intrinsic headers, and more. This stressed these upstreams and we had to fix a number of issues to get through.
This was high quality and good work though and I'm happy to see it help the ecosystem. translate-c and arocc are just excellent standalone projects even if you're not interested in Zig. They're way easier to embed than clang and solve that problem well.
Upstream patches:
* translate-c:
* arocc:
Show more
LLVM21 is a stinker and has worse codegen in general, and a bug forced disabled loop auto-vectorization. Turned out to be a blessing: we clearly identified areas we were over-reliant on implicit compiler optimizations and were able to explicitly restructure our code to what we really wanted.
The result is that we now have clean generic SIMD subroutines in places we previously relied on auto-vectorization. And we did it better and as a result produced faster code (see below). Pure ASCII throughput improved more than 20% (30% on Linux) which is insane and is purely because we wrote better SIMD than an auto-vectorizer can. Lit.
We also found it stopped inlining automatically in certain places which destroyed some benchmarks based on real world corpuses. As a result, we now explicitly inline those backed by benchmarks. Wonderful.
Some things slowed down more than can be attributed to noise. I'm looking into that now but they're minor benchmarks. The important ones are parity or better.
Show more
Quality software doesn’t break, doesn’t demand attention, knows its limits, and fixes fast.
@almonk is a fine builder of quality software, recommend.
Testing some UI. Not Ghostty btw (but, libghostty). Not ready to talk more yet, but sharing things I'm excited about. Plenty more details soon.
Doing stuff like this in the background lets me maximize my productive time when I actually have time to sit at a computer (more limited than ever with a newborn + toddler!). I kicked this (and a handful of other tasks) off while my daughter was bathing last night.
AI is way slower at completing these tasks than I would be doing it manually, but it does them for me when I can't be doing them.
When I get to the computer, my review + commit sessions are relatively short, and then I can quickly get on with the stuff I really want to work on or that really requires my attention.
Show more
This is true outside the browser too! At some point we found ~10% of all Ghostty IO time in an Asciinema dump was log warns for purposely unsupported sequences. We moved that to "log once per sequence" helper and saw that overhead disappear. Source here:
Show more
Did you know that even a simple console.log() per request can hugely hurt performance?
The built-in logger in the next h3/srvx release batches writes and caches the timestamp (Intl), cutting logging overhead ~60–85%.
Show more
Using a generic agent harness (e.g. Codex, Claude, OpenCode) + CLI/MCP is better than "Ask me anything" built-in product chat boxes in every product I've ever tried. A big reason is I can use the latest frontier models, another is mixing more context. Why your box over mine?
Show more
A ChatGPT automation just found ~$45K in erroneous invoices across 3 years of billing history that I've confirmed and already had resolved. My lifetime history for ChatGPT is ~$1,800, so it just paid for itself 25x over.
I setup an automation with read-only access to my email, and tasked this one specifically with analyzing construction invoices. It has access to prior construction invoices, emails, meeting notes, etc. It produces a report and emails it to me (the only email its allowed to send, enforced by API token) whenever I receive a construction invoice.
Across 3 years of construction projects, it found about $45K in issues. Some were wrong amounts, some were duplicate invoices, some were invoices addressed to the wrong person. I manually verified, emailed my GCs, and got refunded/credited.
I get multiple construction bills each month and each bill is ~50 pages in a PDF of low-quality scanned paper. I do manually review each bill but its pretty hard to be right all the time.
I do believe these were genuine mistakes and not done out of ill will just based on what the mistakes were. I don't want to share my full construction costs across the past few years, but $45K is a very small percentage of overall billed amounts.
Pretty sweet.
Show more
Zero regrets about the cost of living in CA. The joy of walking to this anytime I want can’t be overstated. Touch grass therapy is strong here.
I haven’t successfully found a use case for Sol Ultra yet. I’ve run two days of side by side xhigh and ultra runs for planning and impl and I haven’t noticed any tangible quality change. I can see the difference in execution and token usage. Maybe I’m holding it wrong, but how?
Show more
Ghostty is getting automatic scrollback compression, resulting in 70 to 90% less physical memory usage. It happens incrementally when idle, so it had no measurable effect on IO throughput. I'm not aware of any other mainstream terminal that does this. Demo video below!
The gains let us increase the default scrollback limit from 10MB to 50MB, because on average a full scrollback will still compress smaller than the prior limit. More history, for free. ("Unlimited", disk-paged history is on the roadmap too)
Let's talk about cool implementation details, cause this was fun.
First, the data structure and memory layout ("PageList") I wrote two years ago finally pays off! One of its traits is that screen memory is backed by a linked list of page-aligned, page-sized (or page-multiple-sized) blocks.
Because each block is page-aligned and page-sized, we can use madvise to discard its physical backing while keeping the virtual address space reserved. Compressed pages therefore disappear from resident memory, but decompression is still guaranteed because the address space remains valid and we simply fault new pages back in as needed.
We use the same trick for our memory pools, too. Unallocated pool pages don't count as resident memory, saving another couple of MB per terminal.
This functionality is also available to libghostty-vt consumers via new `ghostty_terminal_compress` APIs. The consumer decides when the appropriate time to compress is and the APIs advise on compressability.
Show more