macOS (13+ Ventura, Apple Silicon & Intel) β 2 launchd plists and 2 shell scripts for keeping your dev machine up to date and clean, automatically.
Zero personal data. All paths use
$HOMEorPLACEHOLDERvariables. Download β tweak paths β load with launchd β done.No system paths, no tokens, no credentials.
π― What This Does #
| Component | What | When |
|---|---|---|
daily-update.sh + plist |
Updates Homebrew, npm, uv, bun, rustup, pipx, conda, pip3, gh extensions, Poetry, AI CLIs (Claude Code, Copilot, Cursor Agent, HuggingFace...), Mole, Orbstack and checks for macOS updates | Every day at 09:00 |
mo-extra + plist |
Cleans caches (brew, npm, bun, uv, pip, go, cargo, Docker) and removes old ~/Downloads files (30+ days). Built-in 72h cooldown to avoid redundant runs | Every hour (skips if within cooldown) |
Result: Your machine stays updated and lean β automatically, in the background.
π Files #
| File | Type | Description |
|---|---|---|
com.user.daily-update.plist |
launchd plist | Runs daily-update.sh every morning at 09:00 |
daily-update.sh |
Bash script | 15-step update: brew, npm, uv, bun, rustup, pipx, conda, AI CLIs, macOS |
com.user.mo-extra.plist |
launchd plist | Triggers mo-extra every hour (cooldown managed in script) |
mo-extra |
Bash script | 11 cleanup operations: caches, Docker, Downloads |
π Quick Start #
mkdir -p ~/.local/bin
cp daily-update.sh ~/.local/bin/
cp mo-extra ~/.local/bin/
chmod +x ~/.local/bin/daily-update.sh ~/.local/bin/mo-extra
~/.local/bin/daily-update.sh
~/.local/bin/mo-extra
cp com.user.daily-update.plist ~/Library/LaunchAgents/
cp com.user.mo-extra.plist ~/Library/LaunchAgents/
launchctl load ~/Library/LaunchAgents/com.user.daily-update.plist
launchctl load ~/Library/LaunchAgents/com.user.mo-extra.plist
echo 'alias daily-update="~/.local/bin/daily-update.sh"' >> ~/.zshrc
echo 'alias daily-clean="rm -f ~/.local/state/mo-extra/last-run && ~/.local/bin/mo-extra"' >> ~/.zshrc
π§ Customization #
Plist Placeholders
| Placeholder | Where | Replace with |
|---|---|---|
PROGRAM_PATH |
Both plists | Absolute path to your script (e.g., /Users/jane/.local/bin/daily-update.sh) |
LOG_PATH |
Both plists | Log file path (e.g., /Users/jane/Library/Logs/daily-update.log) |
ERROR_LOG_PATH |
mo-extra plist | Error log path (e.g., /Users/jane/Library/Logs/mo-extra-err.log) |
HOME_DIR |
mo-extra plist | Your home directory (e.g., /Users/jane) |
Script Config Variables
Edit the top of each script to tune:
daily-update.sh:
LOG_FILEβ where logs go (default:~/Library/Logs/daily-update.log)- Sections are modular β comment out any tool you don't use (conda, orb, mo, etc.)
mo-extra:
COOLDOWN_HOURSβ minimum hours between runs (default: 72)DOWNLOADS_OLD_DAYSβ delete Downloads older than N days (default: 30)LOG_DIRβ log directory (default:~/Library/Logs)
π Requirements #
| Tool | Needs | Notes |
|---|---|---|
| Scripts | Bash 5+ | macOS ships Bash 3; install via brew install bash |
| brew cleanup | Homebrew | Most operations depend on it |
| npm / bun / uv / go / cargo | Optional | Sections skip automatically if missing |
| Docker prune | Docker or Orbstack | Skips if Docker isn't running |
| mo clean | Mole (brew install mo) + sudo NOPASSWD |
Optional β comment out if unused |
π§Ή Privacy #
This gist is fully generic:
- No personal paths (
/Users/real-username/...) - No API keys, tokens, or passwords
- All user-specific values use
$HOMEorPLACEHOLDER - Example usernames (
jane,you) are clearly examples - Must be configured before use
π‘ Pro Tips #
- Test without launchd first: Run the scripts manually to make sure they work
- Check logs:
cat ~/Library/Logs/daily-update.log - Force cleanup early:
rm -f ~/.local/state/mo-extra/last-run && mo-extra - Customize tool list: Open
daily-update.shand remove sections you don't need - Add your own tools: Each section follows the same pattern β just copy/paste
Part of my dev workflow. macOS native launchd β zero extra dependencies.