Scripts
Four small, readable files that automate the fiddly parts of this guide. They share the same rules:
- Dry run by default. Nothing changes until you add
--apply. (health-check.shnever changes anything.) - Idempotent. Running a script twice is safe; the second run reports that everything is already set.
- No destructive defaults. Nothing is deleted; replaced LaunchAgent files are backed up.
--helpon every script explains every option.
Install
Section titled “Install”Download the scripts into ~/bin and make them executable:
mkdir -p ~/binmv ~/Downloads/setup-power.sh ~/Downloads/health-check.sh ~/Downloads/install-launchagent.sh ~/bin/chmod +x ~/bin/*.shxattr -d com.apple.quarantine ~/bin/*.sh 2>/dev/null || true # clear the "downloaded from the internet" flag~/bin/setup-power.sh --helpThey use only tools that ship with macOS (bash, pmset, systemsetup, launchctl, plutil), so there’s
nothing else to install.
setup-power.sh
Section titled “setup-power.sh”Keeps the Mac awake and makes it restart by itself. Covered in Stay awake & auto-recover.
~/bin/setup-power.sh # dry run: current values and planned changes (never uses sudo)~/bin/setup-power.sh --apply # apply (asks for your password)~/bin/setup-power.sh --apply --daily-poweron 04:30 # also power on daily at 04:30| Setting | Command it runs |
|---|---|
| Never sleep | pmset -a sleep 0 disksleep 0 |
Display may sleep (default 10 min, --display-sleep N) |
pmset -a displaysleep 10 |
Wake for network access (skip with --no-wake-on-network) |
pmset -a womp 1 |
| Restart after power failure | pmset -a autorestart 1 |
| Keep TCP connections alive | pmset -a tcpkeepalive 1 |
Restart after freeze (skip with --no-restart-on-freeze) |
systemsetup -setrestartfreeze on |
| Optional daily power-on | pmset repeat wakeorpoweron MTWRFSU HH:MM:00 |
Example dry run:
Mode: DRY RUN — nothing will be changed. Re-run with --apply to make changes.
Power settings (pmset): [change] sleep: 1 -> 0 [change] disksleep: 10 -> 0 [ok] displaysleep = 10 [change] autorestart: 0 -> 1 [ok] tcpkeepalive = 1 [ok] womp = 1 would run: sudo pmset -a sleep 0 disksleep 0 autorestart 1
Restart after freeze (systemsetup): [unknown] restart after freeze: reading it needs admin rights, and dry runs never use sudo. Check it yourself: sudo systemsetup -getrestartfreeze would run (if not already On): sudo systemsetup -setrestartfreeze on
Dry run complete. Re-run with --apply to make these changes.A dry run never calls sudo, so it can’t read the one value that needs admin rights (restart after
freeze) and reports it as unknown, with the command to check it yourself. With --apply, the script uses
sudo to read it first and only changes it if it isn’t already on.
To undo, use System Settings → Energy, or sudo pmset restoredefaults.
health-check.sh
Section titled “health-check.sh”Read-only report of what’s running and what isn’t — run it after every restart, or on a schedule.
Exit status is 1 if anything failed, so you can use it in other scripts.
~/bin/health-check.sh~/bin/health-check.sh --app Cursor --app Claude --agent com.example.cursor-workerSave your expectations in ~/.config/mac-ai-server/health-check.conf so a plain health-check.sh checks them:
# Apps that must be running (exact process names)app=Cursorapp=Claudeapp=Google Drive# LaunchAgents that must be loadedagent=com.example.cursor-workerExample output:
Mac mini AI server — health check
System INFO macOS 26.0 WARN Up for 4 min — it rebooted recently. Check everything below came back.
Power (pmset) PASS System sleep disabled (sleep 0) PASS Restart after power failure on (autorestart 1) PASS Wake for network access on (womp 1)
Unattended restart INFO FileVault is On — after a power cut the Mac waits for a password before your apps start.
Remote access PASS Remote Login (SSH) is listening PASS Screen Sharing is listening PASS Tailscale is connected
Apps PASS Cursor is running FAIL Claude is NOT running (required)
LaunchAgents PASS com.example.cursor-worker is running
Summary: 8 pass, 1 warn, 1 failinstall-launchagent.sh
Section titled “install-launchagent.sh”Turns any command into a LaunchAgent that starts at login and is restarted if it exits (or runs every
N seconds with --interval). Covered in Login items & LaunchAgents.
# Dry run: prints the plist and the launchctl commands~/bin/install-launchagent.sh --label com.example.cursor-worker --workdir ~/code/my-project \ -- ~/.local/bin/agent worker start --name your-mac-mini
# Install and load it~/bin/install-launchagent.sh --apply --label com.example.cursor-worker --workdir ~/code/my-project \ -- ~/.local/bin/agent worker start --name your-mac-mini
# Remove it (the plist is moved to a backup folder, not deleted)~/bin/install-launchagent.sh --apply --label com.example.cursor-worker --uninstall| Option | Meaning |
|---|---|
--label |
Reverse-DNS job name (required) |
--workdir DIR |
Working directory, absolute path (default: home) |
--interval SECS |
Run every SECS seconds instead of keeping it alive |
--log-dir DIR |
Log folder, absolute path (default ~/Library/Logs/<label>/) |
--env KEY=VALUE |
Extra environment variables (repeatable) |
--uninstall |
Unload and back up the plist |
LaunchAgent template
Section titled “LaunchAgent template”com.example.ai-worker.plist is a commented plist you can
edit by hand: replace YOUR_USER, adjust the command and folders, and follow the load instructions at
the top of the file.
Source and tests
Section titled “Source and tests”The scripts live in the scripts/ folder of this site’s repository, with a test suite that runs them
against stand-in versions of the macOS commands. See the repository README for how to run ShellCheck and
the tests yourself.