Automated macOS maintenance CLI. Runs Homebrew updates, dev tool cache cleanup (gcloud, pnpm, uv), Fish plugin updates, system optimization, and Brewfile enforcement on boot + weekly via brew services — zero config required.
brew install calvindotsg/tap/mac-upkeep
brew services start mac-upkeep # runs on boot + Monday 12 PMOr via uv:
uv tool install mac-upkeep # persistent install
uvx mac-upkeep run # one-off without installing| Task | Description | Schedule |
|---|---|---|
brew_update |
Update Homebrew package database | Weekly |
brew_upgrade |
Upgrade outdated formulae and casks | Weekly |
gcloud |
Update Google Cloud SDK components | Monthly |
pnpm |
Prune pnpm content-addressable store | Monthly |
uv |
Prune uv package cache | Monthly |
fisher |
Update Fish shell plugins | Weekly |
mo_clean |
Clean system and user caches (Mole) | Weekly |
mo_optimize |
Optimize DNS, Spotlight, fonts, Dock (Mole) | Weekly |
mo_purge |
Remove old project artifacts (Mole) | Monthly |
brew_cleanup |
Remove old versions and cache files | Monthly |
brew_bundle |
Remove packages not in Brewfile | Weekly |
git_sync |
Pull configured git repositories | Daily |
Tasks auto-detect installed tools — missing tools are skipped. Use --force <task> to run a specific task on demand.
mac-upkeep tasks # See all tasks with status, frequency, and next runmac-upkeep run # Run tasks (frequency-checked)
mac-upkeep run --dry-run # Preview without executing
mac-upkeep run --force brew_update # Run only brew_update
mac-upkeep run --force all # Run all, ignoring schedule
mac-upkeep run --debug # Verbose output
mac-upkeep tasks # List tasks with status and next run
mac-upkeep init # Generate config (detects your tools)
mac-upkeep show-config --default # Show all available task options
mac-upkeep show-config # Show your config overrides
mac-upkeep setup # Print sudoers rules
mac-upkeep status # Show scheduling dashboard
mac-upkeep logs # View last 20 log lines
mac-upkeep logs -f # Follow logs
mac-upkeep --version # Show versionWorks out of the box with zero configuration. To customize, generate a starter config:
mac-upkeep initThis probes your system, detects installed tools, and writes a commented config to ~/.config/mac-upkeep/config.toml. Only detected tasks are listed. Built-in defaults apply automatically — uncomment lines to override.
To see all available tasks and options:
mac-upkeep show-config --default# ~/.config/mac-upkeep/config.toml
# Disable a task
[tasks.gcloud]
enabled = false
# Change frequency (daily, weekly, or monthly)
[tasks.brew_update]
frequency = "monthly"
# Set Brewfile path explicitly
[paths]
brewfile = "~/.config/Brewfile"Add your own tasks using the same format:
[tasks.docker_prune]
description = "Prune Docker system"
command = "docker system prune -f"
detect = "docker"
frequency = "monthly"
# Control execution order
[run]
order = ["brew_update", "brew_upgrade", "docker_prune", "brew_cleanup", "brew_bundle"]Pull configured git repositories daily with git pull --ff-only. Opt-in — list your repos explicitly:
[git_sync]
repos = [
"~/code/my-project",
"~/work/max-*", # glob patterns supported
]
skip_dirty = true # skip repos with uncommitted changesEach repo is skipped with a reason if it's not a git repo, has no remote, has no upstream branch, or (when skip_dirty = true) has uncommitted changes.
Any of the following work under launchd without mac-upkeep-side configuration:
- SSH +
IdentityAgent(recommended under launchd): a path-based entry in~/.ssh/configpointing at any SSH agent's UNIX socket. Works because the directive is a file path, not theSSH_AUTH_SOCKenv var that launchd would strip. - HTTPS + credential helper:
gh auth setup-gitorgit config --global credential.helper osxkeychain. Requires the helper binary on the launchdPATH. [url].insteadOfrewrite: force SSH regardless of remote protocol by rewritinghttps://<host>/in~/.gitconfigto a matching SSHHostalias. Bypasses HTTPS auth entirely.
git_sync sets GIT_TERMINAL_PROMPT=0 and a no-op GIT_ASKPASS default (user-set GIT_ASKPASS is respected) so misconfigured auth fails in milliseconds instead of stalling to the 60 s subprocess timeout.
MAC_UPKEEP_GCLOUD=false mac-upkeep run # Disable a task
MAC_UPKEEP_GCLOUD_FREQUENCY=monthly mac-upkeep run # Override frequencymo_clean and mo_optimize require passwordless sudo for the mo binary:
mac-upkeep setup | sudo tee /etc/sudoers.d/mac-upkeep && sudo chmod 0440 /etc/sudoers.d/mac-upkeep
sudo visudo -cSee CONTRIBUTING.md for development setup and conventions.
MIT
