← Paul Barrick

// the agentic os

Mac the Reaper

A background service and Mac app that frees disk space from build output, caches, stale worktrees and agent scratch — behind five gates, with a ledger that says how to get each thing back. Agents can ask; they can't approve.

live · Mac

The Mac the Reaper app: 13.4 GB free of 460.4 GB, runs nightly at 04:00 and by itself under 20 GB free, 49.2 GB freed this week; filter chips for Unattended, When asked, Needs approval, Approved and Never; and a list of unattended caches, each with its size, what it is, how it comes back, and a Reap button.
what
disk reclaimer
role
Designer and sole engineer
when
Oct 2026 – present
stack
TypeScript · Node 24 · SQLite (node:sqlite) · Tauri · MCP · launchd

The problem

Agentic work eats disk. Every task gets its own git worktree, and every worktree grows its own node_modules or Rust target/ folder. Agent sessions leave scratch folders behind. On 29 October I found 20 GB of session scratch that nothing could see. The Mac’s disk routinely sat in the nineties, and a full disk doesn’t fail politely: one release build’s output was lost when the disk filled.

I had a disk-cleanup skill that freed space in tiers. On 22 October, deleting the Gradle wrapper and a speech model broke a build. Cleaning was easy. Cleaning without losing work was the actual job.

What I built

Mac the Reaper is a background service, reapd, that reclaims space from the targets Surface’s disk maps find, behind gates. It has its own Mac app, a status icon in Surface’s menu bar, a Reap screen inside Collab, a CLI, and an MCP door so an agent session can see what’s safe to purge.

It ships in dry run. Until I type reaper execute on at the Mac, every run plans, checks every gate, and writes “would reap” to the ledger. No door — HTTP, MCP or Collab — can turn deleting on.

How it works

Agents can see their own mess

The sessions that make the mess can see it too. The Reaper has an MCP door, so an agent session can ask what’s taking space, what’s in use and what isn’t, and why each target got its verdict. That way it doesn’t have to guess, and doesn’t have to ask me:

reaper_summary            free space, whether deleting is on, pending approvals, recent runs
reaper_targets            the current plan: every target, its verdict and the reason
reaper_plan               re-plan now
reaper_stashes            a repo's stashes, and whether each is safe to drop
reaper_request_approval   ask me about something a gate is holding
reaper_run                reap what's already cleared to go
reaper_ledger             what went, every gate's answer, and how to get it back

So a session that runs low on space in the middle of a build can find its own stale worktrees and build output and reap them right then, without waiting for 04:00. It reaps only what the gates have already cleared. It can’t approve anything a gate is holding, and it can’t turn deleting on. Surface’s disk map has its own MCP door too (disk_tiers, disk_growth, disk_activity), so a session can see where the space is going before it asks.

Decisions worth noting

Deletes are immediate, and the ledger is the undo. There’s no holding folder — a holding folder on a full disk is a second problem. Every ledger row says how to get the thing back: npm install, cargo build, “regenerates on its own”.

An approval can’t override everything. It lapses in 24 hours and overrides only “starred” and “active today”. It never overrides git or in-use, because those protect work that would be lost. An approval given during a dry run is spent by it and never deletes later.

Agents can’t approve and can’t turn deleting on. An agent can plan, ask for approval, and start a run of what may already go. The decision stays mine.

The dev-root rule, bought the hard way. The first night it ran for real, unattended runs took targets that only Surface’s map named, across my whole home folder, and broke installed software: a global npm tool’s node_modules, a VS Code extension’s dist, Playwright’s browsers. A node_modules beside a package.json is build output inside a repo and installed software outside one. Now unattended reaping only touches build output in repos under my dev folder; anything else waits for a person.

Where it fits

Surface measures; Mac the Reaper deletes. It reads Surface’s tier map and the vault’s session ledger, so it knows which sessions are live and which repos were touched today. It sends approval requests through Headlines as blocking cards with Approve and Deny. Collab’s Reap screen mirrors the standalone page and never gets a feature the standalone page lacks.

Surface's Disk screen with the Mac at 99% disk and a Mac the Reaper card reading 'deleting', freed 49.2 GB this week.
Surface measures; Mac the Reaper deletes. Its status card lives in the cockpit.

Outcome

In the week of the screenshot, it freed 49.2 GB. The first-night incident is why the gates look the way they do: every lesson from it, and from the cleanup skill before it, is now a rule in the code — never follow a symlink, fail closed on unpushed work, never the Gradle wrapper, app caches only while the app isn’t running.

← All of the Agentic OS