Notes

Short notes, mostly for myself.

On pipes as a type system

A Unix pipe is a type constraint with one type: the byte stream. This is often derided as primitive; it is in fact the reason that tools composed over four decades still interoperate. The lesson I keep relearning is that any richer interface between two programs will rot faster than the programs themselves. jq is a pragmatic concession, not a counterexample.

On writing C in 2025

I still write new C when the problem is small, the interface is narrow, and I expect the program to outlive three generations of package manager. The cost is eternal vigilance about memory; the benefit is a binary that will compile on a machine pulled out of a closet in ten years. For anything with a surface area larger than a few thousand lines, I reach for Rust. For anything smaller than a few hundred lines that will only ever run once, I reach for awk.

On histograms

Almost every metric you care about is better as a histogram than a mean. The mean tells you about an average user who does not exist; the histogram tells you about the actual users, including the 1% for whom everything is on fire. If you take one thing from this site, take that. (This is also the excuse for four separate tools in the gallery that are, functionally, histograms wearing different costumes.)

On being wrong in public

Several of the tools in the gallery are wrong in ways I know about, and presumably several more in ways I do not. I leave them up because the goal of this archive is not to present a polished surface; it is to preserve the record of what I actually built and what I actually thought at the time. If you find a bug, good. That is how the catalog gets better. The Broken by design page is an honest ledger of the ones I have not yet chosen to fix.

On dependencies

Every dependency is a bet that someone else's project will remain healthy for at least as long as yours does. Most such bets are losing bets. The correct number of dependencies for a small tool is in the low single digits; the correct number for a tool you would like to still run in ten years is often zero. libpcre2, capstone, and libbpf are the three I have made peace with. Everything else I would rather vendor.

On signals

Every command-line program should handle three signals correctly: SIGINT (user wants out now), SIGPIPE (reader went away, please stop), and SIGTERM (shut down cleanly, please). Everything else is optional. The single most common bug I find in small tools is a SIGPIPE handler that turns a | head into a backtrace.

On flags

If your tool has more than about nine flags, you have written two tools. If it has more than about twenty, you have written a subsystem and should confess to having done so. The gallery has exactly one offender and I am not going to say which.

On manual pages

A man page is a contract. It is the smallest viable artifact that says this program behaves this way, on purpose. The act of writing one tends to surface, in the first paragraph, the reason the program should not exist in its current form. I consider this a feature.

Notes are added when a program stops teaching me something I already knew. No schedule. No RSS.