Docs

Using Ebb

Install it once, then mostly forget it: Ebb scans every day and tells you when there's something worth clearing. This page covers the app, the ebbctl command, and every setting.

Install

# macOS 14 or later, Apple silicon or Intel
curl -fsSL https://ebb.serveka.com/install.sh | sh

The script downloads the latest GitHub release, checks its SHA-256 checksum and code signature, and then:

  • puts Ebb.app in /Applications (or ~/Applications if that isn't writable);
  • links the ebbctl and ebb commands into /usr/local/bin (or ~/.local/bin);
  • opens Ebb.
Why ebbctl? MacTeX ships its own command called ebb. The installer never replaces it, and ebbctl is always Ebb. Everywhere below, ebb and ebbctl are the same program.

Without the script

Download Ebb.zip from the latest release and drag Ebb.app to Applications. Ebb isn't notarized yet, so the first time, right-click Ebb.app and choose Open. To build from source, see the README.

First run

  1. Welcome. What Ebb does and what it promises not to do.
  2. Full Disk Access. macOS hides parts of ~/Library and some tool folders from apps. Click Open System Settings, find Ebb under Privacy & Security › Full Disk Access, and switch it on. Ebb notices and carries on by itself. You can also choose Scan without it; Ebb then skips what it can't see.
  3. First scan. About a minute, read-only. At the end, switch on Scan once a day to get the daily notification, and allow notifications when macOS asks.

Update and uninstall

Run the install command again to update; it replaces the app and keeps your settings.

# remove everything: app, commands, daily agent, settings, history, permissions
curl -fsSL https://ebb.serveka.com/uninstall.sh | sh

# remove the app but keep settings, rules and history for later
curl -fsSL https://ebb.serveka.com/uninstall.sh | sh -s -- --keep-data

Nothing Ebb moved to the Trash is touched by uninstalling.

The daily notification

With Scan once a day on, Ebb checks every hour whether today's scan is due. It scans once a day:

  • after a start time picked at random between 10:00 and 18:00 when you turn the agent on;
  • only once the Mac has been idle for two minutes;
  • on power, or on battery above 30% (you can change the limit);
  • and it catches up after the Mac slept through the start time.

It notifies you only when at least 2 GB can be cleared, the amount grew since the last notification (or you cleaned since), and it hasn't notified you today. Click the notification to open the review screen. The scan never cleans anything.

The window

PaneWhat it's for
OverviewFree space, safe to clear, worth a look, freed this month, and the top recommendations.
RecommendationsEvery item with a checkbox, its path, why it's safe and whether it regenerates. Filter by Regenerates or Needs a look. The side panel shows the selected total and the Move to Trash button.
Active projectsEvery project Ebb is protecting, with the signals behind it, and Always keep.
HistoryEvery clean, with Put back, and how much from Ebb cleans is still in the Trash.
SettingsSee Settings.

Pre-selected items regenerate on their own (reinstall, rebuild, refill). Items that can't come back, like old AI chats or duplicates, are listed but never pre-selected. Items cleared by a tool's own command, like the pnpm store, show the command; Ebb doesn't run it.

Always keep

On the Active projects pane, click Always keep on a project. In Recommendations, right-click an item and choose Always keep. A kept project counts as active forever; a kept path is never suggested, nor anything inside it. Unpin it from Settings › Never touch.

History, put back and emptying

Before moving anything, Ebb checks each item again: still there, not open in an app, not changed in the last 24 hours, not in a project that became active. Then it moves it to the Trash and writes it to History. From History, Put back restores one item or a whole clean, and never overwrites something new at the old path.

The space comes back once the Trash is emptied. Empty Ebb's items (in History, or in the menu bar panel when something is waiting) removes for good only what Ebb moved there; anything you put in the Trash yourself stays. It asks first, and emptied items can't be put back. From the terminal: ebbctl empty-trash.

Command line

ebbctl uses the same engine and the same settings as the app. Commands that look for projects share these options:

OptionWhat it does
--in <dir>Folder to search for projects. Repeatable. Default: your home folder (or your Settings).
--active-days <days>Activity this recent makes a project active. Default: your setting, 14.
--library-cachesAlso look at app caches in ~/Library/Caches.
--all-volumesFollow folders onto external disks and network volumes.
-q, --quietDon't show the progress line.

Progress goes to stderr and only on a terminal, so --json output stays clean in pipes.

ebbctl scan

What's safe to clear, by category. Read-only; this is also what ebbctl runs with no command.

ebbctl scan
ebbctl scan --details           # every item with its reason, and everything skipped
ebbctl scan --json > scan.json  # the full result, for scripts
ebbctl scan --in ~/code --active-days 30

"Safe to clear" is the total of pre-selected items. "Worth a look" is everything else. ~ before a size means it's an estimate, usually because files are shared with something else (pnpm does this).

ebbctl clean

Scans, shows what would go, asks, then moves items to the Trash and logs them.

ebbctl clean --dry-run                          # show, move nothing
ebbctl clean                                    # the pre-selected items, after asking
ebbctl clean --select node-leftovers,python-venvs
ebbctl clean --select old-installers --yes      # no question (scripts)

--select takes category ids from ebbctl scan and includes items that aren't pre-selected. Without a terminal, clean refuses unless you pass --yes. Items that need a tool's own command are listed with it instead of being moved.

ebbctl active

Every project Ebb considers active, and the signals that made it so.

ebbctl active
ebbctl active --json

ebbctl history · undo · empty-trash

history lists every clean with its id, size and what's still in the Trash. undo puts a clean back; without an id it's the latest one. empty-trash removes Ebb's items from the Trash for good, after asking (-y to skip the question).

ebbctl history
ebbctl undo                                  # the latest clean
ebbctl undo 20261026-082535-760b             # a specific clean
ebbctl undo 20261026-082535-760b --path ~/code/site/node_modules
ebbctl empty-trash                           # only Ebb's items; asks first

ebbctl rule

Add, list and remove custom rules.

ebbctl rule add '\.mov$' --in ~/Movies --older 90d --larger 500MB --name "Old recordings"
ebbctl rule add '^client-' --in ~/code --never-touch
ebbctl rule list
ebbctl rule remove d940aee9
OptionWhat it does
<regex>The pattern (ICU syntax, like NSRegularExpression). Matches anywhere unless anchored with ^ and $.
--in <dir>Folder to look in. Repeatable. Required unless --never-touch.
--older <age>Only files unchanged this long: 14d, 2w, 3m, 1y.
--larger <size>Only files at least this big: 50MB, 1.5GB.
--never-touchProtect matches from every category and rule, instead of suggesting them.
--full-pathMatch the whole path, not just the file name.
--name <name>A name to show. Default: the pattern.
--comes-back <label>no (default), redownload, or a how-to like "re-export from Final Cut".

Settings

Open Ebb › Settings. Changes apply from the next scan, and the command line uses the same settings.

SettingDefaultWhat it does
Scan once a dayoff until first runInstalls the daily agent and sends the notification.
Notify when at least2 GBBelow this, no notification. 1, 2, 5, 10 or 20 GB.
On battery, only above30%On battery, the agent waits until the charge is above this.
Show the size in the menu baronThe number next to the wave icon.
Open Ebb at loginoffStarts the menu bar app when you log in.
Active means used in the last14 days7, 14 or 30 days.
Signalsall onTurn off any of: file edits, git, Claude Code, Codex, running processes, editors.
Look for projects in~Add or remove folders.
Never look innoneFolders to skip completely.
External disksoffInclude external disks and network volumes.
App cachesoffInclude ~/Library/Caches in temp files.
Categoriesall onTurn any category off.

Custom rules

Rules add your own patterns. Two kinds:

  • Suggest rules list matching files under "worth a look". They're never pre-selected, and every built-in check still applies: the never-touch list, active projects, changed in the last 24 hours, open files.
  • Never-touch rules protect matches from every category and every other rule. A match anywhere inside a folder protects the whole folder.

Add them with ebbctl rule add, or edit the file directly:

{
  "version": 1,
  "rules": [
    {
      "id": "3f2a9c1e",
      "name": "Old screen recordings",
      "pattern": "^Screen Recording .*\\.mov$",
      "matchOn": "fileName",
      "roots": ["~/Desktop", "~/Movies"],
      "olderThanDays": 14,
      "largerThanMB": 50,
      "action": "suggest",
      "comesBack": { "kind": "no" }
    }
  ]
}

Invalid patterns are refused when added, and skipped with a note if edited in by hand. Each rule gets 15 seconds per folder, so a bad pattern can't hang a scan. Never-touch rules count as matching if they can't decide in time.

Files Ebb keeps

Everything lives in ~/Library/Application Support/Ebb/, on your Mac only.

FileWhat's in it
settings.jsonYour settings, including Always keep.
rules.jsonCustom rules. Copy it to another Mac to bring your rules along.
history.jsonEvery clean: what moved, from where, to where in the Trash.
last-scan.jsonThe latest scan, so the menu bar has a number right away.
agent-state.jsonWhen the agent last scanned and notified.

The daily agent is ~/Library/LaunchAgents/com.serveka.ebb.agent.plist; its log is ~/Library/Logs/Ebb/agent.log.

How Ebb decides

A project is the outermost folder with a marker: .git, package.json, pyproject.toml, requirements.txt, Cargo.toml, Package.swift, go.mod, build.gradle or an .xcodeproj. It's active, and skipped completely, if within activeDays:

SignalWhat Ebb looks at
File editsA file changed outside build folders like node_modules and dist.
Git.git/HEAD, index or logs/HEAD changed.
Claude CodeA session in ~/.claude/projects for the folder.
CodexA session in ~/.codex/sessions whose working folder is inside it.
RunningA process has its working folder inside it right now.
EditorA recent workspace in VS Code, Cursor, Windsurf, Kiro, Antigravity or Xcode.
PinnedYou chose Always keep.

ebbctl active shows which signals fired for each project.

Categories

IdWhatRule
node-leftoversnode_modules, .next, .turbo, .parcel-cache, dist, buildProject inactive
python-venvs.venv, venv, env with pyvenv.cfgProject inactive
build-outputsRust target, Swift .build, GradleProject inactive
package-cachesnpm, pnpm, Yarn, Bun, pip, Homebrew, CocoaPods, GoAlways eligible
xcodeDerivedData, old device support, unavailable simulatorsProject inactive or gone
dockerUntagged images, unused build cacheNot used by a container
temp-files$TMPDIR, optionally ~/Library/Caches3 days untouched
old-installers.dmg, .pkg, downloaded .zip in DownloadsOlder than 30 days
claude-code-historyOld Claude Code chatsOlder than 30 days*
agent-historyCodex, Gemini CLI, CursorOlder than 30 days*
local-modelsOllama, LM Studio, Hugging FaceNot used in 30 days*
xcode-archives.xcarchiveOlder than 90 days*
duplicatesIdentical files in Downloads, Desktop, DocumentsOldest copy kept*

* Never pre-selected. Contributors can add categories in categories.json.

Never touched

No category or rule can override this list: .git, .env*, .credentials*, .netrc, .npmrc, key files, keychains, CLAUDE.md, AGENTS.md, GEMINI.md, ~/.claude/settings*.json, Claude Code memory, ~/.codex/config* and auth.json, ~/.ssh, ~/.gnupg, ~/.aws, ~/.kube, the Trash, /System, /usr, and other users' home folders. Ebb also skips anything changed in the last 24 hours, anything open in an app, symlinks, other disks, and folders it can't fully read.

Troubleshooting

I can't see Ebb in the menu bar

On a MacBook with a notch, macOS hides menu bar items that don't fit, and Ebb's can end up behind the notch. Open Ebb from Applications or Spotlight to get its window any time. To bring the item back, quit a few menu bar apps or hold ⌘ and drag Ebb's icon to the right; turning off Show the size in the menu bar in Settings also makes it narrower.

"ebb" runs something else

That's MacTeX's ebb. Use ebbctl.

No notifications

Check that Scan once a day is on, and that Ebb is allowed in System Settings › Notifications. The agent only notifies when at least your threshold can be cleared and it grew since last time. To try a run now: /Applications/Ebb.app/Contents/MacOS/Ebb --agent --now.

Something I expected isn't listed

Run ebbctl scan --details. The skipped list says why each item was left out, and ebbctl active shows which project signals fired.

Something I need was moved

Open History and click Put back, or run ebbctl undo. Please also report it privately so it can't happen again.