Opinionated rules for automating, managing and scripting macOS software updates in both standalone and enterprise (MDM-managed) environments.
You're tired of manually shepherding hundreds of Macs through security patches. Tired of users ignoring critical updates for weeks. Tired of that one machine that breaks after every upgrade because someone skipped the compatibility check.
Manual update management breaks down fast:
Enterprise reality check: That "simple" macOS update just became a 40-hour project involving backup verification, compatibility testing, staged rollouts, and failure recovery—multiplied across your entire fleet.
These Cursor Rules transform macOS update management from reactive firefighting into predictable, automated infrastructure. You get production-ready Bash scripts that handle everything from compatibility validation to rollback procedures, plus enterprise MDM integration that actually works.
What you're getting:
Immediate productivity gains:
Cut manual intervention by 85%: Security patches deploy automatically with zero-touch installation and validation
# Before: 2 hours per security update across 200 machines
# After: 15 minutes to configure, then fully automated
Eliminate compatibility disasters: Pre-flight checks catch breaking changes before they hit production
validate_compatibility() {
check_hardware_support "$TARGET_VERSION" || die "Hardware incompatible"
test_critical_apps || die "App compatibility failed"
verify_backup_status || die "Backup required"
}
Reduce update-related tickets by 70%: Proper staging and rollback procedures prevent most common failures
Save 6+ hours per major upgrade cycle: Automated compatibility matrix validation and staged deployment
Before: 3-hour scramble to manually patch 200 machines after CVE announcement After: Single command triggers validated deployment to entire fleet
#!/usr/bin/env bash
# Emergency patch deployment
set -euo pipefail; IFS=$'\n\t'
EMERGENCY_MODE=true
MAX_DEFERRAL=0
FORCE_RESTART=true
deploy_security_patch() {
log "EMERGENCY: Deploying security patch fleet-wide"
softwareupdate --download --all --restart --force
validate_installation || trigger_rollback
}
Before: Weeks of manual compatibility testing and deployment coordination After: Automated validation pipeline with staged rollout
# Three-ring deployment with automated validation
deploy_to_dev_ring() {
validate_hardware_compatibility
run_app_smoke_tests
measure_performance_baseline
}
promote_to_pilot() {
[[ $DEV_SUCCESS_RATE -gt 95 ]] || die "Dev ring failure rate too high"
deploy_to_users "$PILOT_GROUP"
}
Before: Complex Jamf Pro policies that break frequently After: Production-ready smart groups and policies with proper error handling
# Jamf Pro policy integration
create_smart_groups() {
jamf createcomputergroup -name "Needs-Security-Update" \
-criteria "patch_status:missing_critical"
jamf createpolicy -name "Auto-Security-Patch" \
-trigger "softwareUpdatePolicy" \
-scope "Needs-Security-Update"
}
# Install the update automation framework
git clone your-cursor-generated-repo
cd macos-update-automation
# Configure environment
./configure.sh --environment production \
--mdm jamf-pro \
--max-deferrals 3 \
--critical-patch-window 4h
# Create deployment rings
./create-rings.sh --dev-ring "IT-Team" \
--pilot-ring "Early-Adopters" \
--prod-ring "All-Users"
# Configure ring-specific policies
./configure-policies.sh --security-patches immediate \
--feature-updates staged
# Jamf Pro integration
./jamf-integration.sh --server your-jamf-server \
--credentials ./jamf-creds \
--create-policies
# Validate deployment
./test-deployment.sh --dry-run --ring dev
# Real-time deployment monitoring
./monitor.sh --dashboard --alert-failures
Week 1: Automated security patch deployment reduces manual work from 8 hours to 30 minutes per cycle
Month 1: Zero critical security patches remain uninstalled beyond 4-hour window (down from 2-3 weeks average)
Quarter 1: Major macOS upgrade deploys to 500+ machines with 98% success rate and zero data loss
Ongoing: Your update process becomes invisible infrastructure that just works, freeing you to focus on strategic projects instead of patch management firefighting
Concrete metrics you'll see:
Your macOS fleet becomes as predictable and automated as your cloud infrastructure. Updates happen automatically, safely, and successfully—without you having to think about them.
Start with emergency security patch automation, then expand to full lifecycle management. Your future self will thank you when the next critical CVE drops and your entire fleet patches itself while you sleep.
You are an expert in macOS Software Update automation, Bash scripting, and modern Apple MDM frameworks (Jamf Pro, Kandji, Addigy, Automox).
Key Principles
- Security First: apply security patches within 24 h; critical CVEs within 4 h.
- Automate everything **and** require human-verified backups before major upgrades.
- Treat “update” (patch) and “upgrade” (major) as separate pipelines with explicit approvals.
- Minimise downtime: stagger roll-outs (10 % → 25 % → 100 %) and allow user-deferrals ≤ 3.
- Always validate hardware & app compatibility against Apple release notes and vendor matrices.
- All scripts must be idempotent and re-entrant—running twice must yield the same system state.
Bash (primary scripting language)
- Use `/usr/bin/env bash` shebang; target Bash 5 features only when bundled with script.
- Enforce `set -euo pipefail` and `IFS=$'\n\t'` for safe execution.
- Functions are `snake_case`; global constants are `UPPER_SNAKE`.
- Log helpers
```bash
log() { printf "%s\t%s\n" "$(date -u +%F'T'%T'Z')" "$1" | tee -a "$LOG_FILE"; }
die() { log "ERROR: $1"; exit ${2:-1}; }
success(){ log "SUCCESS: $1"; }
```
- Prefer `softwareupdate --download --all --restart --force` for patches, but use `--install --agreetolicense` ONLY after hash verification.
- Always check exit codes and `softwareupdate --history` to confirm installation.
- Temporary files belong in `/private/tmp/<script_name>-$$` and get removed in a `trap 'cleanup' EXIT` block.
- Sample skeleton
```bash
#!/usr/bin/env bash
set -euo pipefail; IFS=$'\n\t'
LOG_FILE="/var/log/swupdate.log"
trap 'die "Interrupted" 130' INT
trap 'cleanup' EXIT
cleanup() { rm -rf "$TMP_DIR"; }
```
Error Handling and Validation
- Check free disk ≥ 20 GB and battery level ≥ 50 % (or AC power) before downloading.
- Validate Time Machine status: `tmutil status | grep -q "Running = 0"` or abort.
- Parse `softwareupdate` stderr; common codes:
0 = success, 1 = no updates, 2 = reboot required, 4 = error. Handle each explicitly.
- On failure, auto-collect `/var/log/install.log` & `/var/log/swupdate.log`, hash them, and ship to the MDM log endpoint.
- Use early returns; avoid nested `if` ladders.
Apple MDM / Jamf Pro
- Use `ScheduleOSUpdate` MDM command for supervised devices; set `maxUserDeferrals=3`, `priority=high`.
- In Jamf Pro:
• Create two smart groups: `Needs-Update` (patch missing) and `Recently-Updated` (< 7 days).
• Apply a policy scoped to `Needs-Update` with a custom trigger `softwareUpdatePolicy` executing the Bash skeleton.
• Enable “Restart Options → Restart Immediately if a package or update requires it”.
- For major upgrades:
• Upload macOS `InstallAssistant.pkg` using Jamf Cloud DP.
• Use --eraseinstall flag only on Apple-silicon lab machines.
- Always push a Self Service item so users can trigger updates early.
Kandji / Addigy / Automox
- Use native “Auto-OS Patch” modules; override only when Apple 0-day appears.
- Map Kandji blueprint → `macOS Security` → `Install OS Updates` with frequency `Daily`.
- In Addigy, enable “Force Update Install After Deadline” with a 5-day window.
Additional Sections
Testing
- Maintain three rings: Dev (IT team), Pilot (5 % org), Prod (remaining).
- Dev ring gets **beta** profiles; Pilot ring receives `.0` releases after 24 h.
- Validate critical apps (Office, Adobe, VPN) using an automated smoke suite driven by `osascript`.
Performance & Reliability
- Measure pre/post update boot times with `pmset -g log | grep "System Wake"`.
- Record free disk and RAM; rollback if performance drops > 15 %.
Security
- Enforce FileVault before any upgrade; abort if encryption in progress.
- Verify SHA-256 of downloaded installers using Apple support hashes.
- Remove cached installers older than 14 days via LaunchDaemon.
Directory Layout (for repo-based scripts)
- `scripts/` – Bash & Python helpers
- `profiles/` – . mobileconfig payloads (Auto updates, deferals)
- `packages/` – cached Apple installers (.pkg)
- `logs/` – rotated analysis logs (exclude from repo)
Common Pitfalls
- Ignoring firmware updates on Apple Silicon → use `shutdown -r now` after major upgrade to complete.
- Leaving users on battery; scripts should warn and exit.
- Mixing `softwareupdate` UI & CLI – stick to CLI in automation.
Ready-to-use one-liner for unmanaged Macs
```bash
sudo /usr/sbin/softwareupdate --install --recommended --agree-to-license && sudo reboot
```
Always document the update result in the device inventory and close the ticket automatically when `sw_vers` matches the target version.