My Mac was crawling. I opened our own app to find out why, and it told me everything was fine.
Two servers listening. Both at zero percent CPU. A calm, tidy screen.
Meanwhile the machine had a load average of 43 across 11 cores — four times more work queued than it had cores to run it. Every app I touched stuttered. The tool I built specifically to answer "what is my machine doing?" was showing me a quiet room while the building was on fire.
So I did the thing the app exists to save you from. I opened Terminal and ran ps, lsof, and uptime by hand.
What was actually eating it
A Flask dev server I had started that morning and forgotten — up for sixteen hours, with a pool of thirteen worker processes behind it. An antivirus scan pinning one and a half cores. A test build chewing another. The window server. A log daemon.
Now look at that list again, because there is a pattern in it that took me longer to see than I would like to admit:
None of them were listening on a port.
Not one. And Localhost Explorer is, by construction, a tool that finds processes by their sockets. If a process does not open a port, it does not exist to us. We fetch CPU numbers only for the processes we have already found — which means we can only ever tell you the CPU of things that listen.
The worker pool is the sharpest version of it. Thirteen processes were burning nearly five cores between them, and every one of them was a child. Only the parent held the socket. So the single row we did show — the parent, idling at zero percent, politely listening — was the least interesting process in the entire tree.
We were not wrong. We were answering a different question than the one I had.
Two questions, not one
"What is listening?" and "what is eating my machine?" feel like the same question when you are a developer with too many dev servers. Most days they overlap enough that you never notice. The day they diverge is exactly the day you need an answer, and that is the day we had nothing to say.
So 1.1.1 adds the other half.
Load, in words
There is now a strip at the top of Stats with the load average expressed per core. Per core matters more than the raw number: a load of 8 is alarming on a 4-core machine and unremarkable on a 16-core one, and the raw figure cannot tell those apart. Underneath it, a verdict in plain language — healthy, fully committed, or oversubscribed — everything will feel slow.
Because "43" means nothing to most people at a glance. "Everything will feel slow" is the sentence you actually needed.
The heavy things that don't listen
Next to it: the biggest CPU consumers that never open a port, which is to say the ones this app could never show you before. Antivirus. Build jobs. Runaway worker pools. The window server having a moment.
It excludes the processes already in your list, so it complements the panel instead of printing it twice. And it names things the way you think of them — the app, not the helper binary buried four folders inside its bundle.
Quiet by default
The strip hides itself completely when the machine is calm or the reading is unavailable. A healthy Mac gets no new chrome, no new number to ignore. It appears when it has something to say that the rest of the panel cannot say for it.
That is the rule we try to hold to generally: the only loud thing should be the thing that needs you.
One more, small
Holding a letter key in the list — open, terminal, stop — used to repeat the action on every key repeat, and leak the keystroke through as typed text besides. One press, one action, as it should always have been.
The honest lesson
Our model of the world was "processes with sockets", and we built a good tool on top of it. But a model is also a blind spot, and you usually find yours the way I found this one: staring at your own product while it calmly tells you nothing is wrong.
Update from the app, or grab 1.1.1 from the site.