{"slug": "macos-launchd-services-2-plist-2-scripts-automated-daily-updates-system-cleanup", "title": "🍎 macOS Launchd Services — 2 plist + 2 scripts: automated daily updates & system cleanup", "summary": "MacOS automation setup using two launchd plist files and two shell scripts to perform daily system updates and hourly cleanup tasks. The daily-update script updates Homebrew, npm, and various developer tools, while the mo-extra script clears caches and removes old downloads, with a 72-hour cooldown to prevent redundant runs. The setup is designed to be privacy-focused, using only `$HOME` or placeholder variables, and requires users to customize file paths before loading the services with launchd.", "body_md": "# 🍎 macOS Launchd Services — Automated Daily Updates & System Cleanup\n\n> **macOS** (13+ Ventura, Apple Silicon & Intel) — 2 launchd plists and 2 shell scripts\n> for keeping your dev machine up to date and clean, automatically.\n>\n> **Zero personal data.** All paths use `$HOME` or `PLACEHOLDER` variables.\n> Download → tweak paths → load with launchd — done.\n>\n> _No system paths, no tokens, no credentials._\n\n---\n\n## 🎯 What This Does\n\n| Component | What | When |\n|-----------|------|------|\n| `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 |\n| `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) |\n\n**Result:** Your machine stays updated and lean — automatically, in the background.\n\n---\n\n## 📋 Files\n\n| File | Type | Description |\n|------|------|-------------|\n| `com.user.daily-update.plist` | launchd plist | Runs `daily-update.sh` every morning at 09:00 |\n| `daily-update.sh` | Bash script | 15-step update: brew, npm, uv, bun, rustup, pipx, conda, AI CLIs, macOS |\n| `com.user.mo-extra.plist` | launchd plist | Triggers `mo-extra` every hour (cooldown managed in script) |\n| `mo-extra` | Bash script | 11 cleanup operations: caches, Docker, Downloads |\n\n---\n\n## 🚀 Quick Start\n\n```bash\n# 1. Decide where to keep the scripts\nmkdir -p ~/.local/bin\n\n# 2. Copy scripts there\ncp daily-update.sh ~/.local/bin/\ncp mo-extra ~/.local/bin/\nchmod +x ~/.local/bin/daily-update.sh ~/.local/bin/mo-extra\n\n# 3. Option A — Run manually whenever you want\n~/.local/bin/daily-update.sh\n~/.local/bin/mo-extra\n\n# 4. Option B — Automate with launchd\n#    First, edit the plists: replace PROGRAM_PATH and LOG_PATH\n#    (see \"Customization\" below)\ncp com.user.daily-update.plist ~/Library/LaunchAgents/\ncp com.user.mo-extra.plist ~/Library/LaunchAgents/\nlaunchctl load ~/Library/LaunchAgents/com.user.daily-update.plist\nlaunchctl load ~/Library/LaunchAgents/com.user.mo-extra.plist\n\n# 5. Add aliases for on-demand use (optional)\necho 'alias daily-update=\"~/.local/bin/daily-update.sh\"' >> ~/.zshrc\necho 'alias daily-clean=\"rm -f ~/.local/state/mo-extra/last-run && ~/.local/bin/mo-extra\"' >> ~/.zshrc\n```\n\n---\n\n## 🔧 Customization\n\n### Plist Placeholders\n\n| Placeholder | Where | Replace with |\n|-------------|-------|-------------|\n| `PROGRAM_PATH` | Both plists | Absolute path to your script (e.g., `/Users/jane/.local/bin/daily-update.sh`) |\n| `LOG_PATH` | Both plists | Log file path (e.g., `/Users/jane/Library/Logs/daily-update.log`) |\n| `ERROR_LOG_PATH` | mo-extra plist | Error log path (e.g., `/Users/jane/Library/Logs/mo-extra-err.log`) |\n| `HOME_DIR` | mo-extra plist | Your home directory (e.g., `/Users/jane`) |\n\n### Script Config Variables\n\nEdit the top of each script to tune:\n\n**daily-update.sh:**\n- `LOG_FILE` — where logs go (default: `~/Library/Logs/daily-update.log`)\n- **Sections are modular** — comment out any tool you don't use (conda, orb, mo, etc.)\n\n**mo-extra:**\n- `COOLDOWN_HOURS` — minimum hours between runs (default: 72)\n- `DOWNLOADS_OLD_DAYS` — delete Downloads older than N days (default: 30)\n- `LOG_DIR` — log directory (default: `~/Library/Logs`)\n\n---\n\n## 📝 Requirements\n\n| Tool | Needs | Notes |\n|------|-------|-------|\n| **Scripts** | Bash 5+ | macOS ships Bash 3; install via `brew install bash` |\n| **brew cleanup** | [Homebrew](https://brew.sh) | Most operations depend on it |\n| **npm / bun / uv / go / cargo** | Optional | Sections skip automatically if missing |\n| **Docker prune** | Docker or Orbstack | Skips if Docker isn't running |\n| **mo clean** | [Mole](https://github.com/tw93/Mole) (`brew install mo`) + `sudo NOPASSWD` | Optional — comment out if unused |\n\n---\n\n## 🧹 Privacy\n\nThis gist is **fully generic**:\n- No personal paths (`/Users/real-username/...`)\n- No API keys, tokens, or passwords\n- All user-specific values use `$HOME` or `PLACEHOLDER`\n- Example usernames (`jane`, `you`) are clearly examples\n- Must be configured before use\n\n---\n\n## 💡 Pro Tips\n\n- **Test without launchd first:** Run the scripts manually to make sure they work\n- **Check logs:** `cat ~/Library/Logs/daily-update.log`\n- **Force cleanup early:** `rm -f ~/.local/state/mo-extra/last-run && mo-extra`\n- **Customize tool list:** Open `daily-update.sh` and remove sections you don't need\n- **Add your own tools:** Each section follows the same pattern — just copy/paste\n\n---\n\n> _Part of my dev workflow. macOS native launchd — zero extra dependencies._\n", "url": "https://wpnews.pro/news/macos-launchd-services-2-plist-2-scripts-automated-daily-updates-system-cleanup", "canonical_source": "https://gist.github.com/EnesDemir143/f50a04edec0f2e0c552f56c4bfc1848e", "published_at": "2026-05-22 09:45:50+00:00", "updated_at": "2026-05-22 10:05:27.467074+00:00", "lang": "en", "topics": ["developer-tools"], "entities": ["Homebrew", "npm", "rustup", "pipx", "conda", "Poetry", "Claude Code", "Orbstack"], "alternates": {"html": "https://wpnews.pro/news/macos-launchd-services-2-plist-2-scripts-automated-daily-updates-system-cleanup", "markdown": "https://wpnews.pro/news/macos-launchd-services-2-plist-2-scripts-automated-daily-updates-system-cleanup.md", "text": "https://wpnews.pro/news/macos-launchd-services-2-plist-2-scripts-automated-daily-updates-system-cleanup.txt", "jsonld": "https://wpnews.pro/news/macos-launchd-services-2-plist-2-scripts-automated-daily-updates-system-cleanup.jsonld"}}