Interface
The window
A title bar with the metric tabs, an overview of three cards, and the process table with an optional inspector. The status bar counts processes, threads and the ones macOS restricted.
| Control | Where |
|---|---|
| Metric tabs | centre of the title bar |
| Sweep, alerts, menu bar monitor, pause, refresh interval, theme | right of the title bar |
| Range — 1, 5 or 15 minutes | beside the heading |
| List or Tree, filter, search, export, inspector | process table header |
| Key | Does |
|---|---|
⌘F |
focus the search field |
⌘⇧T |
switch between List and Tree |
Space |
pause and resume |
Escape |
clear the search, then the selection; close the diagnostics window |
↑ ↓ |
move the selection |
← → |
collapse and expand branches in Tree mode; hold ⌥ for the whole branch |

Looking back at a moment
Click a point in the CPU, Memory, Disk or GPU chart — or focus the chart and use the arrow keys and Enter — to see the eight processes that were at the top in that sample, up to fifteen minutes back. Selecting one selects it in the table, if it is still the same process; one that has exited, or whose PID now belongs to another, is marked and cannot be selected.
Only processes whose counters macOS shared can be listed. So the panel also says how much all of the readable ones made up together. For CPU that is put on the same scale as the chart: if the machine used 600% of one processor and readable processes account for 300%, the other 300% is stated as unattributed — the kernel, or a restricted process — rather than left to look as if the listed ones were the whole story.
Network has no moments: its per-process counters are totals refreshed every five seconds, not a rate for the second that was clicked.
Tabs
CPU
The card shows the machine's load as a share of total capacity, so user + system + idle is always 100. The breakdown gives those three. Three chart modes:
- One chart — the whole machine over the selected range.
- Processors — a grid of one chart per logical processor, each on its own 0–100% axis. Filter by Performance or Efficiency and the remaining tiles spread into the space. Click a tile for its full history with a hover readout. When there are more tiles than fit, the grid scrolls; Pages is offered as an alternative, and shows exactly the number that fits so a tile is never half cut off.
- Threads — the same grid for a selected process's threads. It collects only while this mode is open with a process selected.
Blue is total utilisation; pink is the system portion of it, not a second quantity to add on.
The glance card's thermal pressure is macOS's own level — nominal, moderate, heavy, trapping or sleeping — the one it acts on when it limits the processors to shed heat. It is not a temperature: Apple silicon's sensors are not readable without privileges, and Starf does not estimate one.
Memory
Used is active + wired + compressed. Cached is inactive + speculative — reclaimable, and shown separately. The breakdown bar is the one place the parts really do sum to the whole. The glance card carries physical memory, pressure, swap and cached files.
Energy
Battery charge over time, with the controller's own figures: cycle count, charge against design capacity, voltage, current, temperature, and the adapter's rating. The process list opens on Applications.
Apple's per-process Energy Impact is a private metric Starf cannot read. It is not implemented and nothing stands in for it; the table says so. What is shown there is the same CPU counters the CPU tab shows.
Disk and Network
The Disk chart shows what reached the disks, from their drivers — the kernel, swap and restricted processes included. Beside it, the sum over readable processes. The process list's own disk columns are process-lifetime counters. The Network total counts each byte once: it adds hardware and radio interfaces, and shows VPN tunnels, bridges and virtual-machine interfaces beside it without adding them, since their bytes also cross the interface they ride on.
The Network process list shows per-process bytes and packets from nettop. They are
cumulative totals, not rates, and follow the connections nettop can see — so they need
not add up to the interface totals above.
GPU
Device utilisation over time, with renderer and tiler as independent meters rather
than a stacked bar — they overlap and must never be summed. The process list gains % GPU
and observed GPU time.
History is kept per device, so a machine with more than one gets a selector and a device that disconnects keeps its history with a gap where it stopped reporting, rather than having another device's readings continue its line.
The process table
A growing tag next to a name means the process's memory has been climbing steadily — see steady growth. The inspector gives the rate, the span and the footprint it rose from and to.
Search matches name, user or PID. Filters — All, Mine, Active, Applications — match individual processes in both modes.
Sorting a column sorts by the value that column displays. Unavailable values sort last whichever direction you choose.
Columns
Drag a column's right edge to resize it, or double-click that edge to fit it to what it actually holds — measured in the table's own font, not guessed. Drag a header to reorder. The button at the right of the header row chooses which columns are shown, and restores the defaults.
Each table remembers its own layout, and each metric's process table remembers its own, because they show different things. Only what you actually changed is stored, so a column you never touched still follows its definition.
Hiding a column hides it from view only. Search still matches it and exports still carry it — a column you hid is not one you stopped caring about.
Tree mode
Children appear under their parent, with disclosure arrows. Everything is expanded until
you collapse it; Expand all and Collapse all sit in the header.
Numeric columns switch to Σ — the process plus every current descendant, counted once,
including descendants hidden by search or collapse. Expanding, collapsing or searching
never changes a total. ≥ marks a lower bound, — means nothing was reported, and a
badge on each parent gives its subtree's process count. Hovering a Σ cell shows the
process's own value and how many members reported.
Parent and child totals overlap by construction. The banner above the table says so, because adding the visible rows is the natural mistake.
Searching shows matches with their whole ancestor path; ancestors that did not match are muted and marked Parent. The search keeps its own collapse state, so a new search reveals its matches, you can still collapse branches inside it, and clearing the search restores what you had.
Expansion is keyed by PID and start time, so a recycled PID does not arrive collapsed.
Inspector and actions
The inspector shows the selected process's own values, never its subtree's, and says so. It carries Show in Finder, Quit and Force quit — both confirmed, both refused for processes another account owns, and both re-checking the process identity first — and opens the diagnostics window.
Export
Exports the rows you can see, in the order they are drawn, as CSV or JSON. Unavailable
counters stay unavailable: an empty CSV cell, a JSON null. Tree exports add each
additive column's subtree total with its reporting count and whether it is complete,
partial, overflow or unavailable, kept in a separate object from the process's own
values.
Diagnostic bundle… in the same menu saves everything Starf holds about the last fifteen minutes as one JSON file, for a bug report: the last sample in full, the retained history of every chart, the top processes per metric at every retained moment, the sampling interval and the alert rules. It is gathered when you choose it, not when you finish picking a folder. Around 4 MB for a full fifteen minutes on a desktop with 1,300 processes.
It contains only what the window shows, and some of that is taken out:
| Left out | Why |
|---|---|
| environment variables, command-line arguments | never collected by the sampler; they can hold secrets |
| open files, ports, connections | read only in the diagnostics window, for one process |
| the Mac's name | identifies the person, not the problem |
| the home folder | every path under it starts with ~, and your account is shown as you |
| licence key and e-mail | not part of any sample |
The file lists these under leftOut, so whoever reads it knows the gaps are deliberate.
format is starf-bundle and version is 1.
Menu bar monitor
Off until you turn it on. It shows one live figure — the same number the matching card shows, formatted the same way — and reads from the sampling turn the collector already took rather than starting one of its own.
Left click opens a popover with the metric switch, the figure, a one-minute chart and pause. Right click gives a menu to choose the metric, show the window, or quit.
Pins
Keep in menu bar in the inspector puts a process in the menu bar with its own figure. Its menu chooses which metric, opens the window on that process, or removes it.
A pin is identified by PID and start time. When the process exits, the pin keeps its last figure and says so; it never starts reporting whatever later takes that PID. Pins last only as long as this run of the app — a PID from a previous run means nothing, so restoring them would be guessing.
The popover is one window reused by whichever item opened it, anchored under that item, and it closes when it loses focus.
Alerts
The bell in the title bar opens the alert rules. Every rule is off until you turn it on, and macOS is asked for permission to notify the first time you do — not at launch.
| Rule | Fires when |
|---|---|
| A process stays busy | one process stays above a CPU threshold (200 % by default, where 100 % is one processor) for a number of minutes (5 by default) |
| A process keeps growing | a process is tagged growing |
| Memory pressure rises | macOS moves to warning or critical |
| Your Mac runs hot | thermal pressure rises to moderate or above |
| The battery runs low | the charge falls to a threshold (20 % by default) while not on power |
Each condition is announced once per episode. A busy process is announced again only after it has calmed down, a growing one only once per process, pressure only after it has fallen back, and the battery only after it has charged five points above the threshold. An unreadable figure never fires a rule and never counts as recovery: a process whose CPU time could not be read that second is not calm, it is unknown.
The rules are kept in alerts.json in Starf's configuration folder. The collector
evaluates them on the sample it already took, so alerts cost no extra sampling, and they
work with the window closed as long as Starf is running.
A development build run from a terminal is not a bundled app, and macOS may not deliver
its notifications at all; the bundled .app is what to check them with.
In a terminal
The app's own binary has a terminal mode. It reads with the same sampler and prints the same figures, without a window:
alias starf=/Applications/Starf.app/Contents/MacOS/starf
starf top # redraws every two seconds; Ctrl-C to stop
starf top --sort memory -n 20 # the twenty largest
starf top --mine --once # your own processes, one table, then exit
starf top --json > sample.json # one full sample, as the window receives it
| Option | |
|---|---|
-s, --sort |
cpu (default), memory, disk or threads |
-n, --count |
how many processes; otherwise as many as fit the terminal |
-i, --interval |
seconds between samples, 0.5 to 30 (2) |
-u, --mine |
only processes running as you |
--once |
one table without escape codes, then exit |
--json |
one sample as JSON, with every path, then exit |
The rules are the window's. CPU is a share of one processor. A counter macOS would not
share prints as —, and sorts after every measured value — a measured 0.0 outranks
it, because an unknown is not idle. A process tagged growing has ↑growing after its
name. When the output is not a terminal — a pipe, a file — it behaves as --once, and a
reader that stops early (| head) is not an error.
It redraws by clearing the screen rather than switching to the alternate screen, so there is nothing to restore when it is interrupted.
starf sweep is the terminal side of Sweep: it lists what the
window's Sweep would offer, and moves it to the Trash only with --apply.
Sweep
The broom in the title bar replaces the charts and the process table with Sweep; a metric tab brings them back. Three tabs:
- Build output — Cargo targets,
node_modulesand framework output,distandbuildfolders git ignores, and Xcode DerivedData, in the folders listed under Looking in. Scan finds them and measures each; what has not changed within the chosen time is selected as it is measured. - Caches — found by the same scan, none selected.
- Applications — choose one to see it and what it left in the Library. Exact matches are selected; folders only named like it are listed as likely, unselected, with a warning when they hold git work that is not pushed.
Each row shows its size (… while measuring, ≥ for a lower bound, — when it could not
be read), when anything inside last changed, and why it is offered, on hover. The folder
button reveals it in Finder. Move to Trash moves what is selected on the current tab;
the result says what moved, what was refused and why, and offers Undo. The details,
including every matching rule, are in Sweep.
Themes
Light, dark or system. Dark is Tokyo Night Storm.