Skip to content

v0.2.0 — the log signal reads content, not mtime

Choose a tag to compare

@trsdn trsdn released this 29 Aug 10:16
· 25 commits to master since this release

The cleanup could never touch the process this app was built for.

The liveness guard read the log signal as the newest write in the session's --log-dir. That file was refreshed every 30 s by the leak's own telem flush: spawned detached child pid=… heartbeat — and each of those lines is one of the zombies to be cleaned up. The leaking wrapper was protected by its own leaking.

Measured on 2026-08-29: wrapper 86183, 17 h old, 1022 zombies at 39 % of kern.maxprocperuid, CPU idle for 7.6 h, log age reported as 4 s. Never offered as a candidate. Since both signals must agree, the log signal alone neutralised the whole cleanup feature.

The age is now derived from the log content: the tail is read backwards from EOF and the scan stops at the first line that is not a known heartbeat. The 253 MB log of that session is judged in 60 ms against a 60 s poll interval.

The safety direction is unchanged. Classification is a denylist, so an unrecognised format counts as real work and protects; a file with no parseable timestamp makes the whole directory unknown. The hard guards — PID 1, foreign uid, ancestry, zombie threshold, allowlist — are untouched.

Also in this release: --log-probe for auditing a log directory by hand, GitHub Actions for build, test and release, and install instructions.

130 tests. See CHANGELOG.md for the full entry and the measurements behind each decision.


This build is ad-hoc signed, not notarised. Verify the checksum against checksum.txt, then:

xattr -dr com.apple.quarantine /Applications/OpenZombr.app

Given that this app sends SIGKILL on your behalf, building from source (make install) is the better option. Auto-cleanup is off by default — watch --idle-watch on your own machine first.